summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTracy Zhou <tracyzhou@google.com>2019-07-30 17:30:43 -0700
committerTracy Zhou <tracyzhou@google.com>2019-08-11 17:00:38 +0000
commit8089ffaced5e33cbae17ef059cdf20d23ef54efe (patch)
treee7e533ac3e8d7a07ef37886c16ca8faf3c014c50
parent285185426a12545eaa5b00a52401efad65ee97aa (diff)
Pass the captured snapshot data to Launcher when recents animation is
cancelled. In the current implementation, when recents animation is cancelled due to stack order change, window manager replaces the surface with a snapshot before cancellation. Launcher needs to acquire the snapshot in order to switch the live tile into snapshot mode, and yet because the recents animation is cancelled, that snapshot can no longer be acquired anymore. This change takes care of this "relay" process. Fixes: 138683199 Test: N/A Change-Id: I1c11af38c2bdc442e3b45d0b5f0c7e7e37c2b0f0
-rw-r--r--apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java3
-rw-r--r--core/java/android/view/IRecentsAnimationRunner.aidl13
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java5
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimation.java2
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java53
-rw-r--r--services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java13
7 files changed, 59 insertions, 46 deletions
diff --git a/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
index 4e2b281da1b4..2b6f4557303b 100644
--- a/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java
@@ -26,6 +26,7 @@ import static org.hamcrest.core.AnyOf.anyOf;
import static org.hamcrest.core.Is.is;
import android.app.Activity;
+import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
import android.content.ComponentName;
@@ -216,7 +217,7 @@ public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase {
}
@Override
- public void onAnimationCanceled(boolean deferredWithScreenshot) throws RemoteException {
+ public void onAnimationCanceled(TaskSnapshot taskSnapshot) throws RemoteException {
Assume.assumeNoException(
new AssertionError("onAnimationCanceled should not be called"));
}
diff --git a/core/java/android/view/IRecentsAnimationRunner.aidl b/core/java/android/view/IRecentsAnimationRunner.aidl
index 6cda60c80b7d..724d96ed9585 100644
--- a/core/java/android/view/IRecentsAnimationRunner.aidl
+++ b/core/java/android/view/IRecentsAnimationRunner.aidl
@@ -16,6 +16,7 @@
package android.view;
+import android.app.ActivityManager;
import android.graphics.Rect;
import android.view.RemoteAnimationTarget;
import android.view.IRecentsAnimationController;
@@ -33,16 +34,16 @@ oneway interface IRecentsAnimationRunner {
* wallpaper not drawing in time, or the handler not finishing the animation within a predefined
* amount of time.
*
- * @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 must call
- * {@link IRecentsAnimationController#cleanupScreenshot).
+ * @param taskSnapshot If the snapshot is null, the animation will be cancelled and the leash
+ * will be inactive immediately. Otherwise, the contents of the task will be
+ * replaced with {@param taskSnapshot}, such that the runner's leash is
+ * still active. As soon as the runner doesn't need the leash anymore, it
+ * must call {@link IRecentsAnimationController#cleanupScreenshot).
*
* @see {@link RecentsAnimationController#cleanupScreenshot}
*/
@UnsupportedAppUsage
- void onAnimationCanceled(boolean deferredWithScreenshot) = 1;
+ void onAnimationCanceled(in @nullable ActivityManager.TaskSnapshot taskSnapshot) = 1;
/**
* Called when the system is ready for the handler to start animating all the visible tasks.
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 13fc702aa0a0..82287873f5ad 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -31,6 +31,7 @@ import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManager.RecentTaskInfo;
import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.AppGlobals;
@@ -235,9 +236,9 @@ public class ActivityManagerWrapper {
}
@Override
- public void onAnimationCanceled(boolean deferredWithScreenshot) {
+ public void onAnimationCanceled(TaskSnapshot taskSnapshot) {
animationHandler.onAnimationCanceled(
- deferredWithScreenshot ? new ThumbnailData() : null);
+ taskSnapshot != null ? new ThumbnailData(taskSnapshot) : null);
}
};
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 036bef755a87..4f0332c58deb 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -460,7 +460,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
*/
static void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) {
try {
- recentsAnimationRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
+ recentsAnimationRunner.onAnimationCanceled(null /* taskSnapshot */);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to cancel recents animation before start", e);
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 6ea4d580ea98..724a72e1861e 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -23,8 +23,8 @@ import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
-
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
import static com.android.server.wm.AnimationAdapterProto.REMOTE;
@@ -525,18 +525,23 @@ public class RecentsAnimationController implements DeathRecipient {
// 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);
+ final TaskSnapshot taskSnapshot = screenshotRecentTask(task, reorderMode,
+ runSynchronously);
try {
- mRunner.onAnimationCanceled(true /* deferredWithScreenshot */);
+ mRunner.onAnimationCanceled(taskSnapshot);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to cancel recents animation", e);
}
+ if (taskSnapshot == null) {
+ mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
+ false /* sendUserLeaveHint */);
+ }
} 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 */);
+ mRunner.onAnimationCanceled(null /* taskSnapshot */);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to cancel recents animation", e);
}
@@ -587,20 +592,32 @@ public class RecentsAnimationController implements DeathRecipient {
return mRequestDeferCancelUntilNextTransition && mCancelDeferredWithScreenshot;
}
- void screenshotRecentTask(Task task, @ReorderMode int reorderMode, boolean runSynchronously) {
- final TaskScreenshotAnimatable animatable = TaskScreenshotAnimatable.create(task);
- if (animatable != null) {
- mRecentScreenshotAnimator = new SurfaceAnimator(
- animatable,
- () -> {
- if (DEBUG_RECENTS_ANIMATIONS) {
- Slog.d(TAG, "mRecentScreenshotAnimator finish");
- }
- mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
- false /* sendUserLeaveHint */);
- }, mService);
- mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator);
- }
+ TaskSnapshot screenshotRecentTask(Task task, @ReorderMode int reorderMode,
+ boolean runSynchronously) {
+ 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 /* reducedResolution */);
+ if (taskSnapshot == null) {
+ return null;
+ }
+
+ final TaskScreenshotAnimatable animatable = new TaskScreenshotAnimatable(task,
+ new SurfaceControl.ScreenshotGraphicBuffer(taskSnapshot.getSnapshot(),
+ taskSnapshot.getColorSpace(), false /* containsSecureLayers */));
+ mRecentScreenshotAnimator = new SurfaceAnimator(
+ animatable,
+ () -> {
+ if (DEBUG_RECENTS_ANIMATIONS) {
+ Slog.d(TAG, "mRecentScreenshotAnimator finish");
+ }
+ mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
+ false /* sendUserLeaveHint */);
+ }, mService);
+ mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator);
+ return taskSnapshot;
}
void cleanupAnimation(@ReorderMode int reorderMode) {
diff --git a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
index 143543e8c74b..d6c2f66dbb65 100644
--- a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
+++ b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
@@ -18,7 +18,6 @@ package com.android.server.wm;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
import android.graphics.GraphicBuffer;
-import android.graphics.Rect;
import android.util.Slog;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -37,20 +36,7 @@ class TaskScreenshotAnimatable implements SurfaceAnimator.Animatable {
private int mWidth;
private int mHeight;
- public static TaskScreenshotAnimatable create(Task task) {
- return new TaskScreenshotAnimatable(task, getBufferFromTask(task));
- }
-
- private static SurfaceControl.ScreenshotGraphicBuffer getBufferFromTask(Task task) {
- if (task == null) {
- return null;
- }
- final Rect tmpRect = task.getBounds();
- tmpRect.offset(0, 0);
- return SurfaceControl.captureLayers(task.getSurfaceControl(), tmpRect, 1f);
- }
-
- private TaskScreenshotAnimatable(Task task,
+ TaskScreenshotAnimatable(Task task,
SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer) {
GraphicBuffer buffer = screenshotBuffer == null
? null : screenshotBuffer.getGraphicBuffer();
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 cd292b2494ff..f5a1d752590e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -44,6 +44,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import android.app.ActivityManager.TaskSnapshot;
import android.os.Binder;
import android.os.IInterface;
import android.platform.test.annotations.Presubmit;
@@ -73,6 +74,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
@Mock OnAnimationFinishedCallback mFinishedCallback;
@Mock IRecentsAnimationRunner mMockRunner;
@Mock RecentsAnimationController.RecentsAnimationCallbacks mAnimationCallbacks;
+ @Mock TaskSnapshot mMockTaskSnapshot;
private RecentsAnimationController mController;
@Before
@@ -104,7 +106,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
// Verify that the finish callback to reparent the leash is called
verify(mFinishedCallback).onAnimationFinished(eq(adapter));
// Verify the animation canceled callback to the app was made
- verify(mMockRunner).onAnimationCanceled(false);
+ verify(mMockRunner).onAnimationCanceled(null /* taskSnapshot */);
verifyNoMoreInteractionsExceptAsBinder(mMockRunner);
}
@@ -162,7 +164,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
mController.setDeferredCancel(true /* deferred */, false /* screenshot */);
mController.cancelAnimationWithScreenshot(false /* screenshot */);
- verify(mMockRunner).onAnimationCanceled(false /* deferredWithScreenshot */);
+ verify(mMockRunner).onAnimationCanceled(null /* taskSnapshot */);
assertNull(mController.mRecentScreenshotAnimator);
// Simulate the app transition finishing
@@ -183,9 +185,14 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
mController.addAnimation(appWindow.getTask(), false /* isRecentTaskInvisible */);
assertTrue(mController.isAnimatingTask(appWindow.getTask()));
+ spyOn(mWm.mTaskSnapshotController);
+ doNothing().when(mWm.mTaskSnapshotController).notifyAppVisibilityChanged(any(),
+ anyBoolean());
+ doReturn(mMockTaskSnapshot).when(mWm.mTaskSnapshotController).getSnapshot(anyInt(),
+ anyInt(), eq(false) /* restoreFromDisk */, eq(false) /* reducedResolution */);
mController.setDeferredCancel(true /* deferred */, true /* screenshot */);
mController.cancelAnimationWithScreenshot(true /* screenshot */);
- verify(mMockRunner).onAnimationCanceled(true /* deferredWithScreenshot */);
+ verify(mMockRunner).onAnimationCanceled(mMockTaskSnapshot /* taskSnapshot */);
assertNotNull(mController.mRecentScreenshotAnimator);
assertTrue(mController.mRecentScreenshotAnimator.isAnimating());