Merge "Decompose prepareAnimationIfNeeded into smaller methods."

This commit is contained in:
Wei Sheng Shih
2023-02-07 02:20:54 +00:00
committed by Android (Google) Code Review
4 changed files with 426 additions and 291 deletions

View File

@@ -19,7 +19,6 @@ package com.android.server.wm;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_TO_BACK;
@@ -28,12 +27,12 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW;
import static com.android.server.wm.BackNavigationProto.ANIMATION_IN_PROGRESS;
import static com.android.server.wm.BackNavigationProto.LAST_BACK_TYPE;
import static com.android.server.wm.BackNavigationProto.SHOW_WALLPAPER;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_PREDICT_BACK;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteCallback;
@@ -45,6 +44,7 @@ import android.util.proto.ProtoOutputStream;
import android.view.IWindowFocusObserver;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.WindowInsets;
import android.window.BackAnimationAdapter;
import android.window.BackNavigationInfo;
import android.window.IBackAnimationFinishedCallback;
@@ -54,8 +54,11 @@ import android.window.TaskSnapshot;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.LocalServices;
import com.android.server.wm.utils.InsetUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.function.Consumer;
/**
* Controller to handle actions related to the back gesture on the server side.
@@ -69,7 +72,7 @@ class BackNavigationController {
private boolean mShowWallpaper;
private Runnable mPendingAnimation;
private final AnimationTargets mAnimationTargets = new AnimationTargets();
private AnimationHandler mAnimationHandler;
private final ArrayList<WindowContainer> mTmpOpenApps = new ArrayList<>();
private final ArrayList<WindowContainer> mTmpCloseApps = new ArrayList<>();
@@ -233,7 +236,6 @@ class BackNavigationController {
return infoBuilder.build();
}
mBackAnimationInProgress = true;
// We don't have an application callback, let's find the destination of the back gesture
// The search logic should align with ActivityClientController#finishActivity
prevActivity = currentTask.topRunningActivity(currentActivity.token, INVALID_TASK_ID);
@@ -314,8 +316,17 @@ class BackNavigationController {
}
if (prepareAnimation) {
prepareAnimationIfNeeded(currentTask, prevTask, prevActivity,
removedWindowContainer, backType, adapter);
mPendingAnimation = mAnimationHandler.scheduleAnimation(backType, adapter,
currentTask, prevTask, currentActivity, prevActivity);
prepareAnimation = mPendingAnimation != null;
mBackAnimationInProgress = prepareAnimation;
if (prepareAnimation) {
mWindowManagerService.mWindowPlacerLocked.requestTraversal();
if (mShowWallpaper) {
currentTask.getDisplayContent().mWallpaperController
.adjustWallpaperWindows();
}
}
}
infoBuilder.setPrepareRemoteAnimation(prepareAnimation);
} // Release wm Lock
@@ -333,7 +344,7 @@ class BackNavigationController {
}
boolean isWaitBackTransition() {
return mAnimationTargets.mComposed && mAnimationTargets.mWaitTransition;
return mAnimationHandler.mComposed && mAnimationHandler.mWaitTransition;
}
boolean isKeyguardOccluded(WindowState focusWindow) {
@@ -359,18 +370,19 @@ class BackNavigationController {
boolean result = false;
// Note: TmpOpenApps is empty. Unlike shell transition, the open apps will be removed from
// mOpeningApps if there is no visibility change.
if (mAnimationTargets.containsBackAnimationTargets(mTmpOpenApps, mTmpCloseApps)) {
if (mAnimationHandler.containsBackAnimationTargets(mTmpOpenApps, mTmpCloseApps)) {
// remove close target from close list, open target from open list;
// but the open target can be in close list.
for (int i = openApps.size() - 1; i >= 0; --i) {
final ActivityRecord ar = openApps.valueAt(i);
if (mAnimationTargets.isTarget(ar, true /* open */)) {
if (mAnimationHandler.isTarget(ar, true /* open */)) {
openApps.removeAt(i);
mAnimationHandler.mOpenTransitionTargetMatch = true;
}
}
for (int i = closeApps.size() - 1; i >= 0; --i) {
final ActivityRecord ar = closeApps.valueAt(i);
if (mAnimationTargets.isTarget(ar, false /* open */)) {
if (mAnimationHandler.isTarget(ar, false /* open */)) {
closeApps.removeAt(i);
}
}
@@ -391,7 +403,7 @@ class BackNavigationController {
* animations, and shouldn't join next transition.
*/
boolean containsBackAnimationTargets(Transition transition) {
if (!mAnimationTargets.mComposed
if (!mAnimationHandler.mComposed
|| (transition.mType != TRANSIT_CLOSE && transition.mType != TRANSIT_TO_BACK)) {
return false;
}
@@ -408,18 +420,22 @@ class BackNavigationController {
mTmpCloseApps.add(wc);
}
}
final boolean result = mAnimationTargets.containsBackAnimationTargets(
final boolean result = mAnimationHandler.containsBackAnimationTargets(
mTmpOpenApps, mTmpCloseApps);
if (result) {
mAnimationHandler.mOpenTransitionTargetMatch =
mAnimationHandler.containTarget(mTmpOpenApps, true);
}
mTmpOpenApps.clear();
mTmpCloseApps.clear();
return result;
}
boolean isMonitorTransitionTarget(WindowContainer wc) {
if (!mAnimationTargets.mComposed || !mAnimationTargets.mWaitTransition) {
if (!mAnimationHandler.mComposed || !mAnimationHandler.mWaitTransition) {
return false;
}
return mAnimationTargets.isTarget(wc, wc.isVisibleRequested() /* open */);
return mAnimationHandler.isTarget(wc, wc.isVisibleRequested() /* open */);
}
/**
@@ -428,60 +444,106 @@ class BackNavigationController {
* cleanup together.
*/
void clearBackAnimations(SurfaceControl.Transaction cleanupTransaction) {
mAnimationTargets.clearBackAnimateTarget(cleanupTransaction);
mAnimationHandler.clearBackAnimateTarget(cleanupTransaction);
}
/**
* TODO: Animation composer
* prepareAnimationIfNeeded will become too complicated in order to support
* ActivityRecord/WindowState, using a factory class to create the RemoteAnimationTargets for
* different scenario.
* Create and handling animations status for an open/close animation targets.
*/
private static class AnimationTargets {
ActivityRecord mCloseTarget; // Must be activity
WindowContainer mOpenTarget; // Can be activity or task if activity was removed
private static class AnimationHandler {
private final WindowManagerService mWindowManagerService;
private BackWindowAnimationAdaptor mCloseAdaptor;
private BackWindowAnimationAdaptor mOpenAdaptor;
private boolean mComposed;
private boolean mWaitTransition;
private int mSwitchType = UNKNOWN;
private SurfaceControl.Transaction mFinishedTransaction;
// This will be set before transition happen, to know whether the real opening target
// exactly match animating target. When target match, reparent the starting surface to
// the opening target like starting window do.
private boolean mOpenTransitionTargetMatch;
// The starting surface task Id. Used to clear the starting surface if the animation has
// request one during animating.
private int mRequestedStartingSurfaceTaskId;
private SurfaceControl mStartingSurface;
AnimationHandler(WindowManagerService wms) {
mWindowManagerService = wms;
}
private static final int UNKNOWN = 0;
private static final int TASK_SWITCH = 1;
private static final int ACTIVITY_SWITCH = 2;
void reset(@NonNull WindowContainer close, @NonNull WindowContainer open) {
clearBackAnimateTarget(null);
if (close == null || open == null) {
Slog.e(TAG, "reset animation with null target close: "
+ close + " open: " + open);
return;
}
private void initiate(WindowContainer close, WindowContainer open) {
WindowContainer closeTarget;
if (close.asActivityRecord() != null && open.asActivityRecord() != null
&& (close.asActivityRecord().getTask() == open.asActivityRecord().getTask())) {
mSwitchType = ACTIVITY_SWITCH;
mCloseTarget = close.asActivityRecord();
closeTarget = close.asActivityRecord();
} else if (close.asTask() != null && open.asTask() != null
&& close.asTask() != open.asTask()) {
mSwitchType = TASK_SWITCH;
mCloseTarget = close.asTask().getTopNonFinishingActivity();
closeTarget = close.asTask().getTopNonFinishingActivity();
} else {
mSwitchType = UNKNOWN;
return;
}
mOpenTarget = open;
mComposed = false;
mWaitTransition = false;
mCloseAdaptor = createAdaptor(closeTarget, false /* isOpen */);
mOpenAdaptor = createAdaptor(open, true /* isOpen */);
if (mCloseAdaptor.mAnimationTarget == null || mOpenAdaptor.mAnimationTarget == null) {
Slog.w(TAG, "composeNewAnimations fail, skip");
clearBackAnimateTarget(null /* cleanupTransaction */);
}
}
void composeNewAnimations(@NonNull WindowContainer close, @NonNull WindowContainer open) {
reset(close, open);
if (mSwitchType == UNKNOWN || mComposed || mCloseTarget == mOpenTarget
|| mCloseTarget == null || mOpenTarget == null) {
return;
boolean composeAnimations(@NonNull WindowContainer close, @NonNull WindowContainer open) {
clearBackAnimateTarget(null /* cleanupTransaction */);
if (close == null || open == null) {
Slog.e(TAG, "reset animation with null target close: "
+ close + " open: " + open);
return false;
}
initiate(close, open);
if (mSwitchType == UNKNOWN) {
return false;
}
mComposed = true;
mWaitTransition = false;
return true;
}
RemoteAnimationTarget[] getAnimationTargets() {
return mComposed ? new RemoteAnimationTarget[] {
mCloseAdaptor.mAnimationTarget, mOpenAdaptor.mAnimationTarget} : null;
}
boolean isSupportWindowlessSurface() {
return mWindowManagerService.mAtmService.mTaskOrganizerController
.isSupportWindowlessStartingSurface();
}
void createStartingSurface(TaskSnapshot snapshot) {
if (!mComposed) {
return;
}
final ActivityRecord topActivity = getTopOpenActivity();
if (topActivity == null) {
Slog.e(TAG, "createStartingSurface fail, no open activity: " + this);
return;
}
// TODO (b/257857570) draw snapshot by starting surface.
}
private ActivityRecord getTopOpenActivity() {
if (mSwitchType == ACTIVITY_SWITCH) {
return mOpenAdaptor.mTarget.asActivityRecord();
} else if (mSwitchType == TASK_SWITCH) {
return mOpenAdaptor.mTarget.asTask().getTopNonFinishingActivity();
}
return null;
}
boolean containTarget(ArrayList<WindowContainer> wcs, boolean open) {
@@ -495,13 +557,13 @@ class BackNavigationController {
boolean isTarget(WindowContainer wc, boolean open) {
if (open) {
return wc == mOpenTarget || mOpenTarget.hasChild(wc);
return wc == mOpenAdaptor.mTarget || mOpenAdaptor.mTarget.hasChild(wc);
}
if (mSwitchType == TASK_SWITCH) {
return wc == mCloseTarget
|| (wc.asTask() != null && wc.hasChild(mCloseTarget));
return wc == mCloseAdaptor.mTarget
|| (wc.asTask() != null && wc.hasChild(mCloseAdaptor.mTarget));
} else if (mSwitchType == ACTIVITY_SWITCH) {
return wc == mCloseTarget;
return wc == mCloseAdaptor.mTarget;
}
return false;
}
@@ -519,19 +581,53 @@ class BackNavigationController {
return;
}
final SurfaceControl.Transaction pt = t != null ? t
: mOpenTarget.getPendingTransaction();
: mOpenAdaptor.mTarget.getPendingTransaction();
if (mFinishedTransaction != null) {
pt.merge(mFinishedTransaction);
mFinishedTransaction = null;
}
cleanUpWindowlessSurface();
if (mCloseAdaptor != null) {
mCloseAdaptor.mTarget.cancelAnimation();
mCloseAdaptor = null;
}
if (mOpenAdaptor != null) {
mOpenAdaptor.mTarget.cancelAnimation();
mOpenAdaptor = null;
}
}
private void cleanUpWindowlessSurface() {
final ActivityRecord ar = getTopOpenActivity();
if (ar == null) {
Slog.w(TAG, "finishPresentAnimations without top activity: " + this);
}
final SurfaceControl.Transaction pendingT = ar != null ? ar.getPendingTransaction()
: mOpenAdaptor.mTarget.getPendingTransaction();
// ensure open target is visible before cancel animation.
mOpenTransitionTargetMatch &= ar != null;
if (mOpenTransitionTargetMatch) {
pendingT.show(ar.getSurfaceControl());
}
if (mRequestedStartingSurfaceTaskId != 0) {
// If open target match, reparent to open activity
if (mStartingSurface != null && mOpenTransitionTargetMatch) {
pendingT.reparent(mStartingSurface, ar.getSurfaceControl());
}
// remove starting surface.
mStartingSurface = null;
// TODO (b/257857570) draw snapshot by starting surface.
mRequestedStartingSurfaceTaskId = 0;
}
}
void clearBackAnimateTarget(SurfaceControl.Transaction cleanupTransaction) {
finishPresentAnimations(cleanupTransaction);
mCloseTarget = null;
mOpenTarget = null;
mComposed = false;
mWaitTransition = false;
mOpenTransitionTargetMatch = false;
mRequestedStartingSurfaceTaskId = 0;
mSwitchType = UNKNOWN;
if (mFinishedTransaction != null) {
Slog.w(TAG, "Clear back animation, found un-processed finished transaction");
@@ -555,211 +651,284 @@ class BackNavigationController {
@Override
public String toString() {
final StringBuilder sb = new StringBuilder(128);
sb.append("AnimationTargets{");
sb.append(" mOpenTarget= ");
sb.append(mOpenTarget);
sb.append(" mCloseTarget= ");
sb.append(mCloseTarget);
sb.append(" mSwitchType= ");
sb.append(mSwitchType);
sb.append(" mComposed= ");
sb.append(mComposed);
sb.append(" mWaitTransition= ");
sb.append(mWaitTransition);
sb.append('}');
return sb.toString();
return "AnimationTargets{"
+ " openTarget= "
+ mOpenAdaptor.mTarget
+ " closeTarget= "
+ mCloseAdaptor.mTarget
+ " mSwitchType= "
+ mSwitchType
+ " mComposed= "
+ mComposed
+ " mWaitTransition= "
+ mWaitTransition
+ '}';
}
}
private void prepareAnimationIfNeeded(Task currentTask,
Task prevTask, ActivityRecord prevActivity, WindowContainer<?> removedWindowContainer,
int backType, BackAnimationAdapter adapter) {
final ArrayList<SurfaceControl> leashes = new ArrayList<>();
final SurfaceControl.Transaction startedTransaction = currentTask.getPendingTransaction();
final SurfaceControl.Transaction finishedTransaction = new SurfaceControl.Transaction();
// Prepare a leash to animate for the departing window
final SurfaceControl animLeash = currentTask.makeAnimationLeash()
.setName("BackPreview Leash for " + currentTask)
.setHidden(false)
.build();
removedWindowContainer.reparentSurfaceControl(startedTransaction, animLeash);
private static BackWindowAnimationAdaptor createAdaptor(
WindowContainer target, boolean isOpen) {
final BackWindowAnimationAdaptor adaptor =
new BackWindowAnimationAdaptor(target, isOpen);
target.startAnimation(target.getPendingTransaction(), adaptor, false /* hidden */,
ANIMATION_TYPE_PREDICT_BACK);
return adaptor;
}
final RemoteAnimationTarget topAppTarget = createRemoteAnimationTargetLocked(
currentTask, animLeash, MODE_CLOSING);
private static class BackWindowAnimationAdaptor implements AnimationAdapter {
SurfaceControl mCapturedLeash;
private final Rect mBounds = new Rect();
private final WindowContainer mTarget;
private final boolean mIsOpen;
private RemoteAnimationTarget mAnimationTarget;
// reset leash after animation finished.
leashes.add(animLeash);
removedWindowContainer.reparentSurfaceControl(finishedTransaction,
removedWindowContainer.getParentSurfaceControl());
BackWindowAnimationAdaptor(WindowContainer closeTarget, boolean isOpen) {
mBounds.set(closeTarget.getBounds());
mTarget = closeTarget;
mIsOpen = isOpen;
}
@Override
public boolean getShowWallpaper() {
return false;
}
// Prepare a leash to animate for the entering window.
RemoteAnimationTarget behindAppTarget = null;
if (needsScreenshot(backType)) {
HardwareBuffer screenshotBuffer = null;
Task backTargetTask = prevTask;
switch(backType) {
case BackNavigationInfo.TYPE_CROSS_TASK:
int prevTaskId = prevTask != null ? prevTask.mTaskId : 0;
int prevUserId = prevTask != null ? prevTask.mUserId : 0;
screenshotBuffer = getTaskSnapshot(prevTaskId, prevUserId);
break;
@Override
public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t,
int type, SurfaceAnimator.OnAnimationFinishedCallback finishCallback) {
mCapturedLeash = animationLeash;
createRemoteAnimationTarget(mIsOpen);
}
@Override
public void onAnimationCancelled(SurfaceControl animationLeash) {
if (mCapturedLeash == animationLeash) {
mCapturedLeash = null;
}
}
@Override
public long getDurationHint() {
return 0;
}
@Override
public long getStatusBarTransitionsStartTime() {
return 0;
}
@Override
public void dump(PrintWriter pw, String prefix) {
pw.print(prefix + "BackWindowAnimationAdaptor mCapturedLeash=");
pw.print(mCapturedLeash);
pw.println();
}
@Override
public void dumpDebug(ProtoOutputStream proto) {
}
RemoteAnimationTarget createRemoteAnimationTarget(boolean isOpen) {
if (mAnimationTarget != null) {
return mAnimationTarget;
}
Task t = mTarget.asTask();
final ActivityRecord r = t != null ? t.getTopNonFinishingActivity()
: mTarget.asActivityRecord();
if (t == null && r != null) {
t = r.getTask();
}
if (t == null || r == null) {
Slog.e(TAG, "createRemoteAnimationTarget fail " + mTarget);
return null;
}
final WindowState mainWindow = r.findMainWindow();
Rect insets;
if (mainWindow != null) {
insets = mainWindow.getInsetsStateWithVisibilityOverride().calculateInsets(
mBounds, WindowInsets.Type.systemBars(),
false /* ignoreVisibility */).toRect();
InsetUtils.addInsets(insets, mainWindow.mActivityRecord.getLetterboxInsets());
} else {
insets = new Rect();
}
final int mode = isOpen ? MODE_OPENING : MODE_CLOSING;
mAnimationTarget = new RemoteAnimationTarget(t.mTaskId, mode, mCapturedLeash,
!r.fillsParent(), new Rect(),
insets, r.getPrefixOrderIndex(), new Point(mBounds.left, mBounds.top),
mBounds, mBounds, t.getWindowConfiguration(),
true /* isNotInRecents */, null, null, t.getTaskInfo(),
r.checkEnterPictureInPictureAppOpsState());
return mAnimationTarget;
}
}
Runnable scheduleAnimation(int backType, BackAnimationAdapter adapter,
Task currentTask, Task previousTask, ActivityRecord currentActivity,
ActivityRecord previousActivity) {
switch (backType) {
case BackNavigationInfo.TYPE_RETURN_TO_HOME:
return new ScheduleAnimationBuilder(backType, adapter)
.setIsLaunchBehind(true)
.setComposeTarget(currentTask, previousTask)
.build();
case BackNavigationInfo.TYPE_CROSS_ACTIVITY:
if (prevActivity != null && prevActivity.mActivityComponent != null) {
screenshotBuffer = getActivitySnapshot(currentTask, prevActivity);
return new ScheduleAnimationBuilder(backType, adapter)
.setComposeTarget(currentActivity, previousActivity)
.setOpeningSnapshot(getActivitySnapshot(previousActivity)).build();
case BackNavigationInfo.TYPE_CROSS_TASK:
return new ScheduleAnimationBuilder(backType, adapter)
.setComposeTarget(currentTask, previousTask)
.setOpeningSnapshot(getTaskSnapshot(previousTask)).build();
}
return null;
}
private class ScheduleAnimationBuilder {
final int mType;
final BackAnimationAdapter mBackAnimationAdapter;
WindowContainer mCloseTarget;
WindowContainer mOpenTarget;
TaskSnapshot mOpenSnapshot;
boolean mIsLaunchBehind;
ScheduleAnimationBuilder(int type, BackAnimationAdapter backAnimationAdapter) {
mType = type;
mBackAnimationAdapter = backAnimationAdapter;
}
ScheduleAnimationBuilder setComposeTarget(WindowContainer close, WindowContainer open) {
mCloseTarget = close;
mOpenTarget = open;
return this;
}
ScheduleAnimationBuilder setOpeningSnapshot(TaskSnapshot snapshot) {
mOpenSnapshot = snapshot;
return this;
}
ScheduleAnimationBuilder setIsLaunchBehind(boolean launchBehind) {
mIsLaunchBehind = launchBehind;
return this;
}
Runnable build() {
if (mOpenTarget == null || mCloseTarget == null) {
return null;
}
final boolean shouldLaunchBehind = mIsLaunchBehind || !isSupportWindowlessSurface();
final ActivityRecord launchBehindActivity = !shouldLaunchBehind ? null
: mOpenTarget.asTask() != null
? mOpenTarget.asTask().getTopNonFinishingActivity()
: mOpenTarget.asActivityRecord() != null
? mOpenTarget.asActivityRecord() : null;
if (shouldLaunchBehind && launchBehindActivity == null) {
Slog.e(TAG, "No opening activity");
return null;
}
if (!composeAnimations(mCloseTarget, mOpenTarget)) {
return null;
}
if (launchBehindActivity != null) {
setLaunchBehind(launchBehindActivity);
} else {
createStartingSurface(mOpenSnapshot);
}
final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback(
launchBehindActivity != null ? triggerBack -> {
if (!triggerBack) {
restoreLaunchBehind(launchBehindActivity);
}
} : null,
mCloseTarget);
final RemoteAnimationTarget[] targets = getAnimationTargets();
return () -> {
try {
mBackAnimationAdapter.getRunner().onAnimationStart(mType,
targets, null, null, callback);
} catch (RemoteException e) {
e.printStackTrace();
}
backTargetTask = currentTask;
break;
};
}
// Find a screenshot of the previous activity if we actually have an animation
SurfaceControl animationLeashParent = removedWindowContainer.getAnimationLeashParent();
if (screenshotBuffer != null) {
final SurfaceControl screenshotSurface = new SurfaceControl.Builder()
.setName("BackPreview Screenshot for " + prevActivity)
.setHidden(false)
.setParent(animationLeashParent)
.setBLASTLayer()
.build();
startedTransaction.setBuffer(screenshotSurface, screenshotBuffer);
// The Animation leash needs to be above the screenshot surface, but the animation
// leash needs to be added before to be in the synchronized block.
startedTransaction.setLayer(topAppTarget.leash, 1);
behindAppTarget =
createRemoteAnimationTargetLocked(
backTargetTask, screenshotSurface, MODE_OPENING);
// reset leash after animation finished.
leashes.add(screenshotSurface);
}
} else if (prevTask != null && prevActivity != null) {
// Make previous task show from behind by marking its top activity as visible
// and launch-behind to bump its visibility for the duration of the back gesture.
setLaunchBehind(prevActivity);
final SurfaceControl leash = prevActivity.makeAnimationLeash()
.setName("BackPreview Leash for " + prevActivity)
.setHidden(false)
.build();
prevActivity.reparentSurfaceControl(startedTransaction, leash);
behindAppTarget = createRemoteAnimationTargetLocked(
prevTask, leash, MODE_OPENING);
// reset leash after animation finished.
leashes.add(leash);
prevActivity.reparentSurfaceControl(finishedTransaction,
prevActivity.getParentSurfaceControl());
}
if (mShowWallpaper) {
currentTask.getDisplayContent().mWallpaperController.adjustWallpaperWindows();
// TODO(b/241808055): If the current animation need to show wallpaper and animate the
// wallpaper, start the wallpaper animation to collect wallpaper target and deliver it
// to the back animation controller.
}
final RemoteAnimationTarget[] targets = (behindAppTarget == null)
? new RemoteAnimationTarget[] {topAppTarget}
: new RemoteAnimationTarget[] {topAppTarget, behindAppTarget};
final ActivityRecord finalPrevActivity = prevActivity;
final IBackAnimationFinishedCallback callback =
new IBackAnimationFinishedCallback.Stub() {
private IBackAnimationFinishedCallback makeAnimationFinishedCallback(
Consumer<Boolean> b, WindowContainer closeTarget) {
return new IBackAnimationFinishedCallback.Stub() {
@Override
public void onAnimationFinished(boolean triggerBack) {
for (SurfaceControl sc: leashes) {
finishedTransaction.remove(sc);
}
final SurfaceControl.Transaction finishedTransaction =
new SurfaceControl.Transaction();
synchronized (mWindowManagerService.mGlobalLock) {
if (b != null) {
b.accept(triggerBack);
}
if (triggerBack) {
final SurfaceControl surfaceControl =
removedWindowContainer.getSurfaceControl();
closeTarget.getSurfaceControl();
if (surfaceControl != null && surfaceControl.isValid()) {
// The animation is finish and start waiting for transition,
// hide the task surface before it re-parented to avoid flicker.
// Hide the close target surface when transition start.
finishedTransaction.hide(surfaceControl);
}
} else if (!needsScreenshot(backType)) {
restoreLaunchBehind(finalPrevActivity);
}
if (!mAnimationTargets.setFinishTransaction(finishedTransaction)) {
if (!setFinishTransaction(finishedTransaction)) {
finishedTransaction.apply();
}
if (!triggerBack) {
mAnimationTargets.clearBackAnimateTarget(null);
clearBackAnimateTarget(
null /* cleanupTransaction */);
} else {
mAnimationTargets.mWaitTransition = true;
mWaitTransition = true;
}
}
// TODO Add timeout monitor if transition didn't happen
}
};
if (backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) {
mAnimationTargets.composeNewAnimations(removedWindowContainer, prevActivity);
} else if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
|| backType == BackNavigationInfo.TYPE_CROSS_TASK) {
mAnimationTargets.composeNewAnimations(removedWindowContainer, prevTask);
}
scheduleAnimationLocked(backType, targets, adapter, callback);
}
@NonNull
private static RemoteAnimationTarget createRemoteAnimationTargetLocked(
Task task, SurfaceControl animLeash, int mode) {
ActivityRecord topApp = task.getTopRealVisibleActivity();
if (topApp == null) {
topApp = task.getTopNonFinishingActivity();
}
final WindowState mainWindow = topApp != null
? topApp.findMainWindow()
: null;
int windowType = INVALID_WINDOW_TYPE;
if (mainWindow != null) {
windowType = mainWindow.getWindowType();
}
Rect bounds = new Rect(task.getBounds());
Rect localBounds = new Rect(bounds);
Point tmpPos = new Point();
task.getRelativePosition(tmpPos);
localBounds.offsetTo(tmpPos.x, tmpPos.y);
return new RemoteAnimationTarget(
task.mTaskId,
mode,
animLeash,
false /* isTransluscent */,
new Rect() /* clipRect */,
new Rect() /* contentInsets */,
task.getPrefixOrderIndex(),
tmpPos /* position */,
localBounds /* localBounds */,
bounds /* screenSpaceBounds */,
task.getWindowConfiguration(),
true /* isNotInRecent */,
null,
null,
task.getTaskInfo(),
false,
windowType);
}
@VisibleForTesting
void scheduleAnimationLocked(@BackNavigationInfo.BackTargetType int type,
RemoteAnimationTarget[] targets, BackAnimationAdapter backAnimationAdapter,
IBackAnimationFinishedCallback callback) {
mPendingAnimation = () -> {
try {
backAnimationAdapter.getRunner().onAnimationStart(type,
targets, null, null, callback);
} catch (RemoteException e) {
e.printStackTrace();
}
};
mWindowManagerService.mWindowPlacerLocked.requestTraversal();
private void setLaunchBehind(ActivityRecord activity) {
if (activity == null) {
return;
}
if (!activity.isVisibleRequested()) {
activity.setVisibility(true);
}
activity.mLaunchTaskBehind = true;
// Handle fixed rotation launching app.
final DisplayContent dc = activity.mDisplayContent;
dc.rotateInDifferentOrientationIfNeeded(activity);
if (activity.hasFixedRotationTransform()) {
// Set the record so we can recognize it to continue to update display
// orientation if the previous activity becomes the top later.
dc.setFixedRotationLaunchingApp(activity,
activity.getWindowConfiguration().getRotation());
}
ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
"Setting Activity.mLauncherTaskBehind to true. Activity=%s", activity);
activity.mTaskSupervisor.mStoppingActivities.remove(activity);
activity.getDisplayContent().ensureActivitiesVisible(null /* starting */,
0 /* configChanges */, false /* preserveWindows */, true);
}
private void restoreLaunchBehind(ActivityRecord activity) {
if (activity == null) {
return;
}
activity.mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp();
// Restore the launch-behind state.
activity.mTaskSupervisor.scheduleLaunchTaskBehindComplete(activity.token);
activity.mLaunchTaskBehind = false;
ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
"Setting Activity.mLauncherTaskBehind to false. Activity=%s",
activity);
}
}
}
void checkAnimationReady(WallpaperController wallpaperController) {
@@ -796,80 +965,36 @@ class BackNavigationController {
mShowWallpaper = false;
}
private HardwareBuffer getActivitySnapshot(@NonNull Task task, ActivityRecord r) {
return task.getSnapshotForActivityRecord(r);
}
private HardwareBuffer getTaskSnapshot(int taskId, int userId) {
if (mWindowManagerService.mTaskSnapshotController == null) {
private static TaskSnapshot getActivitySnapshot(@NonNull ActivityRecord r) {
if (!isScreenshotEnabled()) {
return null;
}
TaskSnapshot snapshot = mWindowManagerService.mTaskSnapshotController.getSnapshot(taskId,
userId, true /* restoreFromDisk */, false /* isLowResolution */);
return snapshot != null ? snapshot.getHardwareBuffer() : null;
// Check if we have a screenshot of the previous activity, indexed by its
// component name.
// TODO return TaskSnapshot when feature complete.
// final HardwareBuffer hw = r.getTask().getSnapshotForActivityRecord(r);
return null;
}
private boolean needsScreenshot(int backType) {
private static TaskSnapshot getTaskSnapshot(Task task) {
if (!isScreenshotEnabled()) {
return false;
return null;
}
switch (backType) {
case BackNavigationInfo.TYPE_RETURN_TO_HOME:
case BackNavigationInfo.TYPE_DIALOG_CLOSE:
return false;
}
return true;
// Don't read from disk!!
return task.mRootWindowContainer.mWindowManager.mTaskSnapshotController.getSnapshot(
task.mTaskId, task.mUserId, false /* restoreFromDisk */,
false /* isLowResolution */);
}
void setWindowManager(WindowManagerService wm) {
mWindowManagerService = wm;
}
private void setLaunchBehind(ActivityRecord activity) {
if (activity == null) {
return;
}
if (!activity.isVisibleRequested()) {
activity.setVisibility(true);
}
activity.mLaunchTaskBehind = true;
// Handle fixed rotation launching app.
final DisplayContent dc = activity.mDisplayContent;
dc.rotateInDifferentOrientationIfNeeded(activity);
if (activity.hasFixedRotationTransform()) {
// Set the record so we can recognize it to continue to update display orientation
// if the previous activity becomes the top later.
dc.setFixedRotationLaunchingApp(activity,
activity.getWindowConfiguration().getRotation());
}
ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
"Setting Activity.mLauncherTaskBehind to true. Activity=%s", activity);
activity.mTaskSupervisor.mStoppingActivities.remove(activity);
activity.getDisplayContent().ensureActivitiesVisible(null /* starting */,
0 /* configChanges */, false /* preserveWindows */, true);
}
private void restoreLaunchBehind(ActivityRecord activity) {
if (activity == null) {
return;
}
activity.mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp();
// Restore the launch-behind state.
activity.mTaskSupervisor.scheduleLaunchTaskBehindComplete(activity.token);
activity.mLaunchTaskBehind = false;
ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
"Setting Activity.mLauncherTaskBehind to false. Activity=%s",
activity);
mAnimationHandler = new AnimationHandler(wm);
}
boolean isWallpaperVisible(WindowState w) {
return mAnimationTargets.mComposed && mShowWallpaper
return mAnimationHandler.mComposed && mShowWallpaper
&& w.mAttrs.type == TYPE_BASE_APPLICATION && w.mActivityRecord != null
&& mAnimationTargets.isTarget(w.mActivityRecord, true /* open */);
&& mAnimationHandler.isTarget(w.mActivityRecord, true /* open */);
}
// Called from WindowManagerService to write to a protocol buffer output stream.

View File

@@ -564,6 +564,11 @@ class SurfaceAnimator {
*/
public static final int ANIMATION_TYPE_STARTING_REVEAL = 1 << 7;
/**
* Animation when a back gesture animation is applied to a window container.
* @hide
*/
public static final int ANIMATION_TYPE_PREDICT_BACK = 1 << 8;
/**
* Bitmask to include all animation types. This is NOT an {@link AnimationType}
* @hide
@@ -583,7 +588,8 @@ class SurfaceAnimator {
ANIMATION_TYPE_WINDOW_ANIMATION,
ANIMATION_TYPE_INSETS_CONTROL,
ANIMATION_TYPE_TOKEN_TRANSFORM,
ANIMATION_TYPE_STARTING_REVEAL
ANIMATION_TYPE_STARTING_REVEAL,
ANIMATION_TYPE_PREDICT_BACK
})
@Retention(RetentionPolicy.SOURCE)
@interface AnimationType {}
@@ -602,6 +608,7 @@ class SurfaceAnimator {
case ANIMATION_TYPE_INSETS_CONTROL: return "insets_animation";
case ANIMATION_TYPE_TOKEN_TRANSFORM: return "token_transform";
case ANIMATION_TYPE_STARTING_REVEAL: return "starting_reveal";
case ANIMATION_TYPE_PREDICT_BACK: return "predict_back";
default: return "unknown type:" + type;
}
}

View File

@@ -722,6 +722,14 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
return true;
}
boolean isSupportWindowlessStartingSurface() {
// Enable after ag/20426257
final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast();
if (lastOrganizer == null) {
return false;
}
return false;
}
/**
* Notify the shell ({@link com.android.wm.shell.ShellTaskOrganizer} that the client has
* removed the splash screen view.

View File

@@ -34,7 +34,6 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
@@ -96,9 +95,7 @@ public class BackNavigationControllerTests extends WindowTestsBase {
.isEqualTo(typeToString(BackNavigationInfo.TYPE_RETURN_TO_HOME));
// verify if back animation would start.
verify(mBackNavigationController).scheduleAnimationLocked(
eq(BackNavigationInfo.TYPE_RETURN_TO_HOME), any(), eq(mBackAnimationAdapter),
any());
assertTrue("Animation scheduled", backNavigationInfo.isPrepareRemoteAnimation());
}
@Test
@@ -115,9 +112,7 @@ public class BackNavigationControllerTests extends WindowTestsBase {
.isEqualTo(typeToString(BackNavigationInfo.TYPE_CROSS_TASK));
// verify if back animation would start.
verify(mBackNavigationController).scheduleAnimationLocked(
eq(BackNavigationInfo.TYPE_CROSS_TASK), any(), eq(mBackAnimationAdapter),
any());
assertTrue("Animation scheduled", backNavigationInfo.isPrepareRemoteAnimation());
// reset drawning status
topTask.forAllWindows(w -> {