Merge "Modify deferred recents animation cancel to work without screenshot" into qt-r1-dev am: 48e3cfc06a

am: 932a656359

Change-Id: I578a09c3955c2da833d604501ad4602ea8413fa2
This commit is contained in:
Winson Chung
2019-07-23 23:21:54 -07:00
committed by android-build-merger
9 changed files with 209 additions and 106 deletions

View File

@@ -77,23 +77,9 @@ interface IRecentsAnimationController {
void hideCurrentInputMethod();
/**
* Set a state for controller whether would like to cancel recents animations with deferred
* task screenshot presentation.
*
* When we cancel the recents animation due to a stack order change, we can't just cancel it
* immediately as it would lead to a flicker in Launcher if we just remove the task from the
* leash. Instead we screenshot the previous task and replace the child of the leash with the
* 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.
*
* @see #cleanupScreenshot()
* @see IRecentsAnimationRunner#onCancelled
* This call is deprecated, use #setDeferCancelUntilNextTransition() instead
* TODO(138144750): Remove this method once there are no callers
* @deprecated
*/
void setCancelWithDeferredScreenshot(boolean screenshot);
@@ -104,4 +90,34 @@ interface IRecentsAnimationController {
* @see {@link IRecentsAnimationRunner#onAnimationCanceled}
*/
void cleanupScreenshot();
/**
* Set a state for controller whether would like to cancel recents animations with deferred
* task screenshot presentation.
*
* When we cancel the recents animation due to a stack order change, we can't just cancel it
* immediately as it would lead to a flicker in Launcher if we just remove the task from the
* leash. Instead we screenshot the previous task and replace the child of the leash with the
* screenshot, so that Launcher can still control the leash lifecycle & make the next app
* transition animate smoothly without flickering.
*
* @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 setDeferCancelUntilNextTransition(boolean defer, boolean screenshot);
}

View File

@@ -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}

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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.

View File

@@ -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);
}
mRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
} 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);
}
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);
}
}

View File

@@ -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";

View File

@@ -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));
}

View File

@@ -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