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

Commit 687ff6af authored by Tony's avatar Tony
Browse files

Fix some state issues with home and quick switch gestures

Handle the fact that LAUNCHER_STARTED can come 25ms+ later than LAUNCHER_PRESENT
- Don't call prepareRecentsUi() if we already completed the gesture to go home
  - Previously it was possible to get LAUNCHER_PRESENT -> GESTURE_STARTED ->
    GESTURE_COMPLETED -> LAUNCHER_STARTED. Because we go to BACKGROUND_APP state in
    LAUNCHER_STARTED, this sequence ended up there instead of home (b/124338231)
- Call setupRecentsViewUi() in LAUNCHER_PRESENT instead of LAUNCHER_START
  - Because setupRecentsViewUi() sets RecentsView to show the running task, it was
    interferring with quick switches that had the state sequence above

Other quick switch fixes
- Set canBeContinued = true for LAST_TASK gesture target. This handles cases like:
  switch from task 0 to task 1, intercept and go back to 0 (LAST_TASK), intercept
  again to go to 1
- Ignore deferred touch down target if we're continuing the previous gesture
- Set STATE_HANDLER_INVALIDATED as soon as we start finishing recents animation
  instead of waiting until the new task is launched. This is what we do when
  re-launching the last task, and it allows us to start a new gesture sooner.

One race condition still exists with consecutive quick switches: if you switch to
a new task, the next gesture might get stuck if it starts after finishing the
recents animation but before the task is fully launched/launcher is stopped.

Bug: 124338231
Bug: 111926330
Change-Id: Ia7e1eebe6e81e2f10bb42a10b2f46fd720da0dc1
parent 0d447c88
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -130,7 +130,8 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
        mVelocityTracker = VelocityTracker.obtain();

        mActivityControlHelper = activityControl;
        mIsDeferredDownTarget = isDeferredDownTarget;
        boolean continuingPreviousGesture = swipeSharedState.getActiveListener() != null;
        mIsDeferredDownTarget = !continuingPreviousGesture && isDeferredDownTarget;
        mOverviewCallbacks = overviewCallbacks;
        mTaskOverlayFactory = taskOverlayFactory;
        mInputConsumer = inputConsumer;
@@ -142,8 +143,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC

        mDragSlop = NavigationBarCompat.getQuickStepDragSlopPx();
        mTouchSlop = NavigationBarCompat.getQuickStepTouchSlopPx();
        // If active listener isn't null, we are continuing the previous gesture.
        mPassedTouchSlop = mPassedDragSlop = mSwipeSharedState.getActiveListener() != null;
        mPassedTouchSlop = mPassedDragSlop = continuingPreviousGesture;
    }

    @Override
+26 −22
Original line number Diff line number Diff line
@@ -162,8 +162,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
    private static final int LAUNCHER_UI_STATES =
            STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED;

    // For debugging, keep in sync with above states

    enum GestureEndTarget {
        HOME(1, STATE_SCALED_CONTROLLER_HOME, true, false, ContainerType.WORKSPACE),

@@ -172,7 +170,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>

        NEW_TASK(0, STATE_START_NEW_TASK, false, true, ContainerType.APP),

        LAST_TASK(0, STATE_SCALED_CONTROLLER_LAST_TASK, false, false, ContainerType.APP);
        LAST_TASK(0, STATE_SCALED_CONTROLLER_LAST_TASK, false, true, ContainerType.APP);

        GestureEndTarget(float endShift, int endState, boolean isLauncher, boolean canBeContinued,
                int containerType) {
@@ -234,6 +232,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
    private ThumbnailData mTaskSnapshot;

    private MultiStateCallback mStateCallback;
    // Used to control launcher components throughout the swipe gesture.
    private AnimatorPlaybackController mLauncherTransitionController;

    private T mActivity;
@@ -274,10 +273,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
    private void initStateCallbacks() {
        mStateCallback = new MultiStateCallback(STATE_NAMES);

        // Re-setup the recents UI when gesture starts, as the state could have been changed during
        // that time by a previous window transition.
        mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_GESTURE_STARTED,
                this::setupRecentsViewUi);
        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_STARTED,
                this::onLauncherPresentAndGestureStarted);

        mStateCallback.addCallback(STATE_LAUNCHER_DRAWN | STATE_GESTURE_STARTED,
                this::initializeLauncherAnimationController);
@@ -285,9 +282,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN,
                this::launcherFrameDrawn);

        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_STARTED,
                this::notifyGestureStartedAsync);

        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_STARTED
                        | STATE_GESTURE_CANCELLED,
                this::resetStateForAnimationCancel);
