diff options
4 files changed, 53 insertions, 8 deletions
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 0b1f4d9e1613..314a1cd3825c 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -5403,6 +5403,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp           */          private ActivityRecord mAnimatingRecents; +        /** Whether {@link #mAnimatingRecents} is going to be the top activity. */ +        private boolean mRecentsWillBeTop; +          /**           * If the recents activity has a fixed orientation which is different from the current top           * activity, it will be rotated before being shown so we avoid a screen rotation animation @@ -5428,10 +5431,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp           * If {@link #mAnimatingRecents} still has fixed rotation, it should be moved to top so we           * don't clear {@link #mFixedRotationLaunchingApp} that will be handled by transition.           */ -        void onFinishRecentsAnimation(boolean moveRecentsToBack) { +        void onFinishRecentsAnimation() {              final ActivityRecord animatingRecents = mAnimatingRecents; +            final boolean recentsWillBeTop = mRecentsWillBeTop;              mAnimatingRecents = null; -            if (!moveRecentsToBack) { +            mRecentsWillBeTop = false; +            if (recentsWillBeTop) {                  // The recents activity will be the top, such as staying at recents list or                  // returning to home (if home and recents are the same activity).                  return; @@ -5454,6 +5459,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp              }          } +        void notifyRecentsWillBeTop() { +            mRecentsWillBeTop = true; +        } +          /**           * Return {@code true} if there is an ongoing animation to the "Recents" activity and this           * activity as a fixed orientation so shouldn't be rotated. @@ -5474,6 +5483,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp              if (r == null || r == mAnimatingRecents) {                  return;              } +            if (mAnimatingRecents != null && mRecentsWillBeTop) { +                // The activity is not the recents and it should be moved to back later, so it is +                // better to keep its current appearance for the next transition. Otherwise the +                // display orientation may be updated too early and the layout procedures at the +                // end of finishing recents animation is skipped. That causes flickering because +                // the surface of closing app hasn't updated to invisible. +                return; +            }              if (mFixedRotationLaunchingApp == null) {                  // In most cases this is a no-op if the activity doesn't have fixed rotation.                  // Otherwise it could be from finishing recents animation while the display has diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index f5bd4cd866a6..6b3a5d6bf18c 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -702,6 +702,11 @@ public class RecentsAnimationController implements DeathRecipient {                          "cleanupAnimation(): Notify animation finished mPendingAnimations=%d "                                  + "reorderMode=%d",                          mPendingAnimations.size(), reorderMode); +        if (reorderMode != REORDER_MOVE_TO_ORIGINAL_POSITION) { +            // Notify the state at the beginning because the removeAnimation may notify the +            // transition is finished. This is a signal that there will be a next transition. +            mDisplayContent.mFixedRotationTransitionListener.notifyRecentsWillBeTop(); +        }          for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {              final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);              if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) { @@ -742,8 +747,7 @@ public class RecentsAnimationController implements DeathRecipient {                          mTargetActivityRecord.token);              }          } -        mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation( -                reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION /* moveRecentsToBack */); +        mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation();          // Notify that the animation has ended          if (mStatusBar != null) { diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 96ea64667f6e..edf15361e445 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -1354,7 +1354,7 @@ public class DisplayContentTests extends WindowTestsBase {          assertFalse(displayRotation.updateRotationUnchecked(false));          // Rotation can be updated if the recents animation is finished. -        mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation(false); +        mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation();          assertTrue(displayRotation.updateRotationUnchecked(false));          // Rotation can be updated if the recents animation is animating but it is not on top, e.g. diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index 695a0e3881ea..8bc8c0b1169f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -362,13 +362,14 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {          assertFalse(homeActivity.hasFixedRotationTransform());      } -    @Test -    public void testClearFixedRotationLaunchingAppAfterCleanupAnimation() { -        unblockDisplayRotation(mDefaultDisplay); +    private ActivityRecord prepareFixedRotationLaunchingAppWithRecentsAnim() {          final ActivityRecord homeActivity = createHomeActivity();          homeActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);          final ActivityRecord activity = createActivityRecord(mDefaultDisplay,                  WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); +        // Add a window so it can be animated by the recents. +        final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win"); +        activity.addWindow(win);          // Assume an activity is launching to different rotation.          mDefaultDisplay.setFixedRotationLaunchingApp(activity,                  (mDefaultDisplay.getRotation() + 1) % 4); @@ -379,6 +380,14 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {          // Before the transition is done, the recents animation is triggered.          initializeRecentsAnimationController(mController, homeActivity);          assertFalse(homeActivity.hasFixedRotationTransform()); +        assertTrue(mController.isAnimatingTask(activity.getTask())); + +        return activity; +    } + +    @Test +    public void testClearFixedRotationLaunchingAppAfterCleanupAnimation() { +        final ActivityRecord activity = prepareFixedRotationLaunchingAppWithRecentsAnim();          // Simulate giving up the swipe up gesture to keep the original activity as top.          mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION); @@ -388,6 +397,21 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {      }      @Test +    public void testKeepFixedRotationWhenMovingRecentsToTop() { +        final ActivityRecord activity = prepareFixedRotationLaunchingAppWithRecentsAnim(); +        // Assume a transition animation has started running before recents animation. Then the +        // activity will receive onAnimationFinished that notifies app transition finished when +        // removing the recents animation of task. +        activity.getTask().getAnimationSources().add(activity); + +        // Simulate swiping to home/recents before the transition is done. +        mController.cleanupAnimation(REORDER_MOVE_TO_TOP); +        // The rotation transform should be preserved. In real case, it will be cleared by the next +        // move-to-top transition. +        assertTrue(activity.hasFixedRotationTransform()); +    } + +    @Test      public void testWallpaperHasFixedRotationApplied() {          unblockDisplayRotation(mDefaultDisplay);          mWm.setRecentsAnimationController(mController);  |