Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5a5734bb authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Finish fixed rotation after recents moved to top

While the task transition is running, its activity is the animation
source. If recents animation is triggered and finished before the
transition is done, the animation source will be notified that the
transition is finished. At this timing, the rotated activity is still
the top activity. Since it is moving to back, the display orientation
is unnecessary to be updated for the intermediate state. That avoids
flickering by not committing visibility due to configuration change.

Fixes: 160239226
Test: atest RecentsAnimationControllerTest# \
            testKeepFixedRotationWhenMovingRecentsToTop
Change-Id: I5c5c12338b9bc0cd8a99655a843a33d8729f8892
Merged-In: I5c5c12338b9bc0cd8a99655a843a33d8729f8892
parent 2d4e0b75
Loading
Loading
Loading
Loading
+19 −2
Original line number Diff line number Diff line
@@ -5642,6 +5642,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
         */
        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
@@ -5667,10 +5670,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
         * 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;
@@ -5693,6 +5698,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
            }
        }

        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.
@@ -5713,6 +5722,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
            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
+6 −2
Original line number Diff line number Diff line
@@ -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) {
+1 −1
Original line number Diff line number Diff line
@@ -1282,7 +1282,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.
+27 −2
Original line number Diff line number Diff line
@@ -363,12 +363,14 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
        assertFalse(homeActivity.hasFixedRotationTransform());
    }

    @Test
    public void testClearFixedRotationLaunchingAppAfterCleanupAnimation() {
    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 +381,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);
@@ -387,6 +397,21 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
        assertFalse(mDefaultDisplay.hasTopFixedRotationLaunchingApp());
    }

    @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() {
        mWm.setRecentsAnimationController(mController);