Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 27ad7ae6 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Use single snapshot when predictive back opens two adjacent activities" into main

parents 4eacef22 6a49b929
Loading
Loading
Loading
Loading
+155 −158
Original line number Diff line number Diff line
@@ -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,40 +1175,23 @@ 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);
@@ -1208,16 +1206,23 @@ class BackNavigationController {
                        .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);
                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());
                    }
                }
                return new RemoteAnimationTarget(represent.taskId, represent.mode, leashSurface,
                        represent.isTranslucent, represent.clipRect, represent.contentInsets,
@@ -1226,9 +1231,95 @@ class BackNavigationController {
                        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 {
                    return mAdaptors[0].mAnimationTarget;
                        // 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());
                    }
                    // 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;
            }
        }

@@ -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 {