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

Commit 6a930e06 authored by Winson Chung's avatar Winson Chung
Browse files

Handle rotation while recents animation is running

- It's not actually possible for Launcher to cleanly handle display
  configuration changes since all of its signals are after the
  rotation has happened which affects the app in live tile mode.
  Instead, we can preemptively cancel the recents animation in these
  cases, providing Launcher the snapshot to update the running task
  view with.

Bug: 189843542
Test: atest RecentsAnimationControllerTest
Test: With live-tile enabled, swipe up to overview and rotate
      or swipe up, and then change a display property (size/density/etc)
Change-Id: I41278e78b491c4b956e49b8b1fea40b470252aab
parent 95b8d4bc
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -5492,6 +5492,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
    }

    boolean updateDisplayOverrideConfigurationLocked() {
        // Preemptively cancel the running recents animation -- SysUI can't currently handle this
        // case properly since the signals it receives all happen post-change
        final RecentsAnimationController recentsAnimationController =
                mWmService.getRecentsAnimationController();
        if (recentsAnimationController != null) {
            recentsAnimationController.cancelAnimationForDisplayChange();
        }

        Configuration values = new Configuration();
        computeScreenConfiguration(values);

+10 −0
Original line number Diff line number Diff line
@@ -480,6 +480,16 @@ public class DisplayRotation {
            return false;
        }

        // Preemptively cancel the running recents animation -- SysUI can't currently handle this
        // case properly since the signals it receives all happen post-change. We do this earlier
        // in the rotation flow, since DisplayContent.updateDisplayOverrideConfigurationLocked seems
        // to happen too late.
        final RecentsAnimationController recentsAnimationController =
                mService.getRecentsAnimationController();
        if (recentsAnimationController != null) {
            recentsAnimationController.cancelAnimationForDisplayChange();
        }

        final Transition t = (useShellTransitions
                && !mService.mAtmService.getTransitionController().isCollecting())
                ? mService.mAtmService.getTransitionController().createTransition(TRANSIT_CHANGE)
+41 −10
Original line number Diff line number Diff line
@@ -221,7 +221,7 @@ public class RecentsAnimationController implements DeathRecipient {
                            final ArraySet<Task> tasks = Sets.newArraySet(task);
                            snapshotController.snapshotTasks(tasks);
                            snapshotController.addSkipClosingAppSnapshotTasks(tasks);
                            return snapshotController.getSnapshot(taskId, 0 /* userId */,
                            return snapshotController.getSnapshot(taskId, task.mUserId,
                                    false /* restoreFromDisk */, false /* isLowResolution */);
                        }
                    }
@@ -353,18 +353,23 @@ public class RecentsAnimationController implements DeathRecipient {

        @Override
        public void cleanupScreenshot() {
            final long token = Binder.clearCallingIdentity();
            try {
                synchronized (mService.mGlobalLock) {
                    if (mRecentScreenshotAnimator != null) {
                        mRecentScreenshotAnimator.cancelAnimation();
                        mRecentScreenshotAnimator = null;
                    }
                }
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }

        @Override
        public void setWillFinishToHome(boolean willFinishToHome) {
            synchronized (mService.getWindowManagerLock()) {
                mWillFinishToHome = willFinishToHome;
                RecentsAnimationController.this.setWillFinishToHome(willFinishToHome);
            }
        }

@@ -513,7 +518,6 @@ public class RecentsAnimationController implements DeathRecipient {
                || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
    }


    @VisibleForTesting
    AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) {
        return addAnimation(task, isRecentTaskInvisible, false /* hidden */,
@@ -816,6 +820,18 @@ public class RecentsAnimationController implements DeathRecipient {
        cancelAnimation(REORDER_KEEP_IN_PLACE, screenshot, "rootTaskOrderChanged");
    }

    /**
     * If there is a recents animation running, we need to cancel the animation and snapshot the
     * tasks before the change (to ensure they are captured at the right configuration)
     */
    public void cancelAnimationForDisplayChange() {
        if (mCanceled) {
            return;
        }
        cancelAnimation(mWillFinishToHome ? REORDER_MOVE_TO_TOP : REORDER_MOVE_TO_ORIGINAL_POSITION,
                true /* screenshot */, "cancelAnimationForDisplayChange");
    }

    private void cancelAnimation(@ReorderMode int reorderMode, boolean screenshot, String reason) {
        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "cancelAnimation(): reason=%s", reason);
        synchronized (mService.getWindowManagerLock()) {
@@ -826,7 +842,7 @@ public class RecentsAnimationController implements DeathRecipient {
            mService.mH.removeCallbacks(mFailsafeRunnable);
            mCanceled = true;

            if (screenshot) {
            if (screenshot && !mPendingAnimations.isEmpty()) {
                // Screen shot previous task when next task starts transition and notify the runner.
                // We will actually finish the animation once the runner calls cleanUpScreenshot().
                final Task task = mPendingAnimations.get(0).mTask;
@@ -853,6 +869,11 @@ public class RecentsAnimationController implements DeathRecipient {
        }
    }

    @VisibleForTesting
    void setWillFinishToHome(boolean willFinishToHome) {
        mWillFinishToHome = willFinishToHome;
    }

    /**
     * Cancel recents animation when the next app transition starts.
     * <p>
@@ -905,7 +926,8 @@ public class RecentsAnimationController implements DeathRecipient {
            return null;
        }

        final TaskScreenshotAnimatable animatable = new TaskScreenshotAnimatable(mService.mSurfaceControlFactory, task,
        final TaskScreenshotAnimatable animatable = new TaskScreenshotAnimatable(
                mService.mSurfaceControlFactory, task,
                new SurfaceControl.ScreenshotHardwareBuffer(taskSnapshot.getHardwareBuffer(),
                        taskSnapshot.getColorSpace(), false /* containsSecureLayers */));
        mRecentScreenshotAnimator = new SurfaceAnimator(
@@ -1006,7 +1028,16 @@ public class RecentsAnimationController implements DeathRecipient {

    @Override
    public void binderDied() {
        if (!mCanceled) {
            cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
        } else {
            synchronized (mService.getWindowManagerLock()) {
                if (mRecentScreenshotAnimator != null) {
                    mRecentScreenshotAnimator.cancelAnimation();
                    mRecentScreenshotAnimator = null;
                }
            }
        }

        synchronized (mService.getWindowManagerLock()) {
            // Clear associated input consumers on runner death
+30 −0
Original line number Diff line number Diff line
@@ -655,6 +655,36 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
        assertFalse(win1.mHasSurface);
    }

    @Test
    public void testCancelForRotation_ReorderToTop() throws Exception {
        mWm.setRecentsAnimationController(mController);
        final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
        final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "win1");
        activity.addWindow(win1);

        mController.addAnimation(activity.getTask(), false /* isRecentTaskInvisible */);
        mController.setWillFinishToHome(true);
        mController.cancelAnimationForDisplayChange();

        verify(mMockRunner).onAnimationCanceled(any());
        verify(mAnimationCallbacks).onAnimationFinished(REORDER_MOVE_TO_TOP, false);
    }

    @Test
    public void testCancelForRotation_ReorderToOriginalPosition() throws Exception {
        mWm.setRecentsAnimationController(mController);
        final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
        final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "win1");
        activity.addWindow(win1);

        mController.addAnimation(activity.getTask(), false /* isRecentTaskInvisible */);
        mController.setWillFinishToHome(false);
        mController.cancelAnimationForDisplayChange();

        verify(mMockRunner).onAnimationCanceled(any());
        verify(mAnimationCallbacks).onAnimationFinished(REORDER_MOVE_TO_ORIGINAL_POSITION, false);
    }

    private ActivityRecord createHomeActivity() {
        final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService)
                .setParentTask(mRootHomeTask)