summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java313
1 files changed, 155 insertions, 158 deletions
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index c2dfa21016fa..38ee4564396e 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -629,7 +629,7 @@ class BackNavigationController {
final ActivityRecord ar = openApps.valueAt(i);
if (mAnimationHandler.isTarget(ar, true /* open */)) {
openApps.removeAt(i);
- mAnimationHandler.markStartingSurfaceMatch();
+ mAnimationHandler.markStartingSurfaceMatch(null /* reparentTransaction */);
}
}
for (int i = closeApps.size() - 1; i >= 0; --i) {
@@ -773,10 +773,15 @@ class BackNavigationController {
for (int i = mTmpOpenApps.size() - 1; i >= 0; --i) {
final WindowContainer wc = mTmpOpenApps.get(i);
if (mAnimationHandler.isTarget(wc, true /* open */)) {
- mAnimationHandler.markStartingSurfaceMatch();
+ mAnimationHandler.markStartingSurfaceMatch(startTransaction);
break;
}
}
+ // release animation leash
+ if (mAnimationHandler.mOpenAnimAdaptor.mCloseTransaction != null) {
+ startTransaction.merge(mAnimationHandler.mOpenAnimAdaptor.mCloseTransaction);
+ mAnimationHandler.mOpenAnimAdaptor.mCloseTransaction = null;
+ }
// Because the target will reparent to transition root, so it cannot be controlled by
// animation leash. Hide the close target when transition starts.
startTransaction.hide(mAnimationHandler.mCloseAdaptor.mTarget.getSurfaceControl());
@@ -993,7 +998,7 @@ class BackNavigationController {
}
final RemoteAnimationTarget[] targets = new RemoteAnimationTarget[2];
targets[0] = mCloseAdaptor.mAnimationTarget;
- targets[1] = mOpenAnimAdaptor.getOrCreateAnimationTarget();
+ targets[1] = mOpenAnimAdaptor.mRemoteAnimationTarget;
return targets;
}
@@ -1067,11 +1072,12 @@ class BackNavigationController {
}
}
- void markStartingSurfaceMatch() {
- mStartingSurfaceTargetMatch = true;
- for (int i = mOpenAnimAdaptor.mAdaptors.length - 1; i >= 0; --i) {
- mOpenAnimAdaptor.mAdaptors[i].reparentWindowlessSurfaceToTarget();
+ void markStartingSurfaceMatch(SurfaceControl.Transaction reparentTransaction) {
+ if (mStartingSurfaceTargetMatch) {
+ return;
}
+ mStartingSurfaceTargetMatch = true;
+ mOpenAnimAdaptor.reparentWindowlessSurfaceToTarget(reparentTransaction);
}
void clearBackAnimateTarget() {
@@ -1140,14 +1146,23 @@ class BackNavigationController {
private static class BackWindowAnimationAdaptorWrapper {
final BackWindowAnimationAdaptor[] mAdaptors;
+ // The highest remote animation target, which can be a wrapper if multiple adaptors,
+ // or the single opening target.
+ final RemoteAnimationTarget mRemoteAnimationTarget;
SurfaceControl.Transaction mCloseTransaction;
+ // The starting surface task Id. Used to clear the starting surface if the animation has
+ // requested one during animating.
+ private int mRequestedStartingSurfaceId = INVALID_TASK_ID;
+ private SurfaceControl mStartingSurface;
BackWindowAnimationAdaptorWrapper(boolean isOpen, int switchType,
@NonNull WindowContainer... targets) {
mAdaptors = new BackWindowAnimationAdaptor[targets.length];
for (int i = targets.length - 1; i >= 0; --i) {
mAdaptors[i] = createAdaptor(targets[i], isOpen, switchType);
}
+ mRemoteAnimationTarget = targets.length > 1 ? createWrapTarget()
+ : mAdaptors[0].mAnimationTarget;
}
boolean isValid() {
@@ -1160,76 +1175,152 @@ class BackNavigationController {
}
void cleanUp(boolean startingSurfaceMatch) {
+ cleanUpWindowlessSurface(startingSurfaceMatch);
for (int i = mAdaptors.length - 1; i >= 0; --i) {
- mAdaptors[i].cleanUpWindowlessSurface(startingSurfaceMatch);
mAdaptors[i].mTarget.cancelAnimation();
}
+ mRequestedStartingSurfaceId = INVALID_TASK_ID;
+ mStartingSurface = null;
if (mCloseTransaction != null) {
mCloseTransaction.apply();
mCloseTransaction = null;
}
}
- void onAnimationFinish() {
- final SurfaceControl.Transaction pt = mAdaptors[0].mTarget.getPendingTransaction();
- if (mCloseTransaction != null) {
- pt.merge(mCloseTransaction);
- mCloseTransaction = null;
- }
- if (mAdaptors.length > 1) {
- for (int i = mAdaptors.length - 1; i >= 0; --i) {
- final WindowContainer wc = mAdaptors[i].mTarget;
- final WindowContainer parent = wc.getParent();
- if (parent != null) {
- pt.reparent(wc.getSurfaceControl(),
- parent.getSurfaceControl());
- }
- }
- }
- }
-
- @NonNull RemoteAnimationTarget getOrCreateAnimationTarget() {
+ private RemoteAnimationTarget createWrapTarget() {
// Special handle for opening two activities together.
// If we animate both activities separately, the animation area and rounded corner
// would also being handled separately. To make them seem like "open" together, wrap
// their leash with another animation leash.
- if (mAdaptors.length > 1 && mCloseTransaction == null) {
- final Rect unionBounds = new Rect();
- for (int i = mAdaptors.length - 1; i >= 0; --i) {
- unionBounds.union(mAdaptors[i].mAnimationTarget.localBounds);
+ final Rect unionBounds = new Rect();
+ for (int i = mAdaptors.length - 1; i >= 0; --i) {
+ unionBounds.union(mAdaptors[i].mAnimationTarget.localBounds);
+ }
+ final WindowContainer wc = mAdaptors[0].mTarget;
+ final Task task = wc.asActivityRecord() != null
+ ? wc.asActivityRecord().getTask() : wc.asTask();
+ final RemoteAnimationTarget represent = mAdaptors[0].mAnimationTarget;
+ final SurfaceControl leashSurface = new SurfaceControl.Builder()
+ .setName("cross-animation-leash")
+ .setContainerLayer()
+ .setHidden(false)
+ .setParent(task.getSurfaceControl())
+ .build();
+ mCloseTransaction = new SurfaceControl.Transaction();
+ mCloseTransaction.reparent(leashSurface, null);
+ final SurfaceControl.Transaction pt = wc.getPendingTransaction();
+ pt.setLayer(leashSurface, wc.getParent().getLastLayer());
+ for (int i = mAdaptors.length - 1; i >= 0; --i) {
+ BackWindowAnimationAdaptor adaptor = mAdaptors[i];
+ pt.reparent(adaptor.mAnimationTarget.leash, leashSurface);
+ pt.setPosition(adaptor.mAnimationTarget.leash,
+ adaptor.mAnimationTarget.localBounds.left,
+ adaptor.mAnimationTarget.localBounds.top);
+ // For adjacent activity embedded, reparent Activity to TaskFragment when
+ // animation finish
+ final WindowContainer parent = adaptor.mTarget.getParent();
+ if (parent != null) {
+ mCloseTransaction.reparent(adaptor.mTarget.getSurfaceControl(),
+ parent.getSurfaceControl());
}
- final WindowContainer wc = mAdaptors[0].mTarget;
- final Task task = wc.asActivityRecord() != null
- ? wc.asActivityRecord().getTask() : wc.asTask();
- final RemoteAnimationTarget represent = mAdaptors[0].mAnimationTarget;
- final SurfaceControl leashSurface = new SurfaceControl.Builder()
- .setName("cross-animation-leash")
- .setContainerLayer()
- .setHidden(false)
- .setParent(task.getSurfaceControl())
- .build();
- final SurfaceControl.Transaction pt = wc.getPendingTransaction();
- pt.setLayer(leashSurface, wc.getParent().getLastLayer());
- mCloseTransaction = new SurfaceControl.Transaction();
- mCloseTransaction.reparent(leashSurface, null);
- for (int i = mAdaptors.length - 1; i >= 0; --i) {
- BackWindowAnimationAdaptor adaptor = mAdaptors[i];
- pt.reparent(adaptor.mAnimationTarget.leash, leashSurface);
- pt.setPosition(adaptor.mAnimationTarget.leash,
- adaptor.mAnimationTarget.localBounds.left,
- adaptor.mAnimationTarget.localBounds.top);
+ }
+ return new RemoteAnimationTarget(represent.taskId, represent.mode, leashSurface,
+ represent.isTranslucent, represent.clipRect, represent.contentInsets,
+ represent.prefixOrderIndex,
+ new Point(unionBounds.left, unionBounds.top),
+ unionBounds, unionBounds, represent.windowConfiguration,
+ true /* isNotInRecents */, null, null, represent.taskInfo,
+ represent.allowEnterPip);
+ }
+
+ void createStartingSurface(@NonNull WindowContainer closeWindow,
+ ActivityRecord[] visibleOpenActivities) {
+ if (mAdaptors[0].mSwitchType == DIALOG_CLOSE) {
+ return;
+ }
+ final WindowContainer mainOpen = mAdaptors[0].mTarget;
+ final int switchType = mAdaptors[0].mSwitchType;
+ final Task openTask = switchType == TASK_SWITCH
+ ? mainOpen.asTask() : switchType == ACTIVITY_SWITCH
+ ? mainOpen.asActivityRecord().getTask() : null;
+ if (openTask == null) {
+ return;
+ }
+ final ActivityRecord mainActivity = switchType == ACTIVITY_SWITCH
+ ? mainOpen.asActivityRecord()
+ : openTask.getTopNonFinishingActivity();
+ if (mainActivity == null) {
+ return;
+ }
+ final TaskSnapshot snapshot = getSnapshot(mainOpen, visibleOpenActivities);
+ mRequestedStartingSurfaceId = openTask.mAtmService.mTaskOrganizerController
+ .addWindowlessStartingSurface(openTask, mainActivity,
+ // Choose configuration from closeWindow, because the configuration
+ // of opening target may not update before resume, so the starting
+ // surface should occlude it entirely.
+ mRemoteAnimationTarget.leash, snapshot, closeWindow.getConfiguration(),
+ new IWindowlessStartingSurfaceCallback.Stub() {
+ // Once the starting surface has been created in shell, it will call
+ // onSurfaceAdded to pass the created surface to core, so if a
+ // transition is triggered by the back gesture, there doesn't need to
+ // create another starting surface for the opening target, just reparent
+ // the starting surface to the opening target.
+ // Note if cleanUpWindowlessSurface happen prior than onSurfaceAdded
+ // called, there won't be able to reparent the starting surface on
+ // opening target. But if that happens and transition target is matched,
+ // the app window should already draw.
+ @Override
+ public void onSurfaceAdded(SurfaceControl sc) {
+ synchronized (openTask.mWmService.mGlobalLock) {
+ if (mRequestedStartingSurfaceId != INVALID_TASK_ID) {
+ mStartingSurface = sc;
+ }
+ }
+ }
+ });
+ }
+
+ // When back gesture has triggered and transition target matches navigation target,
+ // reparent the starting surface to the opening target as it's starting window.
+ void reparentWindowlessSurfaceToTarget(SurfaceControl.Transaction reparentTransaction) {
+ if (mRequestedStartingSurfaceId == INVALID_TASK_ID) {
+ return;
+ }
+ // If open target matches, reparent to open activity or task
+ if (mStartingSurface != null && mStartingSurface.isValid()) {
+ SurfaceControl.Transaction transaction = reparentTransaction != null
+ ? reparentTransaction : mAdaptors[0].mTarget.getPendingTransaction();
+ if (mAdaptors.length == 1) {
+ transaction.reparent(mStartingSurface,
+ mAdaptors[0].mTarget.getSurfaceControl());
+ } else {
+ // More than one opening window, reparent starting surface to leaf task.
+ final WindowContainer wc = mAdaptors[0].mTarget;
+ final Task task = wc.asActivityRecord() != null
+ ? wc.asActivityRecord().getTask() : wc.asTask();
+ transaction.reparent(mStartingSurface, task != null
+ ? task.getSurfaceControl()
+ : mAdaptors[0].mTarget.getSurfaceControl());
}
- return new RemoteAnimationTarget(represent.taskId, represent.mode, leashSurface,
- represent.isTranslucent, represent.clipRect, represent.contentInsets,
- represent.prefixOrderIndex,
- new Point(unionBounds.left, unionBounds.top),
- unionBounds, unionBounds, represent.windowConfiguration,
- true /* isNotInRecents */, null, null, represent.taskInfo,
- represent.allowEnterPip);
- } else {
- return mAdaptors[0].mAnimationTarget;
+ // remove starting surface.
+ mStartingSurface = null;
}
}
+
+ /**
+ * Ask shell to clear the starting surface.
+ * @param openTransitionMatch if true, shell will play the remove starting window
+ * animation, otherwise remove it directly.
+ */
+ void cleanUpWindowlessSurface(boolean openTransitionMatch) {
+ if (mRequestedStartingSurfaceId == INVALID_TASK_ID) {
+ return;
+ }
+ mAdaptors[0].mTarget.mWmService.mAtmService.mTaskOrganizerController
+ .removeWindowlessStartingSurface(mRequestedStartingSurfaceId,
+ !openTransitionMatch);
+ mRequestedStartingSurfaceId = INVALID_TASK_ID;
+ }
}
private static class BackWindowAnimationAdaptor implements AnimationAdapter {
@@ -1240,11 +1331,6 @@ class BackNavigationController {
private RemoteAnimationTarget mAnimationTarget;
private final int mSwitchType;
- // The starting surface task Id. Used to clear the starting surface if the animation has
- // requested one during animating.
- private int mRequestedStartingSurfaceId = INVALID_TASK_ID;
- private SurfaceControl mStartingSurface;
-
BackWindowAnimationAdaptor(@NonNull WindowContainer target, boolean isOpen,
int switchType) {
mBounds.set(target.getBounds());
@@ -1276,8 +1362,6 @@ class BackNavigationController {
public void onAnimationCancelled(SurfaceControl animationLeash) {
if (mCapturedLeash == animationLeash) {
mCapturedLeash = null;
- mRequestedStartingSurfaceId = INVALID_TASK_ID;
- mStartingSurface = null;
}
}
@@ -1345,84 +1429,6 @@ class BackNavigationController {
r.checkEnterPictureInPictureAppOpsState());
return mAnimationTarget;
}
-
- void createStartingSurface(@NonNull WindowContainer closeWindow,
- @NonNull ActivityRecord[] visibleOpenActivities) {
- if (!mIsOpen) {
- return;
- }
- if (mSwitchType == DIALOG_CLOSE) {
- return;
- }
- final Task openTask = mSwitchType == TASK_SWITCH
- ? mTarget.asTask() : mSwitchType == ACTIVITY_SWITCH
- ? mTarget.asActivityRecord().getTask() : null;
- if (openTask == null) {
- return;
- }
- final ActivityRecord mainActivity = mSwitchType == ACTIVITY_SWITCH
- ? mTarget.asActivityRecord()
- : openTask.getTopNonFinishingActivity();
- if (mainActivity == null) {
- return;
- }
- final TaskSnapshot snapshot = getSnapshot(mTarget, visibleOpenActivities);
- mRequestedStartingSurfaceId = openTask.mAtmService.mTaskOrganizerController
- .addWindowlessStartingSurface(openTask, mainActivity,
- // Choose configuration from closeWindow, because the configuration
- // of opening target may not update before resume, so the starting
- // surface should occlude it entirely.
- mAnimationTarget.leash, snapshot, closeWindow.getConfiguration(),
- new IWindowlessStartingSurfaceCallback.Stub() {
- // Once the starting surface has been created in shell, it will call
- // onSurfaceAdded to pass the created surface to core, so if a
- // transition is triggered by the back gesture, there doesn't need to
- // create another starting surface for the opening target, just reparent
- // the starting surface to the opening target.
- // Note if cleanUpWindowlessSurface happen prior than onSurfaceAdded
- // called, there won't be able to reparent the starting surface on
- // opening target. But if that happens and transition target is matched,
- // the app window should already draw.
- @Override
- public void onSurfaceAdded(SurfaceControl sc) {
- synchronized (mTarget.mWmService.mGlobalLock) {
- if (mRequestedStartingSurfaceId != INVALID_TASK_ID) {
- mStartingSurface = sc;
- }
- }
- }
- });
- }
-
- // When back gesture has triggered and transition target matches navigation target,
- // reparent the starting surface to the opening target as it's starting window.
- void reparentWindowlessSurfaceToTarget() {
- if (mRequestedStartingSurfaceId == INVALID_TASK_ID) {
- return;
- }
- // If open target matches, reparent to open activity or task
- if (mStartingSurface != null && mStartingSurface.isValid()) {
- mTarget.getPendingTransaction()
- .reparent(mStartingSurface, mTarget.getSurfaceControl());
- // remove starting surface.
- mStartingSurface = null;
- }
- }
-
- /**
- * Ask shell to clear the starting surface.
- * @param openTransitionMatch if true, shell will play the remove starting window
- * animation, otherwise remove it directly.
- */
- void cleanUpWindowlessSurface(boolean openTransitionMatch) {
- if (mRequestedStartingSurfaceId == INVALID_TASK_ID) {
- return;
- }
- mTarget.mWmService.mAtmService.mTaskOrganizerController
- .removeWindowlessStartingSurface(mRequestedStartingSurfaceId,
- !openTransitionMatch);
- mRequestedStartingSurfaceId = INVALID_TASK_ID;
- }
}
ScheduleAnimationBuilder prepareAnimation(
@@ -1499,18 +1505,10 @@ class BackNavigationController {
* @param visibleOpenActivities The visible activities in opening targets.
*/
private void applyPreviewStrategy(@NonNull WindowContainer closeWindow,
- @NonNull BackWindowAnimationAdaptor[] openAnimationAdaptor,
+ @NonNull BackWindowAnimationAdaptorWrapper openAnimationAdaptor,
@NonNull ActivityRecord[] visibleOpenActivities) {
- if (isSupportWindowlessSurface() && mShowWindowlessSurface && !mIsLaunchBehind
- // TODO (b/274997067) Draw two snapshot in a single starting surface.
- // We are using TaskId as the key of
- // StartingSurfaceDrawer#StartingWindowRecordManager, so we cannot create
- // two activity snapshot with WindowlessStartingWindow.
- // Try to draw two snapshot within a WindowlessStartingWindow, or find
- // another key for StartingWindowRecordManager.
- && openAnimationAdaptor.length == 1) {
- openAnimationAdaptor[0].createStartingSurface(closeWindow,
- visibleOpenActivities);
+ if (isSupportWindowlessSurface() && mShowWindowlessSurface && !mIsLaunchBehind) {
+ openAnimationAdaptor.createStartingSurface(closeWindow, visibleOpenActivities);
} else {
for (int i = visibleOpenActivities.length - 1; i >= 0; --i) {
setLaunchBehind(visibleOpenActivities[i]);
@@ -1541,7 +1539,7 @@ class BackNavigationController {
}
mCloseTarget.mTransitionController.mSnapshotController
.mActivitySnapshotController.clearOnBackPressedActivities();
- applyPreviewStrategy(mCloseTarget, mOpenAnimAdaptor.mAdaptors, openingActivities);
+ applyPreviewStrategy(mCloseTarget, mOpenAnimAdaptor, openingActivities);
final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback();
final RemoteAnimationTarget[] targets = getAnimationTargets();
@@ -1565,7 +1563,6 @@ class BackNavigationController {
// animation was canceled
return;
}
- mOpenAnimAdaptor.onAnimationFinish();
if (!triggerBack) {
clearBackAnimateTarget();
} else {