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);
|
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
|
* 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
|
* 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);
|
return getRecentTasks().isRecentsComponentHomeActivity(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cancelRecentsAnimation(boolean restoreHomeRootTaskPosition) {
|
|
||||||
ActivityTaskManagerService.this.cancelRecentsAnimation(restoreHomeRootTaskPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkCanCloseSystemDialogs(int pid, int uid, @Nullable String packageName) {
|
public boolean checkCanCloseSystemDialogs(int pid, int uid, @Nullable String packageName) {
|
||||||
return ActivityTaskManagerService.this.checkCanCloseSystemDialogs(pid, uid,
|
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.IntDef;
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.app.WindowConfiguration;
|
import android.app.WindowConfiguration;
|
||||||
|
import android.graphics.GraphicBuffer;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
import android.hardware.HardwareBuffer;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.IBinder.DeathRecipient;
|
import android.os.IBinder.DeathRecipient;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
@@ -54,6 +56,7 @@ import android.view.InputWindowHandle;
|
|||||||
import android.view.RemoteAnimationTarget;
|
import android.view.RemoteAnimationTarget;
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
import android.view.SurfaceControl.Transaction;
|
import android.view.SurfaceControl.Transaction;
|
||||||
|
import android.view.SurfaceSession;
|
||||||
import android.view.WindowInsets.Type;
|
import android.view.WindowInsets.Type;
|
||||||
import android.window.PictureInPictureSurfaceTransaction;
|
import android.window.PictureInPictureSurfaceTransaction;
|
||||||
import android.window.TaskSnapshot;
|
import android.window.TaskSnapshot;
|
||||||
@@ -150,6 +153,8 @@ public class RecentsAnimationController implements DeathRecipient {
|
|||||||
private boolean mCancelOnNextTransitionStart;
|
private boolean mCancelOnNextTransitionStart;
|
||||||
// Whether to take a screenshot when handling a deferred cancel
|
// Whether to take a screenshot when handling a deferred cancel
|
||||||
private boolean mCancelDeferredWithScreenshot;
|
private boolean mCancelDeferredWithScreenshot;
|
||||||
|
// The reorder mode to apply after the cleanupScreenshot() callback
|
||||||
|
private int mPendingCancelWithScreenshotReorderMode = REORDER_MOVE_TO_ORIGINAL_POSITION;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
boolean mIsAddingTaskToTargets;
|
boolean mIsAddingTaskToTargets;
|
||||||
@@ -158,12 +163,6 @@ public class RecentsAnimationController implements DeathRecipient {
|
|||||||
private boolean mNavigationBarAttachedToApp;
|
private boolean mNavigationBarAttachedToApp;
|
||||||
private ActivityRecord mNavBarAttachedApp;
|
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
|
* An app transition listener to cancel the recents animation only after the app transition
|
||||||
* starts or is canceled.
|
* starts or is canceled.
|
||||||
@@ -355,12 +354,9 @@ public class RecentsAnimationController implements DeathRecipient {
|
|||||||
public void cleanupScreenshot() {
|
public void cleanupScreenshot() {
|
||||||
final long token = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
synchronized (mService.mGlobalLock) {
|
// Note, the callback will handle its own synchronization, do not lock on WM lock
|
||||||
if (mRecentScreenshotAnimator != null) {
|
// prior to calling the callback
|
||||||
mRecentScreenshotAnimator.cancelAnimation();
|
continueDeferredCancelAnimation();
|
||||||
mRecentScreenshotAnimator = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(token);
|
Binder.restoreCallingIdentity(token);
|
||||||
}
|
}
|
||||||
@@ -519,13 +515,13 @@ public class RecentsAnimationController implements DeathRecipient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) {
|
TaskAnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) {
|
||||||
return addAnimation(task, isRecentTaskInvisible, false /* hidden */,
|
return addAnimation(task, isRecentTaskInvisible, false /* hidden */,
|
||||||
null /* finishedCallback */);
|
null /* finishedCallback */);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible, boolean hidden,
|
TaskAnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible, boolean hidden,
|
||||||
OnAnimationFinishedCallback finishedCallback) {
|
OnAnimationFinishedCallback finishedCallback) {
|
||||||
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addAnimation(%s)", task.getName());
|
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addAnimation(%s)", task.getName());
|
||||||
final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task,
|
final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task,
|
||||||
@@ -541,9 +537,7 @@ public class RecentsAnimationController implements DeathRecipient {
|
|||||||
void removeAnimation(TaskAnimationAdapter taskAdapter) {
|
void removeAnimation(TaskAnimationAdapter taskAdapter) {
|
||||||
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
|
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
|
||||||
"removeAnimation(%d)", taskAdapter.mTask.mTaskId);
|
"removeAnimation(%d)", taskAdapter.mTask.mTaskId);
|
||||||
taskAdapter.mTask.setCanAffectSystemUiFlags(true);
|
taskAdapter.onRemove();
|
||||||
taskAdapter.mCapturedFinishCallback.onAnimationFinished(taskAdapter.mLastAnimationType,
|
|
||||||
taskAdapter);
|
|
||||||
mPendingAnimations.remove(taskAdapter);
|
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
|
* Cancels the running animation when starting home, providing a snapshot for the runner to
|
||||||
* tasks before the change (to ensure they are captured at the right configuration)
|
* 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() {
|
public void cancelAnimationForDisplayChange() {
|
||||||
if (mCanceled) {
|
if (mCanceled) {
|
||||||
@@ -843,16 +851,22 @@ public class RecentsAnimationController implements DeathRecipient {
|
|||||||
mCanceled = true;
|
mCanceled = true;
|
||||||
|
|
||||||
if (screenshot && !mPendingAnimations.isEmpty()) {
|
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.
|
// Screen shot previous task when next task starts transition and notify the runner.
|
||||||
// We will actually finish the animation once the runner calls cleanUpScreenshot().
|
// We will actually finish the animation once the runner calls cleanUpScreenshot().
|
||||||
final Task task = mPendingAnimations.get(0).mTask;
|
final TaskSnapshot taskSnapshot = screenshotRecentTask(task);
|
||||||
final TaskSnapshot taskSnapshot = screenshotRecentTask(task, reorderMode);
|
mPendingCancelWithScreenshotReorderMode = reorderMode;
|
||||||
try {
|
try {
|
||||||
mRunner.onAnimationCanceled(taskSnapshot);
|
mRunner.onAnimationCanceled(taskSnapshot);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Slog.e(TAG, "Failed to cancel recents animation", 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 */);
|
mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -869,6 +883,12 @@ public class RecentsAnimationController implements DeathRecipient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void continueDeferredCancelAnimation() {
|
||||||
|
mCallbacks.onAnimationFinished(mPendingCancelWithScreenshotReorderMode,
|
||||||
|
false /* sendUserLeaveHint */);
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void setWillFinishToHome(boolean willFinishToHome) {
|
void setWillFinishToHome(boolean willFinishToHome) {
|
||||||
mWillFinishToHome = willFinishToHome;
|
mWillFinishToHome = willFinishToHome;
|
||||||
@@ -915,29 +935,13 @@ public class RecentsAnimationController implements DeathRecipient {
|
|||||||
return mRequestDeferCancelUntilNextTransition && mCancelDeferredWithScreenshot;
|
return mRequestDeferCancelUntilNextTransition && mCancelDeferredWithScreenshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskSnapshot screenshotRecentTask(Task task, @ReorderMode int reorderMode) {
|
TaskSnapshot screenshotRecentTask(Task task) {
|
||||||
final TaskSnapshotController snapshotController = mService.mTaskSnapshotController;
|
final TaskSnapshotController snapshotController = mService.mTaskSnapshotController;
|
||||||
final ArraySet<Task> tasks = Sets.newArraySet(task);
|
final ArraySet<Task> tasks = Sets.newArraySet(task);
|
||||||
snapshotController.snapshotTasks(tasks);
|
snapshotController.snapshotTasks(tasks);
|
||||||
snapshotController.addSkipClosingAppSnapshotTasks(tasks);
|
snapshotController.addSkipClosingAppSnapshotTasks(tasks);
|
||||||
final TaskSnapshot taskSnapshot = snapshotController.getSnapshot(task.mTaskId,
|
return snapshotController.getSnapshot(task.mTaskId, task.mUserId,
|
||||||
task.mUserId, false /* restoreFromDisk */, false /* isLowResolution */);
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanupAnimation(@ReorderMode int reorderMode) {
|
void cleanupAnimation(@ReorderMode int reorderMode) {
|
||||||
@@ -976,12 +980,6 @@ public class RecentsAnimationController implements DeathRecipient {
|
|||||||
mRunner = null;
|
mRunner = null;
|
||||||
mCanceled = true;
|
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
|
// 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.
|
// IME icon may missing if the moving task has already been the current focused task.
|
||||||
if (reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION && !mIsAddingTaskToTargets) {
|
if (reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION && !mIsAddingTaskToTargets) {
|
||||||
@@ -1028,16 +1026,7 @@ public class RecentsAnimationController implements DeathRecipient {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void binderDied() {
|
public void binderDied() {
|
||||||
if (!mCanceled) {
|
cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
|
||||||
cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
|
|
||||||
} else {
|
|
||||||
synchronized (mService.getWindowManagerLock()) {
|
|
||||||
if (mRecentScreenshotAnimator != null) {
|
|
||||||
mRecentScreenshotAnimator.cancelAnimation();
|
|
||||||
mRecentScreenshotAnimator = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (mService.getWindowManagerLock()) {
|
synchronized (mService.getWindowManagerLock()) {
|
||||||
// Clear associated input consumers on runner death
|
// Clear associated input consumers on runner death
|
||||||
@@ -1171,6 +1160,8 @@ public class RecentsAnimationController implements DeathRecipient {
|
|||||||
private PictureInPictureSurfaceTransaction mFinishTransaction;
|
private PictureInPictureSurfaceTransaction mFinishTransaction;
|
||||||
// An overlay used to mask the content as an app goes into PIP
|
// An overlay used to mask the content as an app goes into PIP
|
||||||
private SurfaceControl mFinishOverlay;
|
private SurfaceControl mFinishOverlay;
|
||||||
|
// An overlay used for canceling the animation with a screenshot
|
||||||
|
private SurfaceControl mSnapshotOverlay;
|
||||||
|
|
||||||
TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
|
TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
|
||||||
mTask = task;
|
mTask = task;
|
||||||
@@ -1205,10 +1196,47 @@ public class RecentsAnimationController implements DeathRecipient {
|
|||||||
return mTarget;
|
return mTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onCleanup() {
|
void setSnapshotOverlay(TaskSnapshot snapshot) {
|
||||||
if (mFinishTransaction != null) {
|
// Create a surface control for the snapshot and reparent it to the leash
|
||||||
final Transaction pendingTransaction = mTask.getPendingTransaction();
|
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
|
// Reparent the overlay
|
||||||
if (mFinishOverlay != null) {
|
if (mFinishOverlay != null) {
|
||||||
pendingTransaction.reparent(mFinishOverlay, mTask.mSurfaceControl);
|
pendingTransaction.reparent(mFinishOverlay, mTask.mSurfaceControl);
|
||||||
@@ -1236,10 +1264,15 @@ public class RecentsAnimationController implements DeathRecipient {
|
|||||||
} else if (!mTask.isAttached()) {
|
} else if (!mTask.isAttached()) {
|
||||||
// Apply the task's pending transaction in case it is detached and its transaction
|
// Apply the task's pending transaction in case it is detached and its transaction
|
||||||
// is not reachable.
|
// is not reachable.
|
||||||
mTask.getPendingTransaction().apply();
|
pendingTransaction.apply();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public SurfaceControl getSnapshotOverlay() {
|
||||||
|
return mSnapshotOverlay;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getShowWallpaper() {
|
public boolean getShowWallpaper() {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1529,7 +1529,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
|
|||||||
// Updates the extra information of the intent.
|
// Updates the extra information of the intent.
|
||||||
if (fromHomeKey) {
|
if (fromHomeKey) {
|
||||||
homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);
|
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);
|
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.setDeferredCancel(true /* deferred */, false /* screenshot */);
|
||||||
mController.cancelAnimationWithScreenshot(false /* screenshot */);
|
mController.cancelAnimationWithScreenshot(false /* screenshot */);
|
||||||
verify(mMockRunner).onAnimationCanceled(null /* taskSnapshot */);
|
verify(mMockRunner).onAnimationCanceled(null /* taskSnapshot */);
|
||||||
assertNull(mController.mRecentScreenshotAnimator);
|
|
||||||
|
|
||||||
// Simulate the app transition finishing
|
// Simulate the app transition finishing
|
||||||
mController.mAppTransitionListener.onAppTransitionStartingLocked(false, 0, 0, 0);
|
mController.mAppTransitionListener.onAppTransitionStartingLocked(false, 0, 0, 0);
|
||||||
@@ -271,7 +270,8 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
|
|||||||
assertEquals(activity.getTask().getTopVisibleActivity(), activity);
|
assertEquals(activity.getTask().getTopVisibleActivity(), activity);
|
||||||
assertEquals(activity.findMainWindow(), win1);
|
assertEquals(activity.findMainWindow(), win1);
|
||||||
|
|
||||||
mController.addAnimation(activity.getTask(), false /* isRecentTaskInvisible */);
|
RecentsAnimationController.TaskAnimationAdapter adapter = mController.addAnimation(
|
||||||
|
activity.getTask(), false /* isRecentTaskInvisible */);
|
||||||
assertTrue(mController.isAnimatingTask(activity.getTask()));
|
assertTrue(mController.isAnimatingTask(activity.getTask()));
|
||||||
|
|
||||||
spyOn(mWm.mTaskSnapshotController);
|
spyOn(mWm.mTaskSnapshotController);
|
||||||
@@ -282,14 +282,9 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
|
|||||||
mController.setDeferredCancel(true /* deferred */, true /* screenshot */);
|
mController.setDeferredCancel(true /* deferred */, true /* screenshot */);
|
||||||
mController.cancelAnimationWithScreenshot(true /* screenshot */);
|
mController.cancelAnimationWithScreenshot(true /* screenshot */);
|
||||||
verify(mMockRunner).onAnimationCanceled(mMockTaskSnapshot /* taskSnapshot */);
|
verify(mMockRunner).onAnimationCanceled(mMockTaskSnapshot /* taskSnapshot */);
|
||||||
assertNotNull(mController.mRecentScreenshotAnimator);
|
|
||||||
assertTrue(mController.mRecentScreenshotAnimator.isAnimating());
|
|
||||||
|
|
||||||
// Assume IRecentsAnimationController#cleanupScreenshot called to finish screenshot
|
// Continue the animation (simulating a call to cleanupScreenshot())
|
||||||
// animation.
|
mController.continueDeferredCancelAnimation();
|
||||||
spyOn(mController.mRecentScreenshotAnimator.mAnimatable);
|
|
||||||
mController.mRecentScreenshotAnimator.cancelAnimation();
|
|
||||||
verify(mController.mRecentScreenshotAnimator.mAnimatable).onAnimationLeashLost(any());
|
|
||||||
verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, false);
|
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);
|
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() {
|
private ActivityRecord createHomeActivity() {
|
||||||
final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService)
|
final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService)
|
||||||
.setParentTask(mRootHomeTask)
|
.setParentTask(mRootHomeTask)
|
||||||
|
|||||||
Reference in New Issue
Block a user