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

Commit 95d39939 authored by wilsonshih's avatar wilsonshih
Browse files

Allow a back gesture to interrupt a transition.

This change allows a new back gesture to start without waiting for the
previous transition to finish. If the back gesture has not finished
after the previous transition completes, attempt to start the back
navigation again.

Flag: com.android.window.flags.predictive_back_intercept_transition
Bug: 426448018
Test: atest BackAnimationControllerTest BackNavigationControllerTests
Change-Id: Ice87d6d7353d537d1943d92125ef82c8e8d8d9ff
parent 6e7524b3
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -73,6 +73,13 @@ public final class BackNavigationInfo implements Parcelable {
     */
    public static final int TYPE_CALLBACK = 4;

    /**
     * A {@link OnBackInvokedCallback} is not available due to a transition is happening.
     * <p>
     * @hide
     */
    public static final int TYPE_IN_TRANSITION = 5;

    /**
     * Key to access the boolean value passed in {#mOnBackNavigationDone} result bundle
     * that represents if back navigation has been triggered.
@@ -106,7 +113,8 @@ public final class BackNavigationInfo implements Parcelable {
            TYPE_RETURN_TO_HOME,
            TYPE_CROSS_ACTIVITY,
            TYPE_CROSS_TASK,
            TYPE_CALLBACK
            TYPE_CALLBACK,
            TYPE_IN_TRANSITION
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface BackTargetType {
@@ -339,6 +347,8 @@ public final class BackNavigationInfo implements Parcelable {
                return "TYPE_CROSS_TASK";
            case TYPE_CALLBACK:
                return "TYPE_CALLBACK";
            case TYPE_IN_TRANSITION:
                return "TYPE_IN_TRANSITION";
        }
        return String.valueOf(type);
    }
+10 −0
Original line number Diff line number Diff line
@@ -417,6 +417,16 @@ flag {
    }
}

flag {
    name: "predictive_back_intercept_transition"
    namespace: "windowing_frontend"
    description: "Allows back gesture to intercept a running transition."
    bug: "426448018"
    metadata {
      purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "current_animator_scale_uses_shared_memory"
    namespace: "wear_system_health"
+48 −17
Original line number Diff line number Diff line
@@ -159,6 +159,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
     * (and navigation) associated with {@link #mCurrentTracker} have not yet finished.
     */
    private BackTouchTracker mQueuedTracker = new BackTouchTracker();
    private final TransitionIdleRunner mTransitionIdleRunner = new TransitionIdleRunner();

    private final BackTransitionObserver mBackTransitionObserver =
            new BackTransitionObserver();
@@ -470,9 +471,17 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
            tryPilferPointers();
        }

        if (predictiveBackDelayWmTransition()) {
        startPredictiveBackAnimationIfNeeded();
    }

    private void startPredictiveBackAnimationIfNeeded() {
        if (!predictiveBackDelayWmTransition() || !mThresholdCrossed) {
            return;
        }
        mShellExecutor.execute(() -> {
                if (shouldDispatchToAnimator()) {
            if (!shouldDispatchToAnimator()) {
                return;
            }
            try {
                mActivityTaskManager.startPredictiveBackAnimation();
            } catch (RemoteException r) {
@@ -485,10 +494,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
                mActiveCallback = null;
            }
            requestTopUi(true, backType);
                }
        });
    }
    }

    private boolean isAppProgressGenerationAllowed() {
        return mBackNavigationInfo.isAppProgressGenerationAllowed()
@@ -624,6 +631,22 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
        }
    }

    private class TransitionIdleRunner implements Runnable {
        boolean mIsEnable;

        @Override
        public void run() {
            if (!mIsEnable || !mCurrentTracker.isActive()) {
                return;
            }
            ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Gesture hasn't finish after transition "
                    + "idle, start back navigation again.");
            mIsEnable = false;
            startBackNavigation(mCurrentTracker);
            startPredictiveBackAnimationIfNeeded();
        }
    }

    private void onBackNavigationInfoReceived(@Nullable BackNavigationInfo backNavigationInfo,
            @NonNull BackTouchTracker touchTracker) {
        ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Received backNavigationInfo:%s", backNavigationInfo);
@@ -635,6 +658,13 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
            return;
        }
        final int backType = backNavigationInfo.getType();
        if (backType == BackNavigationInfo.TYPE_IN_TRANSITION) {
            mBackNavigationInfo = null;
            tryPilferPointers();
            mTransitionIdleRunner.mIsEnable = true;
            mTransitions.runOnIdle(() -> mShellExecutor.execute(mTransitionIdleRunner));
            return;
        }
        final boolean shouldDispatchToAnimator = shouldDispatchToAnimator();
        if (shouldDispatchToAnimator) {
            if (!predictiveBackDelayWmTransition()) {
@@ -859,6 +889,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
        mPointersPilfered = false;
        mBackGestureStarted = false;
        activeTouchTracker.setState(BackTouchTracker.TouchTrackerState.FINISHED);
        mTransitionIdleRunner.mIsEnable = false;

        if (mPostCommitAnimationInProgress) {
            ProtoLog.w(WM_SHELL_BACK_PREVIEW, "Animation is still running");
+15 −0
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.platform.test.annotations.EnableFlags;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.IRemoteAnimationRunner;
@@ -81,6 +82,7 @@ import android.window.WindowContainerToken;
import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;

import com.android.window.flags.Flags;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
@@ -276,6 +278,19 @@ public class BackAnimationControllerTest extends ShellTestCase {
        }
    }

    @EnableFlags(Flags.FLAG_PREDICTIVE_BACK_INTERCEPT_TRANSITION)
    @Test
    public void noStartInTransition() throws RemoteException {
        registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
        createNavigationInfo(BackNavigationInfo.TYPE_IN_TRANSITION,
                /* enableAnimation = */ true,
                /* isAnimationCallback = */ false);

        doStartEvents(0, 100);
        verify(mAppCallback, never()).onBackStarted(any());
        verify(mTransitions).runOnIdle(any());
    }

    @Test
    public void backToHome_dispatchesEvents() throws RemoteException {
        registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
+16 −4
Original line number Diff line number Diff line
@@ -99,9 +99,13 @@ class BackNavigationController {
    // back animation.
    private AnimationHandler.ScheduleAnimationBuilder mCurrentAnimationBuilder;

    // This will be set if the back navigation is in progress and the current transition is still
    // running. The pending animation builder will do the animation stuff includes creating leashes,
    // re-parenting leashes and set launch behind, etc. Will be handled when transition finished.
    /**
     * This will be set if the back navigation is in progress and the current transition is still
     * running. The pending animation builder will do the animation stuff includes creating leashes,
     * re-parenting leashes and set launch behind, etc. Will be handled when transition finished.
     *
     * @deprecated Remove after Flags#predictive_back_intercept_transition
     */
    private AnimationHandler.ScheduleAnimationBuilder mPendingAnimationBuilder;

    private static int sDefaultAnimationResId;
@@ -229,6 +233,13 @@ class BackNavigationController {
                return null;
            }

            if (Flags.predictiveBackInterceptTransition()
                    && window.mTransitionController.inTransition()) {
                infoBuilder.setType(BackNavigationInfo.TYPE_IN_TRANSITION);
                ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "A transition is happening.");
                return infoBuilder.build();
            }

            final ArrayList<EmbeddedWindowController.EmbeddedWindow> embeddedWindows = wmService
                    .mEmbeddedWindowController.getByHostWindow(window);

@@ -2210,7 +2221,8 @@ class BackNavigationController {
    }

    private void scheduleAnimationInner(AnimationHandler.ScheduleAnimationBuilder builder) {
        if (mWindowManagerService.mAtmService.getTransitionController().inTransition()) {
        if (!Flags.predictiveBackInterceptTransition()
                && mWindowManagerService.mAtmService.getTransitionController().inTransition()) {
            ProtoLog.w(WM_DEBUG_BACK_PREVIEW,
                    "Pending back animation due to another animation is running");
            mPendingAnimationBuilder = builder;
Loading