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
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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() {
|
||||
synchronized (mService.mGlobalLock) {
|
||||
if (mRecentScreenshotAnimator != null) {
|
||||
mRecentScreenshotAnimator.cancelAnimation();
|
||||
mRecentScreenshotAnimator = null;
|
||||
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() {
|
||||
cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user