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

Commit 36fd1663 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Check pending rotation change after recents animation

Rotation change was skipped while running recents animation to
avoid interrupting the animation and may apply unexpected
intermediate orientation to recents activity.

But the rotation change should be still applied after the animation
is finished. Otherwise the display may stay in old rotation. The
case may be more obvious since live tile is introduced, because
the animation keeps running until switch to app. E.g. enable auto
rotation and the top is a rotatable app in landscape, and then enter
recents and rotate the device to portrait. After going back to the
current app, the display is still in landscape.

Fix: 199371058
Test: RecentsAnimationControllerTest#testCheckRotationAfterCleanup

Change-Id: I5e7487b08e139b251d160bd0627326b83351640e
parent ae8b4690
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -442,7 +442,9 @@ public class DisplayRotation {
                return false;
            }

            if (mDisplayContent.mFixedRotationTransitionListener
            final RecentsAnimationController recentsAnimController =
                    mService.getRecentsAnimationController();
            if (recentsAnimController != null && mDisplayContent.mFixedRotationTransitionListener
                    .isTopFixedOrientationRecentsAnimating()
                    // If screen is off or the device is going to sleep, then still allow to update.
                    && mService.mPolicy.okToAnimate(false /* ignoreScreenOn */)) {
@@ -450,6 +452,7 @@ public class DisplayRotation {
                // In order to ignore its requested orientation to avoid a sensor led rotation (e.g
                // user rotating the device while the recents animation is running), we ignore
                // rotation update while the animation is running.
                recentsAnimController.setCheckRotationAfterCleanup();
                return false;
            }
        }
+23 −0
Original line number Diff line number Diff line
@@ -123,6 +123,7 @@ public class RecentsAnimationController implements DeathRecipient {
    private final int mDisplayId;
    private boolean mWillFinishToHome = false;
    private final Runnable mFailsafeRunnable = this::onFailsafe;
    private Runnable mCheckRotationAfterCleanup;

    // The recents component app token that is shown behind the visibile tasks
    private ActivityRecord mTargetActivityRecord;
@@ -920,6 +921,24 @@ public class RecentsAnimationController implements DeathRecipient {
        mCancelDeferredWithScreenshot = screenshot;
    }

    /**
     * If the display rotation change is ignored while recents animation is running, make sure that
     * the pending rotation change will be applied after the animation finishes.
     */
    void setCheckRotationAfterCleanup() {
        if (mCheckRotationAfterCleanup != null) return;
        mCheckRotationAfterCleanup = () -> {
            synchronized (mService.mGlobalLock) {
                if (mDisplayContent.getDisplayRotation()
                        .updateRotationAndSendNewConfigIfChanged()) {
                    if (mTargetActivityRecord != null) {
                        mTargetActivityRecord.finishFixedRotationTransform();
                    }
                }
            }
        };
    }

    /**
     * @return Whether we should defer the cancel from a root task order change until the next app
     * transition.
@@ -1007,6 +1026,10 @@ public class RecentsAnimationController implements DeathRecipient {
        if (mStatusBar != null) {
            mStatusBar.onRecentsAnimationStateChanged(false /* running */);
        }
        if (mCheckRotationAfterCleanup != null) {
            mService.mH.post(mCheckRotationAfterCleanup);
            mCheckRotationAfterCleanup = null;
        }
    }

    void scheduleFailsafe() {
+2 −1
Original line number Diff line number Diff line
@@ -1562,6 +1562,7 @@ public class DisplayContentTests extends WindowTestsBase {
        final ActivityRecord activity = createActivityRecord(mDisplayContent);
        final ActivityRecord recentsActivity = createActivityRecord(mDisplayContent);
        recentsActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
        doReturn(mock(RecentsAnimationController.class)).when(mWm).getRecentsAnimationController();

        // Do not rotate if the recents animation is animating on top.
        mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(recentsActivity);
@@ -2513,7 +2514,7 @@ public class DisplayContentTests extends WindowTestsBase {
        assertThat("topToBottom", actualWindows, is(reverseList(expectedWindowsBottomToTop)));
    }

    private static int getRotatedOrientation(DisplayContent dc) {
    static int getRotatedOrientation(DisplayContent dc) {
        return dc.mBaseDisplayWidth > dc.mBaseDisplayHeight
                ? SCREEN_ORIENTATION_PORTRAIT
                : SCREEN_ORIENTATION_LANDSCAPE;
+17 −1
Original line number Diff line number Diff line
@@ -41,8 +41,8 @@ import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
@@ -438,6 +438,22 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
        assertTrue(activity.hasFixedRotationTransform());
    }

    @Test
    public void testCheckRotationAfterCleanup() {
        mWm.setRecentsAnimationController(mController);
        spyOn(mDisplayContent.mFixedRotationTransitionListener);
        doReturn(true).when(mDisplayContent.mFixedRotationTransitionListener)
                .isTopFixedOrientationRecentsAnimating();
        // Rotation update is skipped while the recents animation is running.
        assertFalse(mDisplayContent.getDisplayRotation().updateOrientation(DisplayContentTests
                .getRotatedOrientation(mDefaultDisplay), false /* forceUpdate */));
        final int prevRotation = mDisplayContent.getRotation();
        mWm.cleanupRecentsAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
        waitHandlerIdle(mWm.mH);
        // The display should be updated to the changed orientation after the animation is finished.
        assertNotEquals(mDisplayContent.getRotation(), prevRotation);
    }

    @Test
    public void testWallpaperHasFixedRotationApplied() {
        unblockDisplayRotation(mDefaultDisplay);