diff --git a/quickstep/robolectric_tests/src/com/android/quickstep/util/RecentsOrientedStateTest.java b/quickstep/robolectric_tests/src/com/android/quickstep/util/RecentsOrientedStateTest.java new file mode 100644 index 0000000000..656379f10f --- /dev/null +++ b/quickstep/robolectric_tests/src/com/android/quickstep/util/RecentsOrientedStateTest.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.quickstep.util; + +import static android.view.Surface.ROTATION_0; +import static android.view.Surface.ROTATION_180; +import static android.view.Surface.ROTATION_90; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import android.content.Context; + +import com.android.quickstep.FallbackActivityInterface; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.LooperMode; +import org.robolectric.annotation.LooperMode.Mode; + +/** + * Tests for {@link RecentsOrientedState} + */ +@RunWith(RobolectricTestRunner.class) +@LooperMode(Mode.PAUSED) +public class RecentsOrientedStateTest { + + private RecentsOrientedState mR1, mR2; + + @Before + public void setup() { + Context context = RuntimeEnvironment.application; + mR1 = new RecentsOrientedState(context, FallbackActivityInterface.INSTANCE, i -> { }); + mR2 = new RecentsOrientedState(context, FallbackActivityInterface.INSTANCE, i -> { }); + assertEquals(mR1.getStateId(), mR2.getStateId()); + } + + @Test + public void stateId_changesWithFlags() { + mR1.setGestureActive(true); + mR2.setGestureActive(false); + assertNotEquals(mR1.getStateId(), mR2.getStateId()); + + mR2.setGestureActive(true); + assertEquals(mR1.getStateId(), mR2.getStateId()); + } + + @Test + public void stateId_changesWithRecentsRotation() { + mR1.setRecentsRotation(ROTATION_90); + mR2.setRecentsRotation(ROTATION_180); + assertNotEquals(mR1.getStateId(), mR2.getStateId()); + + mR2.setRecentsRotation(ROTATION_90); + assertEquals(mR1.getStateId(), mR2.getStateId()); + } + + @Test + public void stateId_changesWithDisplayRotation() { + mR1.update(ROTATION_0, ROTATION_90); + mR2.update(ROTATION_0, ROTATION_180); + assertNotEquals(mR1.getStateId(), mR2.getStateId()); + + mR2.update(ROTATION_90, ROTATION_90); + assertNotEquals(mR1.getStateId(), mR2.getStateId()); + + mR2.update(ROTATION_90, ROTATION_0); + assertNotEquals(mR1.getStateId(), mR2.getStateId()); + + mR2.update(ROTATION_0, ROTATION_90); + assertEquals(mR1.getStateId(), mR2.getStateId()); + } +} diff --git a/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java b/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java index 6c88e55225..688f323d75 100644 --- a/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java +++ b/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java @@ -148,7 +148,7 @@ public class TaskViewSimulatorTest { if (mAppRotation < 0) { mAppRotation = launcherRotation; } - tvs.setLayoutRotation(launcherRotation, mAppRotation); + tvs.getOrientationState().update(launcherRotation, mAppRotation); if (mAppInsets == null) { mAppInsets = new Rect(mLauncherInsets); } diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 43c088b585..041f67981d 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -378,7 +378,7 @@ public abstract class AbsSwipeUpHandler, Q extends if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) { return; } - mTaskViewSimulator.setRecentsRotation(mActivity.getDisplay().getRotation()); + mTaskViewSimulator.setOrientationState(mRecentsView.getPagedViewOrientedState()); // If we've already ended the gesture and are going home, don't prepare recents UI, // as that will set the state as BACKGROUND_APP, overriding the animation to NORMAL. @@ -686,6 +686,7 @@ public abstract class AbsSwipeUpHandler, Q extends dp.updateInsets(targets.homeContentInsets); dp.updateIsSeascape(mContext); initTransitionEndpoints(dp); + mTaskViewSimulator.getOrientationState().setMultiWindowMode(dp.isMultiWindowMode); } // Notify when the animation starts diff --git a/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java index 55f542461c..efd4530c14 100644 --- a/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -132,9 +132,8 @@ final class AppToOverviewAnimationProvider> extend TaskViewSimulator tsv = new TaskViewSimulator(mActivity, mRecentsView.getSizeStrategy()); tsv.setDp(mActivity.getDeviceProfile()); + tsv.setOrientationState(mRecentsView.getPagedViewOrientedState()); tsv.setPreview(runningTaskTarget); - tsv.setLayoutRotation(mRecentsView.getPagedViewOrientedState().getTouchRotation(), - mRecentsView.getPagedViewOrientedState().getDisplayRotation()); TransformParams params = new TransformParams() .setTargetSet(targets) diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java index 8f7ec3bfa0..4bb1bb565e 100644 --- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java +++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java @@ -79,7 +79,7 @@ public abstract class SwipeUpAnimationLogic { mTaskViewSimulator = new TaskViewSimulator(context, gestureState.getActivityInterface()); mTransformParams = transformParams; - mTaskViewSimulator.setLayoutRotation( + mTaskViewSimulator.getOrientationState().update( mDeviceState.getRotationTouchHelper().getCurrentActiveRotation(), mDeviceState.getRotationTouchHelper().getDisplayRotation()); mTaskViewSimulator.setDrawsBelowRecents(true); diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java index ed761cf640..2aed76afcb 100644 --- a/quickstep/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java @@ -179,16 +179,17 @@ public final class TaskViewUtils { Context context = v.getContext(); DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile(); - // RecentsView never updates the display rotation until swipe-up so the value may be stale. - // Use the display value instead. - int displayRotation = DisplayController.getDefaultDisplay(context).getInfo().rotation; - TaskViewSimulator topMostSimulator = null; if (tsv == null && targets.apps.length > 0) { tsv = new TaskViewSimulator(context, recentsView.getSizeStrategy()); tsv.setDp(dp); - tsv.setLayoutRotation(displayRotation, displayRotation); + + // RecentsView never updates the display rotation until swipe-up so the value may + // be stale. Use the display value instead. + int displayRotation = DisplayController.getDefaultDisplay(context).getInfo().rotation; + tsv.getOrientationState().update(displayRotation, displayRotation); + tsv.setPreview(targets.apps[targets.apps.length - 1]); tsv.fullScreenProgress.value = 0; tsv.recentsViewScale.value = 1; diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java index bb84380edd..e273aeb81f 100644 --- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java +++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java @@ -72,7 +72,6 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre private static final String TAG = "RecentsOrientedState"; private static final boolean DEBUG = false; - private static final String DELIMITER_DOT = "\\."; private ContentObserver mSystemAutoRotateObserver = newContentObserver(new Handler(), t -> updateAutoRotateSetting()); @@ -129,6 +128,9 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre private int mFlags; private int mPreviousRotation = ROTATION_0; + // Combined int which encodes the full state. + private int mStateId = 0; + /** * @param rotationChangeListener Callback for receiving rotation events when rotation watcher * is enabled @@ -169,7 +171,7 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre */ public boolean setRecentsRotation(@SurfaceRotation int recentsRotation) { mRecentsRotation = recentsRotation; - return update(mTouchRotation, mDisplayRotation); + return updateHandler(); } /** @@ -183,8 +185,7 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre * Sets if the swipe up gesture is currently running or not */ public boolean setGestureActive(boolean isGestureActive) { - setFlag(FLAG_SWIPE_UP_NOT_RUNNING, !isGestureActive); - return update(mTouchRotation, mDisplayRotation); + return setFlag(FLAG_SWIPE_UP_NOT_RUNNING, !isGestureActive); } /** @@ -201,14 +202,13 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre mDisplayRotation = displayRotation; mTouchRotation = touchRotation; mPreviousRotation = touchRotation; + return updateHandler(); + } - PagedOrientationHandler oldHandler = mOrientationHandler; + private boolean updateHandler() { if (mRecentsActivityRotation == mTouchRotation || (canRecentsActivityRotate() && (mFlags & FLAG_SWIPE_UP_NOT_RUNNING) != 0)) { mOrientationHandler = PagedOrientationHandler.PORTRAIT; - if (DEBUG) { - Log.d(TAG, "current RecentsOrientedState: " + this); - } } else if (mTouchRotation == ROTATION_90) { mOrientationHandler = PagedOrientationHandler.LANDSCAPE; } else if (mTouchRotation == ROTATION_270) { @@ -219,19 +219,26 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre if (DEBUG) { Log.d(TAG, "current RecentsOrientedState: " + this); } - return oldHandler != mOrientationHandler; + + int oldStateId = mStateId; + // Each SurfaceRotation value takes two bits + mStateId = (((((mFlags << 2) + | mDisplayRotation) << 2) + | mTouchRotation) << 3) + | (mRecentsRotation < 0 ? 7 : mRecentsRotation); + return mStateId != oldStateId; } @SurfaceRotation private int inferRecentsActivityRotation(@SurfaceRotation int displayRotation) { if (isRecentsActivityRotationAllowed()) { - return mRecentsRotation < ROTATION_0 ? displayRotation : mRecentsRotation; + return mRecentsRotation < 0 ? displayRotation : mRecentsRotation; } else { return ROTATION_0; } } - private void setFlag(int mask, boolean enabled) { + private boolean setFlag(int mask, boolean enabled) { boolean wasRotationEnabled = !TestProtocol.sDisableSensorRotation && (mFlags & VALUE_ROTATION_WATCHER_ENABLED) == VALUE_ROTATION_WATCHER_ENABLED && !canRecentsActivityRotate(); @@ -253,6 +260,7 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre } }); } + return updateHandler(); } @Override @@ -327,6 +335,13 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre return mRecentsActivityRotation; } + /** + * Returns an id that can be used to tracking internal changes + */ + public int getStateId() { + return mStateId; + } + public boolean isMultipleOrientationSupportedByDevice() { return (mFlags & MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE) == MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE; @@ -509,14 +524,15 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre public String toString() { boolean systemRotationOn = (mFlags & FLAG_SYSTEM_ROTATION_ALLOWED) != 0; return "[" - + "this=" + extractObjectNameAndAddress(super.toString()) - + " mOrientationHandler=" + - extractObjectNameAndAddress(mOrientationHandler.toString()) + + "this=" + nameAndAddress(this) + + " mOrientationHandler=" + nameAndAddress(mOrientationHandler) + " mDisplayRotation=" + mDisplayRotation + " mTouchRotation=" + mTouchRotation + " mRecentsActivityRotation=" + mRecentsActivityRotation + + " mRecentsRotation=" + mRecentsRotation + " isRecentsActivityRotationAllowed=" + isRecentsActivityRotationAllowed() + " mSystemRotation=" + systemRotationOn + + " mStateId=" + mStateId + " mFlags=" + mFlags + "]"; } @@ -533,13 +549,7 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre : idp.portraitProfile; } - /** - * String conversion for only the helpful parts of {@link Object#toString()} method - * @param stringToExtract "foo.bar.baz.MyObject@1234" - * @return "MyObject@1234" - */ - private static String extractObjectNameAndAddress(String stringToExtract) { - int index = stringToExtract.lastIndexOf(DELIMITER_DOT); - return index >= 0 ? stringToExtract.substring(index) : ""; + private static String nameAndAddress(Object obj) { + return obj.getClass().getSimpleName() + "@" + obj.hashCode(); } } diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java index 61ba411363..2f4bb8ed9d 100644 --- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java +++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java @@ -23,7 +23,6 @@ import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_ import android.animation.TimeInterpolator; import android.content.Context; -import android.content.res.Configuration; import android.graphics.Matrix; import android.graphics.Point; import android.graphics.PointF; @@ -31,6 +30,8 @@ import android.graphics.Rect; import android.graphics.RectF; import android.util.IntProperty; +import androidx.annotation.NonNull; + import com.android.launcher3.DeviceProfile; import com.android.launcher3.Utilities; import com.android.launcher3.anim.PendingAnimation; @@ -67,10 +68,12 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { private final RectF mTempRectF = new RectF(); private final float[] mTempPoint = new float[2]; - private final RecentsOrientedState mOrientationState; private final Context mContext; private final BaseActivityInterface mSizeStrategy; + @NonNull + private RecentsOrientedState mOrientationState; + private final Rect mTaskRect = new Rect(); private boolean mDrawsBelowRecents; private final PointF mPivot = new PointF(); @@ -100,6 +103,7 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { // Cached calculations private boolean mLayoutValid = false; private boolean mScrollValid = false; + private int mOrientationStateId; public TaskViewSimulator(Context context, BaseActivityInterface sizeStrategy) { mContext = context; @@ -107,8 +111,8 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { mOrientationState = new RecentsOrientedState(context, sizeStrategy, i -> { }); mOrientationState.setGestureActive(true); - mCurrentFullscreenParams = new FullscreenDrawParams(context); + mOrientationStateId = mOrientationState.getStateId(); } /** @@ -116,23 +120,14 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { */ public void setDp(DeviceProfile dp) { mDp = dp; - mOrientationState.setMultiWindowMode(mDp.isMultiWindowMode); mLayoutValid = false; } /** - * @see com.android.quickstep.views.RecentsView#setLayoutRotation(int, int) + * Sets the orientation state used for this animation */ - public void setLayoutRotation(int touchRotation, int displayRotation) { - mOrientationState.update(touchRotation, displayRotation); - mLayoutValid = false; - } - - /** - * @see com.android.quickstep.views.RecentsView#onConfigurationChanged(Configuration) - */ - public void setRecentsRotation(int recentsRotation) { - mOrientationState.setRecentsRotation(recentsRotation); + public void setOrientationState(@NonNull RecentsOrientedState orientationState) { + mOrientationState = orientationState; mLayoutValid = false; } @@ -251,8 +246,9 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { if (mDp == null || mThumbnailPosition.isEmpty()) { return; } - if (!mLayoutValid) { + if (!mLayoutValid || mOrientationStateId != mOrientationState.getStateId()) { mLayoutValid = true; + mOrientationStateId = mOrientationState.getStateId(); getFullScreenScale(); mThumbnailData.rotation = mOrientationState.getDisplayRotation(); diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 7efa5bd8c4..f281296ee2 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -89,6 +89,7 @@ import android.widget.ListView; import androidx.annotation.Nullable; import com.android.launcher3.BaseActivity; +import com.android.launcher3.BaseActivity.MultiWindowModeChangedListener; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; import com.android.launcher3.InvariantDeviceProfile; @@ -239,7 +240,7 @@ public abstract class RecentsView extends PagedView } }; - protected RecentsOrientedState mOrientationState; + protected final RecentsOrientedState mOrientationState; protected final BaseActivityInterface mSizeStrategy; protected RecentsAnimationController mRecentsAnimationController; protected SurfaceTransactionApplier mSyncTransactionApplier; @@ -408,17 +409,18 @@ public abstract class RecentsView extends PagedView private int mTaskViewStartIndex = 0; private OverviewActionsView mActionsView; - private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener = - (inMultiWindowMode) -> { - if (mOrientationState != null) { + private MultiWindowModeChangedListener mMultiWindowModeChangedListener = + new MultiWindowModeChangedListener() { + @Override + public void onMultiWindowModeChanged(boolean inMultiWindowMode) { mOrientationState.setMultiWindowMode(inMultiWindowMode); setLayoutRotation(mOrientationState.getTouchRotation(), mOrientationState.getDisplayRotation()); updateChildTaskOrientations(); - } - if (!inMultiWindowMode && mOverviewStateEnabled) { - // TODO: Re-enable layout transitions for addition of the unpinned task - reloadIfNeeded(); + if (!inMultiWindowMode && mOverviewStateEnabled) { + // TODO: Re-enable layout transitions for addition of the unpinned task + reloadIfNeeded(); + } } }; @@ -476,9 +478,7 @@ public abstract class RecentsView extends PagedView mLiveTileTaskViewSimulator = new TaskViewSimulator(getContext(), getSizeStrategy()); mLiveTileTaskViewSimulator.recentsViewScale.value = 1; - mLiveTileTaskViewSimulator.setLayoutRotation(getPagedViewOrientedState().getTouchRotation(), - getPagedViewOrientedState().getDisplayRotation()); - mLiveTileTaskViewSimulator.setRecentsRotation(rotation); + mLiveTileTaskViewSimulator.setOrientationState(mOrientationState); mLiveTileTaskViewSimulator.setDrawsBelowRecents(true); } @@ -1763,7 +1763,7 @@ public abstract class RecentsView extends PagedView if (mOrientationState.setRecentsRotation(rotation)) { updateOrientationHandler(); } - mLiveTileTaskViewSimulator.setRecentsRotation(rotation); + // If overview is in modal state when rotate, reset it to overview state without running // animation. if (mActivity.isInState(OVERVIEW_MODAL_TASK)) { @@ -1798,8 +1798,6 @@ public abstract class RecentsView extends PagedView requestLayout(); // Reapply the current page to update page scrolls. setCurrentPage(mCurrentPage); - mLiveTileTaskViewSimulator.setLayoutRotation(getPagedViewOrientedState().getTouchRotation(), - getPagedViewOrientedState().getDisplayRotation()); } public RecentsOrientedState getPagedViewOrientedState() {