summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/IRecentsAnimationController.aidl44
-rw-r--r--core/java/android/view/IRecentsAnimationRunner.aidl2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java9
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java2
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimation.java16
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java188
-rw-r--r--services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java37
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java9
9 files changed, 206 insertions, 103 deletions
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index 956161acd762..955be8d40c47 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -77,6 +77,21 @@ interface IRecentsAnimationController {
void hideCurrentInputMethod();
/**
+ * This call is deprecated, use #setDeferCancelUntilNextTransition() instead
+ * TODO(138144750): Remove this method once there are no callers
+ * @deprecated
+ */
+ void setCancelWithDeferredScreenshot(boolean screenshot);
+
+ /**
+ * Clean up the screenshot of previous task which was created during recents animation that
+ * was cancelled by a stack order change.
+ *
+ * @see {@link IRecentsAnimationRunner#onAnimationCanceled}
+ */
+ void cleanupScreenshot();
+
+ /**
* Set a state for controller whether would like to cancel recents animations with deferred
* task screenshot presentation.
*
@@ -86,22 +101,23 @@ interface IRecentsAnimationController {
* screenshot, so that Launcher can still control the leash lifecycle & make the next app
* transition animate smoothly without flickering.
*
- * @param screenshot When set {@code true}, means recents animation will be canceled when the
- * next app launch. System will take previous task's screenshot when the next
- * app transition starting, and skip previous task's animation.
- * Set {@code false} means will not take screenshot & skip animation
- * for previous task.
+ * @param defer When set {@code true}, means that the recents animation will defer canceling the
+ * animation when a stack order change is triggered until the subsequent app
+ * transition start and skip previous task's animation.
+ * When set to {@code false}, means that the recents animation will be canceled
+ * immediately when the stack order changes.
+ * @param screenshot When set {@code true}, means that the system will take previous task's
+ * screenshot and replace the contents of the leash with it when the next app
+ * transition starting. The runner must call #cleanupScreenshot() to end the
+ * recents animation.
+ * When set to {@code false}, means that the system will simply wait for the
+ * next app transition start to immediately cancel the recents animation. This
+ * can be useful when you want an immediate transition into a state where the
+ * task is shown in the home/recents activity (without waiting for a
+ * screenshot).
*
* @see #cleanupScreenshot()
* @see IRecentsAnimationRunner#onCancelled
*/
- void setCancelWithDeferredScreenshot(boolean screenshot);
-
- /**
- * Clean up the screenshot of previous task which was created during recents animation that
- * was cancelled by a stack order change.
- *
- * @see {@link IRecentsAnimationRunner#onAnimationCanceled}
- */
- void cleanupScreenshot();
+ void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot);
}
diff --git a/core/java/android/view/IRecentsAnimationRunner.aidl b/core/java/android/view/IRecentsAnimationRunner.aidl
index 9c652a8d990b..6cda60c80b7d 100644
--- a/core/java/android/view/IRecentsAnimationRunner.aidl
+++ b/core/java/android/view/IRecentsAnimationRunner.aidl
@@ -36,7 +36,7 @@ oneway interface IRecentsAnimationRunner {
* @param deferredWithScreenshot If set to {@code true}, the contents of the task will be
* replaced with a screenshot, such that the runner's leash is
* still active. As soon as the runner doesn't need the leash
- * anymore, it can call
+ * anymore, it must call
* {@link IRecentsAnimationController#cleanupScreenshot).
*
* @see {@link RecentsAnimationController#cleanupScreenshot}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index d2fe5cd9ef64..2ef042210e67 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -91,6 +91,7 @@ public class RecentsAnimationControllerCompat {
}
}
+ @Deprecated
public void setCancelWithDeferredScreenshot(boolean screenshot) {
try {
mAnimationController.setCancelWithDeferredScreenshot(screenshot);
@@ -99,6 +100,14 @@ public class RecentsAnimationControllerCompat {
}
}
+ public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
+ try {
+ mAnimationController.setDeferCancelUntilNextTransition(defer, screenshot);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to set deferred cancel with screenshot", e);
+ }
+ }
+
public void cleanupScreenshot() {
try {
mAnimationController.cleanupScreenshot();
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index eab5e0dd270e..6c577e150e54 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -2477,7 +2477,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
// transformed the task.
final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
if (controller != null && controller.isAnimatingTask(getTask())
- && controller.shouldCancelWithDeferredScreenshot()) {
+ && controller.shouldDeferCancelUntilNextTransition()) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index bf627ec5680c..0a3e7a4860d5 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -355,7 +355,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
// launch-behind state is restored. That also prevents the next transition
// type being disturbed if the visibility is updated after setting the next
// transition (the target activity will be one of closing apps).
- if (!controller.shouldCancelWithDeferredScreenshot()
+ if (!controller.shouldDeferCancelWithScreenshot()
&& !targetStack.isFocusedStackOnDisplay()) {
targetStack.ensureActivitiesVisibleLocked(null /* starting */,
0 /* starting */, false /* preserveWindows */);
@@ -415,16 +415,18 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
final DisplayContent dc =
mService.mRootActivityContainer.getDefaultDisplay().mDisplayContent;
dc.mBoundsAnimationController.setAnimationType(
- controller.shouldCancelWithDeferredScreenshot() ? FADE_IN : BOUNDS);
+ controller.shouldDeferCancelUntilNextTransition() ? FADE_IN : BOUNDS);
- // Cancel running recents animation and screenshot previous task when the next
- // transition starts in below cases:
- // 1) The next launching task is not in recents animation task.
+ // We defer canceling the recents animation until the next app transition in the following
+ // cases:
+ // 1) The next launching task is not being animated by the recents animation
// 2) The next task is home activity. (i.e. pressing home key to back home in recents).
if ((!controller.isAnimatingTask(stack.getTaskStack().getTopChild())
|| controller.isTargetApp(stack.getTopActivity().mAppWindowToken))
- && controller.shouldCancelWithDeferredScreenshot()) {
- controller.cancelOnNextTransitionStart();
+ && controller.shouldDeferCancelUntilNextTransition()) {
+ // Always prepare an app transition since we rely on the transition callbacks to cleanup
+ mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
+ controller.setCancelOnNextTransitionStart();
} else {
// Just cancel directly to unleash from launcher when the next launching task is the
// current top task.
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index c03dabe660ad..a8b00838577f 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -96,10 +96,9 @@ public class RecentsAnimationController implements DeathRecipient {
private final Runnable mFailsafeRunnable = () ->
cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "failSafeRunnable");
- final Object mLock = new Object();
-
// The recents component app token that is shown behind the visibile tasks
private AppWindowToken mTargetAppToken;
+ private DisplayContent mDisplayContent;
private int mTargetActivityType;
private Rect mMinimizedHomeBounds = new Rect();
@@ -123,25 +122,47 @@ public class RecentsAnimationController implements DeathRecipient {
private boolean mLinkedToDeathOfRunner;
- private boolean mCancelWithDeferredScreenshot;
-
+ // Whether to try to defer canceling from a stack order change until the next transition
+ private boolean mRequestDeferCancelUntilNextTransition;
+ // Whether to actually defer canceling until the next transition
private boolean mCancelOnNextTransitionStart;
+ // Whether to take a screenshot when handling a deferred cancel
+ private boolean mCancelDeferredWithScreenshot;
/**
* Animates the screenshot of task that used to be controlled by RecentsAnimation.
- * @see {@link #cancelOnNextTransitionStart}
+ * @see {@link #setCancelOnNextTransitionStart}
*/
SurfaceAnimator mRecentScreenshotAnimator;
+ /**
+ * An app transition listener to cancel the recents animation only after the app transition
+ * starts or is canceled.
+ */
final AppTransitionListener mAppTransitionListener = new AppTransitionListener() {
@Override
public int onAppTransitionStartingLocked(int transit, long duration,
long statusBarAnimationStartTime, long statusBarAnimationDuration) {
- onTransitionStart();
- mService.mRoot.getDisplayContent(mDisplayId).mAppTransition
- .unregisterListener(this);
+ continueDeferredCancel();
return 0;
}
+
+ @Override
+ public void onAppTransitionCancelledLocked(int transit) {
+ continueDeferredCancel();
+ }
+
+ private void continueDeferredCancel() {
+ mDisplayContent.mAppTransition.unregisterListener(this);
+ if (mCanceled) {
+ return;
+ }
+
+ if (mCancelOnNextTransitionStart) {
+ mCancelOnNextTransitionStart = false;
+ cancelAnimationWithScreenshot(mCancelDeferredWithScreenshot);
+ }
+ }
};
public interface RecentsAnimationCallbacks {
@@ -201,8 +222,7 @@ public class RecentsAnimationController implements DeathRecipient {
? REORDER_MOVE_TO_TOP
: REORDER_MOVE_TO_ORIGINAL_POSITION,
true /* runSynchronously */, sendUserLeaveHint);
- final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
- dc.mBoundsAnimationController.setAnimationType(FADE_IN);
+ mDisplayContent.mBoundsAnimationController.setAnimationType(FADE_IN);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -239,8 +259,7 @@ public class RecentsAnimationController implements DeathRecipient {
}
mInputConsumerEnabled = enabled;
- final InputMonitor inputMonitor =
- mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
+ final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
inputMonitor.updateInputWindowsLw(true /*force*/);
mService.scheduleAnimationLocked();
}
@@ -281,15 +300,23 @@ public class RecentsAnimationController implements DeathRecipient {
}
@Override
+ @Deprecated
public void setCancelWithDeferredScreenshot(boolean screenshot) {
- synchronized (mLock) {
- setCancelWithDeferredScreenshotLocked(screenshot);
+ synchronized (mService.mGlobalLock) {
+ setDeferredCancel(true /* deferred */, screenshot);
+ }
+ }
+
+ @Override
+ public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
+ synchronized (mService.mGlobalLock) {
+ setDeferredCancel(defer, screenshot);
}
}
@Override
public void cleanupScreenshot() {
- synchronized (mLock) {
+ synchronized (mService.mGlobalLock) {
if (mRecentScreenshotAnimator != null) {
mRecentScreenshotAnimator.cancelAnimation();
mRecentScreenshotAnimator = null;
@@ -311,10 +338,7 @@ public class RecentsAnimationController implements DeathRecipient {
mCallbacks = callbacks;
mDisplayId = displayId;
mStatusBar = LocalServices.getService(StatusBarManagerInternal.class);
- }
-
- public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
- initialize(mService.mRoot.getDisplayContent(mDisplayId), targetActivityType, recentTaskIds);
+ mDisplayContent = service.mRoot.getDisplayContent(displayId);
}
/**
@@ -322,15 +346,15 @@ public class RecentsAnimationController implements DeathRecipient {
* because it may call cancelAnimation() which needs to properly clean up the controller
* in the window manager.
*/
- @VisibleForTesting
- void initialize(DisplayContent dc, int targetActivityType, SparseBooleanArray recentTaskIds) {
+ public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
mTargetActivityType = targetActivityType;
- dc.mAppTransition.registerListenerLocked(mAppTransitionListener);
+ mDisplayContent.mAppTransition.registerListenerLocked(mAppTransitionListener);
// Make leashes for each of the visible/target tasks and add it to the recents animation to
// be started
- final ArrayList<Task> visibleTasks = dc.getVisibleTasks();
- final TaskStack targetStack = dc.getStack(WINDOWING_MODE_UNDEFINED, targetActivityType);
+ final ArrayList<Task> visibleTasks = mDisplayContent.getVisibleTasks();
+ final TaskStack targetStack = mDisplayContent.getStack(WINDOWING_MODE_UNDEFINED,
+ targetActivityType);
if (targetStack != null) {
for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
final Task t = targetStack.getChildAt(i);
@@ -364,29 +388,31 @@ public class RecentsAnimationController implements DeathRecipient {
}
// Adjust the wallpaper visibility for the showing target activity
- final AppWindowToken recentsComponentAppToken = dc.getStack(WINDOWING_MODE_UNDEFINED,
- targetActivityType).getTopChild().getTopFullscreenAppToken();
+ final AppWindowToken recentsComponentAppToken =
+ targetStack.getTopChild().getTopFullscreenAppToken();
if (recentsComponentAppToken != null) {
if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setHomeApp("
+ recentsComponentAppToken.getName() + ")");
mTargetAppToken = recentsComponentAppToken;
if (recentsComponentAppToken.windowsCanBeWallpaperTarget()) {
- dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- dc.setLayoutNeeded();
+ mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ mDisplayContent.setLayoutNeeded();
}
}
// Save the minimized home height
- final TaskStack dockedStack = dc.getSplitScreenPrimaryStackIgnoringVisibility();
- dc.getDockedDividerController().getHomeStackBoundsInDockedMode(
- dc.getConfiguration(),
+ final TaskStack dockedStack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
+ mDisplayContent.getDockedDividerController().getHomeStackBoundsInDockedMode(
+ mDisplayContent.getConfiguration(),
dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide(),
mMinimizedHomeBounds);
mService.mWindowPlacerLocked.performSurfacePlacement();
// Notify that the animation has started
- mStatusBar.onRecentsAnimationStateChanged(true /* running */);
+ if (mStatusBar != null) {
+ mStatusBar.onRecentsAnimationStateChanged(true /* running */);
+ }
}
@VisibleForTesting
@@ -440,8 +466,7 @@ public class RecentsAnimationController implements DeathRecipient {
// Perform layout if it was scheduled before to make sure that we get correct content
// insets for the target app window after a rotation
- final DisplayContent displayContent = mService.mRoot.getDisplayContent(mDisplayId);
- displayContent.performLayout(false /* initial */, false /* updateInputWindows */);
+ mDisplayContent.performLayout(false /* initial */, false /* updateInputWindows */);
final Rect minimizedHomeBounds = mTargetAppToken != null
&& mTargetAppToken.inSplitScreenSecondaryWindowingMode()
@@ -479,9 +504,8 @@ public class RecentsAnimationController implements DeathRecipient {
cancelAnimation(reorderMode, true /* runSynchronously */, false /* screenshot */, reason);
}
- void cancelAnimationWithScreenShot() {
- cancelAnimation(REORDER_KEEP_IN_PLACE, true /* sync */, true /* screenshot */,
- "stackOrderChanged");
+ void cancelAnimationWithScreenshot(boolean screenshot) {
+ cancelAnimation(REORDER_KEEP_IN_PLACE, true /* sync */, screenshot, "stackOrderChanged");
}
private void cancelAnimation(@ReorderMode int reorderMode, boolean runSynchronously,
@@ -495,21 +519,29 @@ public class RecentsAnimationController implements DeathRecipient {
}
mService.mH.removeCallbacks(mFailsafeRunnable);
mCanceled = true;
- try {
- if (screenshot) {
- // Screen shot previous task when next task starts transition.
- final Task task = mPendingAnimations.get(0).mTask;
- screenshotRecentTask(task, reorderMode, runSynchronously);
+
+ if (screenshot) {
+ // 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;
+ screenshotRecentTask(task, reorderMode, runSynchronously);
+ try {
mRunner.onAnimationCanceled(true /* deferredWithScreenshot */);
- return;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to cancel recents animation", e);
+ }
+ } else {
+ // Otherwise, notify the runner and clean up the animation immediately
+ // Note: In the fallback case, this can trigger multiple onAnimationCancel() calls
+ // to the runner if we this actually triggers cancel twice on the caller
+ try {
+ mRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to cancel recents animation", e);
}
- mRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to cancel recents animation", e);
+ mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
+ false /* sendUserLeaveHint */);
}
- // Clean up and return to the previous app
- mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
- false /* sendUserLeaveHint */);
}
}
@@ -522,27 +554,36 @@ public class RecentsAnimationController implements DeathRecipient {
* screenshot, so that Launcher can still control the leash lifecycle & make the next app
* transition animate smoothly without flickering.
*/
- void cancelOnNextTransitionStart() {
+ void setCancelOnNextTransitionStart() {
mCancelOnNextTransitionStart = true;
}
- void setCancelWithDeferredScreenshotLocked(boolean screenshot) {
- mCancelWithDeferredScreenshot = screenshot;
+ /**
+ * Requests that we attempt to defer the cancel until the next app transition if we are
+ * canceling from a stack order change. If {@param screenshot} is specified, then the system
+ * will replace the contents of the leash with a screenshot, which must be cleaned up when the
+ * runner calls cleanUpScreenshot().
+ */
+ void setDeferredCancel(boolean defer, boolean screenshot) {
+ mRequestDeferCancelUntilNextTransition = defer;
+ mCancelDeferredWithScreenshot = screenshot;
}
- boolean shouldCancelWithDeferredScreenshot() {
- return mCancelWithDeferredScreenshot;
+ /**
+ * @return Whether we should defer the cancel from a stack order change until the next app
+ * transition.
+ */
+ boolean shouldDeferCancelUntilNextTransition() {
+ return mRequestDeferCancelUntilNextTransition;
}
- void onTransitionStart() {
- if (mCanceled) {
- return;
- }
-
- if (mCancelOnNextTransitionStart) {
- mCancelOnNextTransitionStart = false;
- cancelAnimationWithScreenShot();
- }
+ /**
+ * @return Whether we should both defer the cancel from a stack order change until the next
+ * app transition, and also that the deferred cancel should replace the contents of the leash
+ * with a screenshot.
+ */
+ boolean shouldDeferCancelWithScreenshot() {
+ return mRequestDeferCancelUntilNextTransition && mCancelDeferredWithScreenshot;
}
void screenshotRecentTask(Task task, @ReorderMode int reorderMode, boolean runSynchronously) {
@@ -575,6 +616,7 @@ public class RecentsAnimationController implements DeathRecipient {
// Clear any pending failsafe runnables
mService.mH.removeCallbacks(mFailsafeRunnable);
+ mDisplayContent.mAppTransition.unregisterListener(mAppTransitionListener);
// Clear references to the runner
unlinkToDeathOfRunner();
@@ -588,21 +630,22 @@ public class RecentsAnimationController implements DeathRecipient {
}
// Update the input windows after the animation is complete
- final InputMonitor inputMonitor =
- mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
+ final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
inputMonitor.updateInputWindowsLw(true /*force*/);
// We have deferred all notifications to the target app as a part of the recents animation,
// so if we are actually transitioning there, notify again here
if (mTargetAppToken != null) {
if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
- mService.mRoot.getDisplayContent(mDisplayId)
- .mAppTransition.notifyAppTransitionFinishedLocked(mTargetAppToken.token);
+ mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(
+ mTargetAppToken.token);
}
}
// Notify that the animation has ended
- mStatusBar.onRecentsAnimationStateChanged(false /* running */);
+ if (mStatusBar != null) {
+ mStatusBar.onRecentsAnimationStateChanged(false /* running */);
+ }
}
void scheduleFailsafe() {
@@ -629,8 +672,7 @@ public class RecentsAnimationController implements DeathRecipient {
synchronized (mService.getWindowManagerLock()) {
// Clear associated input consumers on runner death
- final InputMonitor inputMonitor =
- mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
+ final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
inputMonitor.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
}
}
@@ -826,5 +868,11 @@ public class RecentsAnimationController implements DeathRecipient {
pw.print(innerPrefix); pw.println("mSplitScreenMinimized=" + mSplitScreenMinimized);
pw.print(innerPrefix); pw.println("mTargetAppToken=" + mTargetAppToken);
pw.print(innerPrefix); pw.println("isTargetOverWallpaper=" + isTargetOverWallpaper());
+ pw.print(innerPrefix); pw.println("mRequestDeferCancelUntilNextTransition="
+ + mRequestDeferCancelUntilNextTransition);
+ pw.print(innerPrefix); pw.println("mCancelOnNextTransitionStart="
+ + mCancelOnNextTransitionStart);
+ pw.print(innerPrefix); pw.println("mCancelDeferredWithScreenshot="
+ + mCancelDeferredWithScreenshot);
}
}
diff --git a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
index bb1570e1ecb1..c0877a0a6752 100644
--- a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
+++ b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
@@ -28,7 +28,7 @@ import android.view.SurfaceSession;
* Class used by {@link RecentsAnimationController} to create a surface control with taking
* screenshot of task when canceling recents animation.
*
- * @see {@link RecentsAnimationController#cancelOnNextTransitionStart}
+ * @see {@link RecentsAnimationController#setCancelOnNextTransitionStart}
*/
class TaskScreenshotAnimatable implements SurfaceAnimator.Animatable {
private static final String TAG = "TaskScreenshotAnim";
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 26cd63c62cc1..cd292b2494ff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -25,6 +25,7 @@ import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
@@ -35,10 +36,12 @@ import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_O
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
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;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import android.os.Binder;
@@ -79,6 +82,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
// Hold the lock to protect the stubbing from being accessed by other threads.
spyOn(mWm.mRoot);
doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
+ doReturn(mDisplayContent).when(mWm.mRoot).getDisplayContent(anyInt());
}
when(mMockRunner.asBinder()).thenReturn(new Binder());
mController = new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks,
@@ -135,7 +139,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
hiddenAppWindow.setHidden(true);
mDisplayContent.getConfiguration().windowConfiguration.setRotation(
mDisplayContent.getRotation());
- mController.initialize(mDisplayContent, ACTIVITY_TYPE_HOME, new SparseBooleanArray());
+ mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray());
// Ensure that we are animating the target activity as well
assertTrue(mController.isAnimatingTask(homeAppWindow.getTask()));
@@ -144,7 +148,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
}
@Test
- public void testCancelAnimationWithScreenShot() throws Exception {
+ public void testDeferCancelAnimation() throws Exception {
mWm.setRecentsAnimationController(mController);
final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
@@ -156,8 +160,31 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
mController.addAnimation(appWindow.getTask(), false /* isRecentTaskInvisible */);
assertTrue(mController.isAnimatingTask(appWindow.getTask()));
- mController.setCancelWithDeferredScreenshotLocked(true);
- mController.cancelAnimationWithScreenShot();
+ mController.setDeferredCancel(true /* deferred */, false /* screenshot */);
+ mController.cancelAnimationWithScreenshot(false /* screenshot */);
+ verify(mMockRunner).onAnimationCanceled(false /* deferredWithScreenshot */);
+ assertNull(mController.mRecentScreenshotAnimator);
+
+ // Simulate the app transition finishing
+ mController.mAppTransitionListener.onAppTransitionStartingLocked(0, 0, 0, 0);
+ verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true, false);
+ }
+
+ @Test
+ public void testDeferCancelAnimationWithScreenShot() throws Exception {
+ mWm.setRecentsAnimationController(mController);
+ final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, appWindow, "win1");
+ appWindow.addWindow(win1);
+ assertEquals(appWindow.getTask().getTopVisibleAppToken(), appWindow);
+ assertEquals(appWindow.findMainWindow(), win1);
+
+ mController.addAnimation(appWindow.getTask(), false /* isRecentTaskInvisible */);
+ assertTrue(mController.isAnimatingTask(appWindow.getTask()));
+
+ mController.setDeferredCancel(true /* deferred */, true /* screenshot */);
+ mController.cancelAnimationWithScreenshot(true /* screenshot */);
verify(mMockRunner).onAnimationCanceled(true /* deferredWithScreenshot */);
assertNotNull(mController.mRecentScreenshotAnimator);
assertTrue(mController.mRecentScreenshotAnimator.isAnimating());
@@ -185,7 +212,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
// Assume appWindow transition should animate when no
// IRecentsAnimationController#setCancelWithDeferredScreenshot called.
- assertFalse(mController.shouldCancelWithDeferredScreenshot());
+ assertFalse(mController.shouldDeferCancelWithScreenshot());
assertTrue(appWindow.shouldAnimate(TRANSIT_ACTIVITY_CLOSE));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 9630b7d46e3c..0e119e3cc375 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -274,12 +274,13 @@ public class RecentsAnimationTest extends ActivityTestsBase {
// Assume recents animation already started, set a state that cancel recents animation
// with screenshot.
- doReturn(true).when(mRecentsAnimationController).shouldCancelWithDeferredScreenshot();
+ doReturn(true).when(mRecentsAnimationController).shouldDeferCancelUntilNextTransition();
+ doReturn(true).when(mRecentsAnimationController).shouldDeferCancelWithScreenshot();
// Start another fullscreen activity.
fullscreenStack2.moveToFront("Activity start");
- // Ensure that the recents animation was canceled by cancelOnNextTransitionStart().
- verify(mRecentsAnimationController, times(1)).cancelOnNextTransitionStart();
+ // Ensure that the recents animation was canceled by setCancelOnNextTransitionStart().
+ verify(mRecentsAnimationController, times(1)).setCancelOnNextTransitionStart();
}
@Test
@@ -315,7 +316,7 @@ public class RecentsAnimationTest extends ActivityTestsBase {
// Ensure that the recents animation was NOT canceled
verify(mService.mWindowManager, times(0)).cancelRecentsAnimationSynchronously(
eq(REORDER_KEEP_IN_PLACE), any());
- verify(mRecentsAnimationController, times(0)).cancelOnNextTransitionStart();
+ verify(mRecentsAnimationController, times(0)).setCancelOnNextTransitionStart();
}
@Test