Merge "Fix flash when canceling the recents animation with a screenshot" into sc-dev
This commit is contained in:
@@ -279,11 +279,6 @@ public abstract class ActivityTaskManagerInternal {
|
||||
*/
|
||||
public abstract boolean isRecentsComponentHomeActivity(int userId);
|
||||
|
||||
/**
|
||||
* Cancels any currently running recents animation.
|
||||
*/
|
||||
public abstract void cancelRecentsAnimation(boolean restoreHomeRootTaskPosition);
|
||||
|
||||
/**
|
||||
* Returns true if the app can close system dialogs. Otherwise it either throws a {@link
|
||||
* SecurityException} or returns false with a logcat message depending on whether the app
|
||||
|
||||
@@ -5255,11 +5255,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
return getRecentTasks().isRecentsComponentHomeActivity(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelRecentsAnimation(boolean restoreHomeRootTaskPosition) {
|
||||
ActivityTaskManagerService.this.cancelRecentsAnimation(restoreHomeRootTaskPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkCanCloseSystemDialogs(int pid, int uid, @Nullable String packageName) {
|
||||
return ActivityTaskManagerService.this.checkCanCloseSystemDialogs(pid, uid,
|
||||
|
||||
@@ -36,8 +36,10 @@ import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.app.WindowConfiguration;
|
||||
import android.graphics.GraphicBuffer;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.HardwareBuffer;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder.DeathRecipient;
|
||||
import android.os.RemoteException;
|
||||
@@ -54,6 +56,7 @@ import android.view.InputWindowHandle;
|
||||
import android.view.RemoteAnimationTarget;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceControl.Transaction;
|
||||
import android.view.SurfaceSession;
|
||||
import android.view.WindowInsets.Type;
|
||||
import android.window.PictureInPictureSurfaceTransaction;
|
||||
import android.window.TaskSnapshot;
|
||||
@@ -150,6 +153,8 @@ public class RecentsAnimationController implements DeathRecipient {
|
||||
private boolean mCancelOnNextTransitionStart;
|
||||
// Whether to take a screenshot when handling a deferred cancel
|
||||
private boolean mCancelDeferredWithScreenshot;
|
||||
// The reorder mode to apply after the cleanupScreenshot() callback
|
||||
private int mPendingCancelWithScreenshotReorderMode = REORDER_MOVE_TO_ORIGINAL_POSITION;
|
||||
|
||||
@VisibleForTesting
|
||||
boolean mIsAddingTaskToTargets;
|
||||
@@ -158,12 +163,6 @@ public class RecentsAnimationController implements DeathRecipient {
|
||||
private boolean mNavigationBarAttachedToApp;
|
||||
private ActivityRecord mNavBarAttachedApp;
|
||||
|
||||
/**
|
||||
* Animates the screenshot of task that used to be controlled by RecentsAnimation.
|
||||
* @see {@link #setCancelOnNextTransitionStart}
|
||||
*/
|
||||
SurfaceAnimator mRecentScreenshotAnimator;
|
||||
|
||||
/**
|
||||
* An app transition listener to cancel the recents animation only after the app transition
|
||||
* starts or is canceled.
|
||||
@@ -355,12 +354,9 @@ public class RecentsAnimationController implements DeathRecipient {
|
||||
public void cleanupScreenshot() {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mService.mGlobalLock) {
|
||||
if (mRecentScreenshotAnimator != null) {
|
||||
mRecentScreenshotAnimator.cancelAnimation();
|
||||
mRecentScreenshotAnimator = null;
|
||||
}
|
||||
}
|
||||
// Note, the callback will handle its own synchronization, do not lock on WM lock
|
||||
// prior to calling the callback
|
||||
continueDeferredCancelAnimation();
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
@@ -519,13 +515,13 @@ public class RecentsAnimationController implements DeathRecipient {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) {
|
||||
TaskAnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) {
|
||||
return addAnimation(task, isRecentTaskInvisible, false /* hidden */,
|
||||
null /* finishedCallback */);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible, boolean hidden,
|
||||
TaskAnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible, boolean hidden,
|
||||
OnAnimationFinishedCallback finishedCallback) {
|
||||
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addAnimation(%s)", task.getName());
|
||||
final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task,
|
||||
@@ -541,9 +537,7 @@ public class RecentsAnimationController implements DeathRecipient {
|
||||
void removeAnimation(TaskAnimationAdapter taskAdapter) {
|
||||
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
|
||||
"removeAnimation(%d)", taskAdapter.mTask.mTaskId);
|
||||
taskAdapter.mTask.setCanAffectSystemUiFlags(true);
|
||||
taskAdapter.mCapturedFinishCallback.onAnimationFinished(taskAdapter.mLastAnimationType,
|
||||
taskAdapter);
|
||||
taskAdapter.onRemove();
|
||||
mPendingAnimations.remove(taskAdapter);
|
||||
}
|
||||
|
||||
@@ -821,8 +815,22 @@ public class RecentsAnimationController implements DeathRecipient {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* Cancels the running animation when starting home, providing a snapshot for the runner to
|
||||
* properly handle the cancellation. This call uses the provided hint to determine how to
|
||||
* finish the animation.
|
||||
*/
|
||||
public void cancelAnimationForHomeStart() {
|
||||
if (mCanceled) {
|
||||
return;
|
||||
}
|
||||
cancelAnimation(mWillFinishToHome ? REORDER_MOVE_TO_TOP : REORDER_KEEP_IN_PLACE,
|
||||
true /* screenshot */, "cancelAnimationForHomeStart");
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the running animation when there is a display change, providing a snapshot for the
|
||||
* runner to properly handle the cancellation. This call uses the provided hint to determine
|
||||
* how to finish the animation.
|
||||
*/
|
||||
public void cancelAnimationForDisplayChange() {
|
||||
if (mCanceled) {
|
||||
@@ -843,16 +851,22 @@ public class RecentsAnimationController implements DeathRecipient {
|
||||
mCanceled = true;
|
||||
|
||||
if (screenshot && !mPendingAnimations.isEmpty()) {
|
||||
final TaskAnimationAdapter adapter = mPendingAnimations.get(0);
|
||||
final Task task = adapter.mTask;
|
||||
// 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;
|
||||
final TaskSnapshot taskSnapshot = screenshotRecentTask(task, reorderMode);
|
||||
final TaskSnapshot taskSnapshot = screenshotRecentTask(task);
|
||||
mPendingCancelWithScreenshotReorderMode = reorderMode;
|
||||
try {
|
||||
mRunner.onAnimationCanceled(taskSnapshot);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to cancel recents animation", e);
|
||||
}
|
||||
if (taskSnapshot == null) {
|
||||
if (taskSnapshot != null) {
|
||||
// Defer until the runner calls back to cleanupScreenshot()
|
||||
adapter.setSnapshotOverlay(taskSnapshot);
|
||||
} else {
|
||||
// Do a normal cancel since we couldn't screenshot
|
||||
mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
|
||||
}
|
||||
} else {
|
||||
@@ -869,6 +883,12 @@ public class RecentsAnimationController implements DeathRecipient {
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void continueDeferredCancelAnimation() {
|
||||
mCallbacks.onAnimationFinished(mPendingCancelWithScreenshotReorderMode,
|
||||
false /* sendUserLeaveHint */);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setWillFinishToHome(boolean willFinishToHome) {
|
||||
mWillFinishToHome = willFinishToHome;
|
||||
@@ -915,29 +935,13 @@ public class RecentsAnimationController implements DeathRecipient {
|
||||
return mRequestDeferCancelUntilNextTransition && mCancelDeferredWithScreenshot;
|
||||
}
|
||||
|
||||
TaskSnapshot screenshotRecentTask(Task task, @ReorderMode int reorderMode) {
|
||||
TaskSnapshot screenshotRecentTask(Task task) {
|
||||
final TaskSnapshotController snapshotController = mService.mTaskSnapshotController;
|
||||
final ArraySet<Task> tasks = Sets.newArraySet(task);
|
||||
snapshotController.snapshotTasks(tasks);
|
||||
snapshotController.addSkipClosingAppSnapshotTasks(tasks);
|
||||
final TaskSnapshot taskSnapshot = snapshotController.getSnapshot(task.mTaskId,
|
||||
task.mUserId, false /* restoreFromDisk */, false /* isLowResolution */);
|
||||
if (taskSnapshot == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final TaskScreenshotAnimatable animatable = new TaskScreenshotAnimatable(
|
||||
mService.mSurfaceControlFactory, task,
|
||||
new SurfaceControl.ScreenshotHardwareBuffer(taskSnapshot.getHardwareBuffer(),
|
||||
taskSnapshot.getColorSpace(), false /* containsSecureLayers */));
|
||||
mRecentScreenshotAnimator = new SurfaceAnimator(
|
||||
animatable,
|
||||
(type, anim) -> {
|
||||
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "mRecentScreenshotAnimator finish");
|
||||
mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
|
||||
}, mService);
|
||||
mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator);
|
||||
return taskSnapshot;
|
||||
return snapshotController.getSnapshot(task.mTaskId, task.mUserId,
|
||||
false /* restoreFromDisk */, false /* isLowResolution */);
|
||||
}
|
||||
|
||||
void cleanupAnimation(@ReorderMode int reorderMode) {
|
||||
@@ -976,12 +980,6 @@ public class RecentsAnimationController implements DeathRecipient {
|
||||
mRunner = null;
|
||||
mCanceled = true;
|
||||
|
||||
// Make sure previous animator has cleaned-up.
|
||||
if (mRecentScreenshotAnimator != null) {
|
||||
mRecentScreenshotAnimator.cancelAnimation();
|
||||
mRecentScreenshotAnimator = null;
|
||||
}
|
||||
|
||||
// Restore IME icon only when moving the original app task to front from recents, in case
|
||||
// IME icon may missing if the moving task has already been the current focused task.
|
||||
if (reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION && !mIsAddingTaskToTargets) {
|
||||
@@ -1028,16 +1026,7 @@ public class RecentsAnimationController implements DeathRecipient {
|
||||
|
||||
@Override
|
||||
public void binderDied() {
|
||||
if (!mCanceled) {
|
||||
cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
|
||||
} else {
|
||||
synchronized (mService.getWindowManagerLock()) {
|
||||
if (mRecentScreenshotAnimator != null) {
|
||||
mRecentScreenshotAnimator.cancelAnimation();
|
||||
mRecentScreenshotAnimator = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
|
||||
|
||||
synchronized (mService.getWindowManagerLock()) {
|
||||
// Clear associated input consumers on runner death
|
||||
@@ -1171,6 +1160,8 @@ public class RecentsAnimationController implements DeathRecipient {
|
||||
private PictureInPictureSurfaceTransaction mFinishTransaction;
|
||||
// An overlay used to mask the content as an app goes into PIP
|
||||
private SurfaceControl mFinishOverlay;
|
||||
// An overlay used for canceling the animation with a screenshot
|
||||
private SurfaceControl mSnapshotOverlay;
|
||||
|
||||
TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
|
||||
mTask = task;
|
||||
@@ -1205,10 +1196,47 @@ public class RecentsAnimationController implements DeathRecipient {
|
||||
return mTarget;
|
||||
}
|
||||
|
||||
void onCleanup() {
|
||||
if (mFinishTransaction != null) {
|
||||
final Transaction pendingTransaction = mTask.getPendingTransaction();
|
||||
void setSnapshotOverlay(TaskSnapshot snapshot) {
|
||||
// Create a surface control for the snapshot and reparent it to the leash
|
||||
final HardwareBuffer buffer = snapshot.getHardwareBuffer();
|
||||
if (buffer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final SurfaceSession session = new SurfaceSession();
|
||||
mSnapshotOverlay = mService.mSurfaceControlFactory.apply(session)
|
||||
.setName("RecentTaskScreenshotSurface")
|
||||
.setCallsite("TaskAnimationAdapter.setSnapshotOverlay")
|
||||
.setFormat(buffer.getFormat())
|
||||
.setParent(mCapturedLeash)
|
||||
.setBLASTLayer()
|
||||
.build();
|
||||
|
||||
final float scale = 1.0f * mTask.getBounds().width() / buffer.getWidth();
|
||||
mTask.getPendingTransaction()
|
||||
.setBuffer(mSnapshotOverlay, GraphicBuffer.createFromHardwareBuffer(buffer))
|
||||
.setColorSpace(mSnapshotOverlay, snapshot.getColorSpace())
|
||||
.setLayer(mSnapshotOverlay, Integer.MAX_VALUE)
|
||||
.setMatrix(mSnapshotOverlay, scale, 0, 0, scale)
|
||||
.show(mSnapshotOverlay)
|
||||
.apply();
|
||||
}
|
||||
|
||||
void onRemove() {
|
||||
if (mSnapshotOverlay != null) {
|
||||
// Clean up the snapshot overlay if necessary
|
||||
mTask.getPendingTransaction()
|
||||
.remove(mSnapshotOverlay)
|
||||
.apply();
|
||||
mSnapshotOverlay = null;
|
||||
}
|
||||
mTask.setCanAffectSystemUiFlags(true);
|
||||
mCapturedFinishCallback.onAnimationFinished(mLastAnimationType, this);
|
||||
}
|
||||
|
||||
void onCleanup() {
|
||||
final Transaction pendingTransaction = mTask.getPendingTransaction();
|
||||
if (mFinishTransaction != null) {
|
||||
// Reparent the overlay
|
||||
if (mFinishOverlay != null) {
|
||||
pendingTransaction.reparent(mFinishOverlay, mTask.mSurfaceControl);
|
||||
@@ -1236,10 +1264,15 @@ public class RecentsAnimationController implements DeathRecipient {
|
||||
} else if (!mTask.isAttached()) {
|
||||
// Apply the task's pending transaction in case it is detached and its transaction
|
||||
// is not reachable.
|
||||
mTask.getPendingTransaction().apply();
|
||||
pendingTransaction.apply();
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public SurfaceControl getSnapshotOverlay() {
|
||||
return mSnapshotOverlay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getShowWallpaper() {
|
||||
return false;
|
||||
|
||||
@@ -1529,7 +1529,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
|
||||
// Updates the extra information of the intent.
|
||||
if (fromHomeKey) {
|
||||
homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);
|
||||
mWindowManager.cancelRecentsAnimation(REORDER_KEEP_IN_PLACE, "startHomeActivity");
|
||||
if (mWindowManager.getRecentsAnimationController() != null) {
|
||||
mWindowManager.getRecentsAnimationController().cancelAnimationForHomeStart();
|
||||
}
|
||||
}
|
||||
homeIntent.putExtra(WindowManagerPolicy.EXTRA_START_REASON, reason);
|
||||
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.server.wm;
|
||||
|
||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
|
||||
|
||||
import android.graphics.GraphicBuffer;
|
||||
import android.hardware.HardwareBuffer;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceSession;
|
||||
|
||||
import com.android.internal.protolog.common.ProtoLog;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Class used by {@link RecentsAnimationController} to create a surface control with taking
|
||||
* screenshot of task when canceling recents animation.
|
||||
*
|
||||
* @see {@link RecentsAnimationController#setCancelOnNextTransitionStart}
|
||||
*/
|
||||
class TaskScreenshotAnimatable implements SurfaceAnimator.Animatable {
|
||||
private static final String TAG = "TaskScreenshotAnim";
|
||||
private Task mTask;
|
||||
private SurfaceControl mSurfaceControl;
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
|
||||
TaskScreenshotAnimatable(Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory,
|
||||
Task task, SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer) {
|
||||
HardwareBuffer buffer = screenshotBuffer == null
|
||||
? null : screenshotBuffer.getHardwareBuffer();
|
||||
mTask = task;
|
||||
mWidth = (buffer != null) ? buffer.getWidth() : 1;
|
||||
mHeight = (buffer != null) ? buffer.getHeight() : 1;
|
||||
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
|
||||
"Creating TaskScreenshotAnimatable: task: %s width: %d height: %d",
|
||||
task, mWidth, mHeight);
|
||||
mSurfaceControl = surfaceControlFactory.apply(new SurfaceSession())
|
||||
.setName("RecentTaskScreenshotSurface")
|
||||
.setBLASTLayer()
|
||||
.setCallsite("TaskScreenshotAnimatable")
|
||||
.build();
|
||||
if (buffer != null) {
|
||||
GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(buffer);
|
||||
getPendingTransaction().setBuffer(mSurfaceControl, graphicBuffer);
|
||||
getPendingTransaction().setColorSpace(mSurfaceControl,
|
||||
screenshotBuffer.getColorSpace());
|
||||
final float scale = 1.0f * mTask.getBounds().width() / mWidth;
|
||||
getPendingTransaction().setMatrix(mSurfaceControl, scale, 0, 0, scale);
|
||||
}
|
||||
getPendingTransaction().show(mSurfaceControl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceControl.Transaction getPendingTransaction() {
|
||||
return mTask.getPendingTransaction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commitPendingTransaction() {
|
||||
mTask.commitPendingTransaction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationLeashCreated(SurfaceControl.Transaction t, SurfaceControl leash) {
|
||||
t.setLayer(leash, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationLeashLost(SurfaceControl.Transaction t) {
|
||||
if (mSurfaceControl != null) {
|
||||
t.remove(mSurfaceControl);
|
||||
mSurfaceControl = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceControl.Builder makeAnimationLeash() {
|
||||
return mTask.makeAnimationLeash();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceControl getAnimationLeashParent() {
|
||||
return mTask.getAnimationLeashParent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceControl getSurfaceControl() {
|
||||
return mSurfaceControl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceControl getParentSurfaceControl() {
|
||||
return mTask.mSurfaceControl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSurfaceWidth() {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSurfaceHeight() {
|
||||
return mHeight;
|
||||
}
|
||||
}
|
||||
@@ -255,7 +255,6 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
|
||||
mController.setDeferredCancel(true /* deferred */, false /* screenshot */);
|
||||
mController.cancelAnimationWithScreenshot(false /* screenshot */);
|
||||
verify(mMockRunner).onAnimationCanceled(null /* taskSnapshot */);
|
||||
assertNull(mController.mRecentScreenshotAnimator);
|
||||
|
||||
// Simulate the app transition finishing
|
||||
mController.mAppTransitionListener.onAppTransitionStartingLocked(false, 0, 0, 0);
|
||||
@@ -271,7 +270,8 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
|
||||
assertEquals(activity.getTask().getTopVisibleActivity(), activity);
|
||||
assertEquals(activity.findMainWindow(), win1);
|
||||
|
||||
mController.addAnimation(activity.getTask(), false /* isRecentTaskInvisible */);
|
||||
RecentsAnimationController.TaskAnimationAdapter adapter = mController.addAnimation(
|
||||
activity.getTask(), false /* isRecentTaskInvisible */);
|
||||
assertTrue(mController.isAnimatingTask(activity.getTask()));
|
||||
|
||||
spyOn(mWm.mTaskSnapshotController);
|
||||
@@ -282,14 +282,9 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
|
||||
mController.setDeferredCancel(true /* deferred */, true /* screenshot */);
|
||||
mController.cancelAnimationWithScreenshot(true /* screenshot */);
|
||||
verify(mMockRunner).onAnimationCanceled(mMockTaskSnapshot /* taskSnapshot */);
|
||||
assertNotNull(mController.mRecentScreenshotAnimator);
|
||||
assertTrue(mController.mRecentScreenshotAnimator.isAnimating());
|
||||
|
||||
// Assume IRecentsAnimationController#cleanupScreenshot called to finish screenshot
|
||||
// animation.
|
||||
spyOn(mController.mRecentScreenshotAnimator.mAnimatable);
|
||||
mController.mRecentScreenshotAnimator.cancelAnimation();
|
||||
verify(mController.mRecentScreenshotAnimator.mAnimatable).onAnimationLeashLost(any());
|
||||
// Continue the animation (simulating a call to cleanupScreenshot())
|
||||
mController.continueDeferredCancelAnimation();
|
||||
verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, false);
|
||||
}
|
||||
|
||||
@@ -685,6 +680,29 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
|
||||
verify(mAnimationCallbacks).onAnimationFinished(REORDER_MOVE_TO_ORIGINAL_POSITION, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelForStartHome() throws Exception {
|
||||
mWm.setRecentsAnimationController(mController);
|
||||
final ActivityRecord activity = createActivityRecord(mDefaultDisplay);
|
||||
final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "win1");
|
||||
activity.addWindow(win1);
|
||||
|
||||
RecentsAnimationController.TaskAnimationAdapter adapter = mController.addAnimation(
|
||||
activity.getTask(), false /* isRecentTaskInvisible */);
|
||||
mController.setWillFinishToHome(true);
|
||||
|
||||
// Verify cancel is called with a snapshot and that we've created an overlay
|
||||
spyOn(mWm.mTaskSnapshotController);
|
||||
doReturn(mMockTaskSnapshot).when(mWm.mTaskSnapshotController).getSnapshot(anyInt(),
|
||||
anyInt(), eq(false) /* restoreFromDisk */, eq(false) /* isLowResolution */);
|
||||
mController.cancelAnimationForHomeStart();
|
||||
verify(mMockRunner).onAnimationCanceled(any());
|
||||
|
||||
// Continue the animation (simulating a call to cleanupScreenshot())
|
||||
mController.continueDeferredCancelAnimation();
|
||||
verify(mAnimationCallbacks).onAnimationFinished(REORDER_MOVE_TO_TOP, false);
|
||||
}
|
||||
|
||||
private ActivityRecord createHomeActivity() {
|
||||
final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService)
|
||||
.setParentTask(mRootHomeTask)
|
||||
|
||||
Reference in New Issue
Block a user