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:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user