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

Commit a6a5376e authored by Wei Sheng Shih's avatar Wei Sheng Shih Committed by Android (Google) Code Review
Browse files

Merge "Keep only one back animation playing." into udc-dev

parents 9ee9b97e 57721712
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -258,7 +258,7 @@ public class AppTransitionController {
            tmpCloseApps = new ArraySet<>(mDisplayContent.mClosingApps);
            if (mDisplayContent.mAtmService.mBackNavigationController
                    .removeIfContainsBackAnimationTargets(tmpOpenApps, tmpCloseApps)) {
                mDisplayContent.mAtmService.mBackNavigationController.clearBackAnimations(null);
                mDisplayContent.mAtmService.mBackNavigationController.clearBackAnimations();
            }
        }

+116 −101
Original line number Diff line number Diff line
@@ -62,13 +62,12 @@ import com.android.server.wm.utils.InsetUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Objects;
import java.util.function.Consumer;

/**
 * Controller to handle actions related to the back gesture on the server side.
 */
class BackNavigationController {
    private static final String TAG = "BackNavigationController";
    private static final String TAG = "CoreBackPreview";
    private WindowManagerService mWindowManagerService;
    private boolean mBackAnimationInProgress;
    private @BackNavigationInfo.BackTargetType int mLastBackType;
@@ -76,7 +75,13 @@ class BackNavigationController {
    private Runnable mPendingAnimation;
    private final NavigationMonitor mNavigationMonitor = new NavigationMonitor();

    AnimationHandler mAnimationHandler;
    private AnimationHandler mAnimationHandler;

    /**
     * The transition who match the back navigation targets,
     * release animation after this transition finish.
     */
    private Transition mWaitTransitionFinish;
    private final ArrayList<WindowContainer> mTmpOpenApps = new ArrayList<>();
    private final ArrayList<WindowContainer> mTmpCloseApps = new ArrayList<>();

@@ -140,6 +145,11 @@ class BackNavigationController {

        BackNavigationInfo.Builder infoBuilder = new BackNavigationInfo.Builder();
        synchronized (wmService.mGlobalLock) {
            if (isMonitoringTransition()) {
                Slog.w(TAG, "Previous animation hasn't finish, status: " + mAnimationHandler);
                // Don't start any animation for it.
                return null;
            }
            WindowManagerInternal windowManagerInternal =
                    LocalServices.getService(WindowManagerInternal.class);
            IBinder focusedWindowToken = windowManagerInternal.getFocusedWindowToken();
@@ -374,7 +384,7 @@ class BackNavigationController {
    }

    boolean isMonitoringTransition() {
        return isWaitBackTransition() || mNavigationMonitor.isMonitoring();
        return mAnimationHandler.mComposed || mNavigationMonitor.isMonitorForRemote();
    }

    private void scheduleAnimation(@NonNull AnimationHandler.ScheduleAnimationBuilder builder) {
@@ -477,7 +487,7 @@ class BackNavigationController {
        return false;
    }

    private static class NavigationMonitor {
    private class NavigationMonitor {
        // The window which triggering the back navigation.
        private WindowState mNavigatingWindow;
        private RemoteCallback mObserver;
@@ -487,15 +497,23 @@ class BackNavigationController {
            mObserver = observer;
        }

        void stopMonitor() {
            mNavigatingWindow = null;
        void stopMonitorForRemote() {
            mObserver = null;
        }

        boolean isMonitoring() {
        void stopMonitorTransition() {
            mNavigatingWindow = null;
        }

        boolean isMonitorForRemote() {
            return mNavigatingWindow != null && mObserver != null;
        }

        boolean isMonitorAnimationOrTransition() {
            return mNavigatingWindow != null
                    && (mAnimationHandler.mComposed || mAnimationHandler.mWaitTransition);
        }

        /**
         * Notify focus window changed during back navigation. This will cancel the gesture for
         * scenarios like: a system window popup, or when an activity add a new window.
@@ -506,7 +524,8 @@ class BackNavigationController {
         * a short time, but we should not cancel the navigation.
         */
        private void onFocusWindowChanged(WindowState newFocus) {
            if (!isMonitoring() || !atSameDisplay(newFocus)) {
            if (!atSameDisplay(newFocus)
                    || !(isMonitorForRemote() || isMonitorAnimationOrTransition())) {
                return;
            }
            // Keep navigating if either new focus == navigating window or null.
@@ -514,8 +533,14 @@ class BackNavigationController {
                    && (newFocus.mActivityRecord == null
                    || (newFocus.mActivityRecord == mNavigatingWindow.mActivityRecord))) {
                EventLogTags.writeWmBackNaviCanceled("focusWindowChanged");
                if (isMonitorForRemote()) {
                    mObserver.sendResult(null /* result */);
                }
                if (isMonitorAnimationOrTransition()) {
                    // transition won't happen, cancel internal status
                    clearBackAnimations();
                }
            }
        }

        /**
@@ -523,7 +548,7 @@ class BackNavigationController {
         */
        private void onTransitionReadyWhileNavigate(ArrayList<WindowContainer> opening,
                ArrayList<WindowContainer> closing) {
            if (!isMonitoring()) {
            if (!isMonitorForRemote() && !isMonitorAnimationOrTransition()) {
                return;
            }
            final ArrayList<WindowContainer> all = new ArrayList<>(opening);
@@ -531,7 +556,12 @@ class BackNavigationController {
            for (WindowContainer app : all) {
                if (app.hasChild(mNavigatingWindow)) {
                    EventLogTags.writeWmBackNaviCanceled("transitionHappens");
                    if (isMonitorForRemote()) {
                        mObserver.sendResult(null /* result */);
                    }
                    if (isMonitorAnimationOrTransition()) {
                        clearBackAnimations();
                    }
                    break;
                }
            }
@@ -539,6 +569,9 @@ class BackNavigationController {
        }

        private boolean atSameDisplay(WindowState newFocus) {
            if (mNavigatingWindow == null) {
                return false;
            }
            final int navigatingDisplayId = mNavigatingWindow.getDisplayId();
            return newFocus == null || newFocus.getDisplayId() == navigatingDisplayId;
        }
@@ -551,12 +584,10 @@ class BackNavigationController {
     * close target for a transition. So the condition here is
     * The closing target should only exist in close list, but the opening target can be either in
     * open or close list.
     *  @return {@code true} if the participants of this transition was animated by back gesture
     *  animations, and shouldn't join next transition.
     */
    boolean containsBackAnimationTargets(Transition transition) {
    void onTransactionReady(Transition transition) {
        if (!isMonitoringTransition()) {
            return false;
            return;
        }
        final ArraySet<WindowContainer> targets = transition.mParticipants;
        for (int i = targets.size() - 1; i >= 0; --i) {
@@ -576,33 +607,44 @@ class BackNavigationController {
                && mAnimationHandler.containsBackAnimationTargets(mTmpOpenApps, mTmpCloseApps);
        if (!matchAnimationTargets) {
            mNavigationMonitor.onTransitionReadyWhileNavigate(mTmpOpenApps, mTmpCloseApps);
        } else {
            if (mWaitTransitionFinish != null) {
                Slog.e(TAG, "Gesture animation is applied on another transition?");
            }
            mWaitTransitionFinish = transition;
        }
        mTmpOpenApps.clear();
        mTmpCloseApps.clear();
        return matchAnimationTargets;
    }

    boolean isMonitorTransitionTarget(WindowContainer wc) {
        if (!isWaitBackTransition()) {
        if (!isWaitBackTransition() || mWaitTransitionFinish == null) {
            return false;
        }
        return mAnimationHandler.isTarget(wc, wc.isVisibleRequested() /* open */);
    }

    /**
     * Cleanup animation, this can either happen when transition ready or finish.
     * @param cleanupTransaction The transaction which the caller want to apply the internal
     *                           cleanup together.
     * Cleanup animation, this can either happen when legacy transition ready, or when the Shell
     * transition finish.
     */
    void clearBackAnimations(SurfaceControl.Transaction cleanupTransaction) {
        mAnimationHandler.clearBackAnimateTarget(cleanupTransaction);
    void clearBackAnimations() {
        mAnimationHandler.clearBackAnimateTarget();
        mNavigationMonitor.stopMonitorTransition();
        mWaitTransitionFinish = null;
    }

    /**
     * Called when a transition finished.
     * Handle the pending animation when the running transition finished.
     * @param targets The final animation targets derived in transition.
     * @param finishedTransition The finished transition target.
    */
    boolean handleDeferredBackAnimation(@NonNull ArrayList<Transition.ChangeInfo> targets) {
    boolean onTransitionFinish(ArrayList<Transition.ChangeInfo> targets,
            @NonNull Transition finishedTransition) {
        if (finishedTransition == mWaitTransitionFinish) {
            clearBackAnimations();
        }
        if (!mBackAnimationInProgress || mPendingAnimationBuilder == null) {
            return false;
        }
@@ -660,7 +702,7 @@ class BackNavigationController {
        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.
@@ -669,6 +711,7 @@ class BackNavigationController {
        // request one during animating.
        private int mRequestedStartingSurfaceTaskId;
        private SurfaceControl mStartingSurface;
        private ActivityRecord mOpenActivity;

        AnimationHandler(WindowManagerService wms) {
            mWindowManagerService = wms;
@@ -697,7 +740,8 @@ class BackNavigationController {
            return true;
        }

        private void initiate(WindowContainer close, WindowContainer open)  {
        private void initiate(WindowContainer close, WindowContainer open,
                ActivityRecord openActivity)  {
            WindowContainer closeTarget;
            if (isActivitySwitch(close, open)) {
                mSwitchType = ACTIVITY_SWITCH;
@@ -712,22 +756,26 @@ class BackNavigationController {

            mCloseAdaptor = createAdaptor(closeTarget, false /* isOpen */);
            mOpenAdaptor = createAdaptor(open, true /* isOpen */);

            mOpenActivity = openActivity;
            if (mCloseAdaptor.mAnimationTarget == null || mOpenAdaptor.mAnimationTarget == null) {
                Slog.w(TAG, "composeNewAnimations fail, skip");
                clearBackAnimateTarget(null /* cleanupTransaction */);
                clearBackAnimateTarget();
            }
        }

        private boolean composeAnimations(@NonNull WindowContainer close,
                @NonNull WindowContainer open) {
            clearBackAnimateTarget(null /* cleanupTransaction */);
            if (close == null || open == null) {
        boolean composeAnimations(@NonNull WindowContainer close, @NonNull WindowContainer open,
                ActivityRecord openActivity) {
            if (mComposed || mWaitTransition) {
                Slog.e(TAG, "Previous animation is running " + this);
                return false;
            }
            clearBackAnimateTarget();
            if (close == null || open == null || openActivity == null) {
                Slog.e(TAG, "reset animation with null target close: "
                        + close + " open: " + open);
                return false;
            }
            initiate(close, open);
            initiate(close, open, openActivity);
            if (mSwitchType == UNKNOWN) {
                return false;
            }
@@ -791,24 +839,10 @@ class BackNavigationController {
            return false;
        }

        boolean setFinishTransaction(SurfaceControl.Transaction finishTransaction) {
            if (!mComposed) {
                return false;
            }
            mFinishedTransaction = finishTransaction;
            return true;
        }

        void finishPresentAnimations(SurfaceControl.Transaction t) {
        void finishPresentAnimations() {
            if (!mComposed) {
                return;
            }
            final SurfaceControl.Transaction pt = t != null ? t
                    : mOpenAdaptor.mTarget.getPendingTransaction();
            if (mFinishedTransaction != null) {
                pt.merge(mFinishedTransaction);
                mFinishedTransaction = null;
            }
            cleanUpWindowlessSurface();

            if (mCloseAdaptor != null) {
@@ -819,6 +853,9 @@ class BackNavigationController {
                mOpenAdaptor.mTarget.cancelAnimation();
                mOpenAdaptor = null;
            }
            if (mOpenActivity != null && mOpenActivity.mLaunchTaskBehind) {
                restoreLaunchBehind(mOpenActivity);
            }
        }

        private void cleanUpWindowlessSurface() {
@@ -845,22 +882,14 @@ class BackNavigationController {
            }
        }

        void clearBackAnimateTarget(SurfaceControl.Transaction cleanupTransaction) {
            finishPresentAnimations(cleanupTransaction);
        void clearBackAnimateTarget() {
            finishPresentAnimations();
            mComposed = false;
            mWaitTransition = false;
            mOpenTransitionTargetMatch = false;
            mRequestedStartingSurfaceTaskId = 0;
            mSwitchType = UNKNOWN;
            if (mFinishedTransaction != null) {
                Slog.w(TAG, "Clear back animation, found un-processed finished transaction");
                if (cleanupTransaction != null) {
                    cleanupTransaction.merge(mFinishedTransaction);
                } else {
                    mFinishedTransaction.apply();
                }
                mFinishedTransaction = null;
            }
            mOpenActivity = null;
        }

        // The close target must in close list
@@ -876,9 +905,9 @@ class BackNavigationController {
        public String toString() {
            return "AnimationTargets{"
                    + " openTarget= "
                    + mOpenAdaptor.mTarget
                    + (mOpenAdaptor != null ? mOpenAdaptor.mTarget : "null")
                    + " closeTarget= "
                    + mCloseAdaptor.mTarget
                    + (mCloseAdaptor != null ? mCloseAdaptor.mTarget : "null")
                    + " mSwitchType= "
                    + mSwitchType
                    + " mComposed= "
@@ -1048,14 +1077,13 @@ class BackNavigationController {
             * @return If the preview strategy is launch behind, returns the Activity that has
             *         launchBehind set, or null otherwise.
             */
            private ActivityRecord applyPreviewStrategy(WindowContainer open,
            private void applyPreviewStrategy(WindowContainer open,
                    ActivityRecord visibleOpenActivity) {
                if (isSupportWindowlessSurface() && mShowWindowlessSurface && !mIsLaunchBehind) {
                    createStartingSurface(getSnapshot(open));
                    return null;
                    return;
                }
                setLaunchBehind(visibleOpenActivity);
                return visibleOpenActivity;
            }

            Runnable build() {
@@ -1071,19 +1099,12 @@ class BackNavigationController {
                    return null;
                }

                if (!composeAnimations(mCloseTarget, mOpenTarget)) {
                if (!composeAnimations(mCloseTarget, mOpenTarget, openActivity)) {
                    return null;
                }
                final ActivityRecord launchBehindActivity =
                applyPreviewStrategy(mOpenTarget, openActivity);

                final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback(
                        launchBehindActivity != null ? triggerBack -> {
                            if (!triggerBack) {
                                restoreLaunchBehind(launchBehindActivity);
                            }
                        } : null,
                        mCloseTarget);
                final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback();
                final RemoteAnimationTarget[] targets = getAnimationTargets();

                return () -> {
@@ -1096,31 +1117,17 @@ class BackNavigationController {
                };
            }

            private IBackAnimationFinishedCallback makeAnimationFinishedCallback(
                    Consumer<Boolean> b, WindowContainer closeTarget) {
            private IBackAnimationFinishedCallback makeAnimationFinishedCallback() {
                return new IBackAnimationFinishedCallback.Stub() {
                    @Override
                    public void onAnimationFinished(boolean triggerBack) {
                        final SurfaceControl.Transaction finishedTransaction =
                                new SurfaceControl.Transaction();
                        synchronized (mWindowManagerService.mGlobalLock) {
                            if (b != null) {
                                b.accept(triggerBack);
                            }
                            if (triggerBack) {
                                final SurfaceControl surfaceControl =
                                        closeTarget.getSurfaceControl();
                                if (surfaceControl != null && surfaceControl.isValid()) {
                                    // Hide the close target surface when transition start.
                                    finishedTransaction.hide(surfaceControl);
                                }
                            }
                            if (!setFinishTransaction(finishedTransaction)) {
                                finishedTransaction.apply();
                            if (!mComposed) {
                                // animation was canceled
                                return;
                            }
                            if (!triggerBack) {
                                clearBackAnimateTarget(
                                        null /* cleanupTransaction */);
                                clearBackAnimateTarget();
                            } else {
                                mWaitTransition = true;
                            }
@@ -1180,6 +1187,14 @@ class BackNavigationController {
    }

    void startAnimation() {
        if (!mBackAnimationInProgress) {
            // gesture is already finished, do not start animation
            if (mPendingAnimation != null) {
                clearBackAnimations();
                mPendingAnimation = null;
            }
            return;
        }
        if (mPendingAnimation != null) {
            mPendingAnimation.run();
            mPendingAnimation = null;
@@ -1192,7 +1207,7 @@ class BackNavigationController {
        ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, "
                + "triggerBack=%b", backType, triggerBack);

        mNavigationMonitor.stopMonitor();
        mNavigationMonitor.stopMonitorForRemote();
        mBackAnimationInProgress = false;
        mShowWallpaper = false;
        mPendingAnimationBuilder = null;
+2 −6
Original line number Diff line number Diff line
@@ -1031,7 +1031,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
        mTmpTransaction.apply();

        // Handle back animation if it's already started.
        mController.mAtm.mBackNavigationController.handleDeferredBackAnimation(mTargets);
        mController.mAtm.mBackNavigationController.onTransitionFinish(mTargets, this);
        mController.mFinishingTransition = null;
    }

@@ -1136,8 +1136,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
            mFlags |= TRANSIT_FLAG_KEYGUARD_LOCKED;
        }
        // Check whether the participants were animated from back navigation.
        final boolean markBackAnimated = mController.mAtm.mBackNavigationController
                .containsBackAnimationTargets(this);
        mController.mAtm.mBackNavigationController.onTransactionReady(this);
        // Resolve the animating targets from the participants.
        mTargets = calculateTargets(mParticipants, mChanges);
        final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, transaction);
@@ -1150,9 +1149,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
            mTargetDisplays.add(dc);
        }

        if (markBackAnimated) {
            mController.mAtm.mBackNavigationController.clearBackAnimations(mStartTransaction);
        }
        if (mOverrideOptions != null) {
            info.setAnimationOptions(mOverrideOptions);
            if (mOverrideOptions.getType() == ANIM_OPEN_CROSS_PROFILE_APPS) {
+15 −3
Original line number Diff line number Diff line
@@ -89,11 +89,12 @@ public class BackNavigationControllerTests extends WindowTestsBase {

    @Before
    public void setUp() throws Exception {
        mBackNavigationController = Mockito.spy(new BackNavigationController());
        final BackNavigationController original = new BackNavigationController();
        original.setWindowManager(mWm);
        mBackNavigationController = Mockito.spy(original);
        LocalServices.removeServiceForTest(WindowManagerInternal.class);
        mWindowManagerInternal = mock(WindowManagerInternal.class);
        LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);
        mBackNavigationController.setWindowManager(mWm);
        mBackAnimationAdapter = mock(BackAnimationAdapter.class);
        mRootHomeTask = initHomeActivity();
    }
@@ -129,7 +130,9 @@ public class BackNavigationControllerTests extends WindowTestsBase {
        // verify if back animation would start.
        assertTrue("Animation scheduled", backNavigationInfo.isPrepareRemoteAnimation());

        // reset drawning status
        // reset drawing status
        backNavigationInfo.onBackNavigationFinished(false);
        mBackNavigationController.clearBackAnimations();
        topTask.forAllWindows(w -> {
            makeWindowVisibleAndDrawn(w);
        }, true);
@@ -138,6 +141,8 @@ public class BackNavigationControllerTests extends WindowTestsBase {
        assertThat(typeToString(backNavigationInfo.getType()))
                .isEqualTo(typeToString(BackNavigationInfo.TYPE_CALLBACK));

        backNavigationInfo.onBackNavigationFinished(false);
        mBackNavigationController.clearBackAnimations();
        doReturn(true).when(recordA).canShowWhenLocked();
        backNavigationInfo = startBackNavigation();
        assertThat(typeToString(backNavigationInfo.getType()))
@@ -194,6 +199,8 @@ public class BackNavigationControllerTests extends WindowTestsBase {
        assertTrue("Animation scheduled", backNavigationInfo.isPrepareRemoteAnimation());

        // reset drawing status
        backNavigationInfo.onBackNavigationFinished(false);
        mBackNavigationController.clearBackAnimations();
        testCase.recordFront.forAllWindows(w -> {
            makeWindowVisibleAndDrawn(w);
        }, true);
@@ -202,6 +209,8 @@ public class BackNavigationControllerTests extends WindowTestsBase {
        assertThat(typeToString(backNavigationInfo.getType()))
                .isEqualTo(typeToString(BackNavigationInfo.TYPE_CALLBACK));

        backNavigationInfo.onBackNavigationFinished(false);
        mBackNavigationController.clearBackAnimations();
        doReturn(true).when(testCase.recordBack).canShowWhenLocked();
        backNavigationInfo = startBackNavigation();
        assertThat(typeToString(backNavigationInfo.getType()))
@@ -240,6 +249,8 @@ public class BackNavigationControllerTests extends WindowTestsBase {
        assertThat(typeToString(backNavigationInfo.getType()))
                .isEqualTo(typeToString(BackNavigationInfo.TYPE_RETURN_TO_HOME));

        backNavigationInfo.onBackNavigationFinished(false);
        mBackNavigationController.clearBackAnimations();
        setupKeyguardOccluded();
        backNavigationInfo = startBackNavigation();
        assertThat(typeToString(backNavigationInfo.getType()))
@@ -553,6 +564,7 @@ public class BackNavigationControllerTests extends WindowTestsBase {
        assertTrue(toHomeBuilder.mIsLaunchBehind);
        toHomeBuilder.build();
        verify(animationHandler, never()).createStartingSurface(any());
        animationHandler.clearBackAnimateTarget();

        // Back to ACTIVITY and TASK have the same logic, just with different target.
        final ActivityRecord topActivity = createActivityRecord(task);