@@ -414,6 +408,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
        } else {
            activity.setOnStartCallback(this::onLauncherStart);
        }

        setupRecentsViewUi();
        return true;
    }

@@ -425,8 +421,12 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
            return;
        }

        // If we've already ended the gesture and are going home, don't prepare recents UI,
        // as that will set the state as BACKGROUND_APP, overriding the animation to NORMAL.
        if (mGestureEndTarget != HOME) {
            mAnimationFactory = mActivityControlHelper.prepareRecentsUI(mActivity,
                    mWasLauncherAlreadyVisible, true, this::onAnimatorPlaybackControllerCreated);
        }
        AbstractFloatingView.closeAllOpenViews(activity, mWasLauncherAlreadyVisible);

        if (mWasLauncherAlreadyVisible) {
@@ -450,11 +450,18 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
            });
        }

        setupRecentsViewUi();
        activity.getRootView().setOnApplyWindowInsetsListener(this);
        mStateCallback.setState(STATE_LAUNCHER_STARTED);
    }

    private void onLauncherPresentAndGestureStarted() {
        // Re-setup the recents UI when gesture starts, as the state could have been changed during
        // that time by a previous window transition.
        setupRecentsViewUi();

        notifyGestureStartedAsync();
    }

    private void setupRecentsViewUi() {
        if (mContinuingLastGesture) {
            return;
@@ -723,7 +730,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
            final int lastTaskIndex = mRecentsView.getTaskViewCount() - 1;
            final int runningTaskIndex = mRecentsView.getRunningTaskIndex();
            taskToLaunch = nextPage <= lastTaskIndex ? nextPage : lastTaskIndex;
            goingToNewTask = mRecentsView != null && taskToLaunch != runningTaskIndex;
            goingToNewTask = runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex;
        } else {
            goingToNewTask = false;
        }
@@ -859,8 +866,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
            RecentsModel.INSTANCE.get(mContext).endStabilizationSession();
        }

        HomeAnimationFactory homeAnimFactory;
        if (mGestureEndTarget == HOME) {
            HomeAnimationFactory homeAnimFactory;
            if (mActivity != null) {
                homeAnimFactory = mActivityControlHelper.prepareHomeUI(mActivity);
            } else {
@@ -901,7 +908,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
                }
            });
            windowAnim.start();
            homeAnimFactory = null;
        }
        // Always play the entire launcher animation when going home, since it is separate from
        // the animation that has been controlled thus far.
@@ -951,6 +957,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
        }

        AnimatorPlaybackController homeAnim = homeAnimationFactory.createActivityAnimationToHome();

        // We want the window alpha to be 0 once this threshold is met, so that the
        // FolderIconView can be seen morphing into the icon shape.
        final float windowAlphaThreshold = isFloatingIconView ? 0.75f : 1f;
@@ -1006,18 +1013,15 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
        // Launch the task user scrolled to (mRecentsView.getNextPage()).
        if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
            // We finish recents animation inside launchTask() when live tile is enabled.
            mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false,
                    result -> setStateOnUiThread(STATE_HANDLER_INVALIDATED),
                    mMainThreadHandler);
            mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false);
        } else {
            mRecentsAnimationWrapper.finish(true /* toRecents */, () -> {
                mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false,
                        result -> setStateOnUiThread(STATE_HANDLER_INVALIDATED),
                        mMainThreadHandler);
                mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false);
            });
        }
        TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", false);
        doLogGesture(NEW_TASK);
        reset();
    }

    public void reset() {