diff options
| -rw-r--r-- | services/core/java/com/android/server/wm/BackNavigationController.java | 313 |
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 { |