diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java index 6c9f46fc47..127927059a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java @@ -20,13 +20,14 @@ import android.os.Looper; import com.android.launcher3.Launcher; import com.android.launcher3.userevent.nano.LauncherLogProto; +import com.android.quickstep.GestureState; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; /** * State to indicate we are about to launch a recent task. Note that this state is only used when * quick switching from launcher; quick switching from an app uses WindowTransformSwipeHelper. - * @see com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget#NEW_TASK + * @see GestureState.GestureEndTarget#NEW_TASK */ public class QuickSwitchState extends BackgroundAppState { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java index e1e994c6a6..42d0a0c99d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java @@ -96,6 +96,7 @@ public abstract class BaseSwipeUpHandler mActivityInterface; protected final RecentsModel mRecentsModel; @@ -139,6 +140,7 @@ public abstract class BaseSwipeUpHandler mAM.getRunningTask(0)); - if (!useSharedState) { - mTaskAnimationManager.finishRunningRecentsAnimation(false /* toHome */); - sSwipeSharedState.clearAllState(); - } if (mDeviceState.isKeyguardShowingOccluded()) { // This handles apps showing over the lockscreen (e.g. camera) return createDeviceLockedInputConsumer(gestureState, runningTaskInfo); @@ -543,26 +537,27 @@ public class TouchInteractionService extends Service implements } } - if (runningTaskInfo == null && !sSwipeSharedState.goingToLauncher - && !sSwipeSharedState.recentsAnimationFinishInterrupted) { - return mResetGestureInputConsumer; - } else if (sSwipeSharedState.recentsAnimationFinishInterrupted) { + if (previousGestureState.getFinishingRecentsAnimationTaskId() > 0) { // If the finish animation was interrupted, then continue using the other activity input // consumer but with the next task as the running task RunningTaskInfo info = new ActivityManager.RunningTaskInfo(); - info.id = sSwipeSharedState.nextRunningTaskId; - return createOtherActivityInputConsumer(gestureState, event, info); - } else if (sSwipeSharedState.goingToLauncher + info.id = previousGestureState.getFinishingRecentsAnimationTaskId(); + return createOtherActivityInputConsumer(previousGestureState, gestureState, event, + info); + } else if (runningTaskInfo == null) { + return mResetGestureInputConsumer; + } else if (previousGestureState.isRunningAnimationToLauncher() || gestureState.getActivityInterface().isResumed() || forceOverviewInputConsumer) { - return createOverviewInputConsumer(gestureState, event); + return createOverviewInputConsumer(previousGestureState, gestureState, event); } else if (ENABLE_QUICKSTEP_LIVE_TILE.get() && gestureState.getActivityInterface().isInLiveTileMode()) { - return createOverviewInputConsumer(gestureState, event); + return createOverviewInputConsumer(previousGestureState, gestureState, event); } else if (mDeviceState.isGestureBlockedActivity(runningTaskInfo)) { return mResetGestureInputConsumer; } else { - return createOtherActivityInputConsumer(gestureState, event, runningTaskInfo); + return createOtherActivityInputConsumer(previousGestureState, gestureState, event, + runningTaskInfo); } } @@ -572,14 +567,15 @@ public class TouchInteractionService extends Service implements && (info.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0; } - private InputConsumer createOtherActivityInputConsumer(GestureState gestureState, + private InputConsumer createOtherActivityInputConsumer(GestureState previousGestureState, + GestureState gestureState, MotionEvent event, RunningTaskInfo runningTaskInfo) { final boolean shouldDefer; final BaseSwipeUpHandler.Factory factory; if (mMode == Mode.NO_BUTTON && !mOverviewComponentObserver.isHomeAndOverviewSame()) { - shouldDefer = !sSwipeSharedState.recentsAnimationFinishInterrupted; + shouldDefer = previousGestureState.getFinishingRecentsAnimationTaskId() < 0; factory = mFallbackNoButtonFactory; } else { shouldDefer = gestureState.getActivityInterface().deferStartingActivity(mDeviceState, @@ -590,26 +586,28 @@ public class TouchInteractionService extends Service implements final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event); return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager, gestureState, runningTaskInfo, shouldDefer, this::onConsumerInactive, - sSwipeSharedState, mInputMonitorCompat, disableHorizontalSwipe, factory, mLogId); + mInputMonitorCompat, disableHorizontalSwipe, factory); } private InputConsumer createDeviceLockedInputConsumer(GestureState gestureState, RunningTaskInfo taskInfo) { if (mMode == Mode.NO_BUTTON && taskInfo != null) { return new DeviceLockedInputConsumer(this, mDeviceState, mTaskAnimationManager, - gestureState, sSwipeSharedState, mInputMonitorCompat, taskInfo.taskId, mLogId); + gestureState, mInputMonitorCompat, taskInfo.taskId); } else { return mResetGestureInputConsumer; } } - public InputConsumer createOverviewInputConsumer(GestureState gestureState, MotionEvent event) { + public InputConsumer createOverviewInputConsumer(GestureState previousGestureState, + GestureState gestureState, MotionEvent event) { BaseDraggingActivity activity = gestureState.getActivityInterface().getCreatedActivity(); if (activity == null) { return mResetGestureInputConsumer; } - if (activity.getRootView().hasWindowFocus() || sSwipeSharedState.goingToLauncher) { + if (activity.getRootView().hasWindowFocus() + || previousGestureState.isRunningAnimationToLauncher()) { return new OverviewInputConsumer(gestureState, activity, mInputMonitorCompat, false /* startingInActivityBounds */); } else { @@ -704,10 +702,6 @@ public class TouchInteractionService extends Service implements boolean resumed = mOverviewComponentObserver != null && mOverviewComponentObserver.getActivityInterface().isResumed(); pw.println(" resumed=" + resumed); - pw.println(" useSharedState=" + mConsumer.useSharedSwipeState()); - if (mConsumer.useSharedSwipeState()) { - sSwipeSharedState.dump(" ", pw); - } pw.println(" mConsumer=" + mConsumer.getName()); pw.println("FeatureFlags:"); pw.println(" APPLY_CONFIG_AT_RUNTIME=" + APPLY_CONFIG_AT_RUNTIME.get()); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index 29f431d40f..77ebc402d2 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -26,11 +26,12 @@ import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs; import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW; import static com.android.quickstep.BaseActivityInterface.AnimationFactory.ShelfAnimState.HIDE; import static com.android.quickstep.BaseActivityInterface.AnimationFactory.ShelfAnimState.PEEK; +import static com.android.quickstep.GestureState.GestureEndTarget.HOME; +import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK; +import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK; +import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS; +import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINISHED; import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; -import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.HOME; -import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.LAST_TASK; -import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.NEW_TASK; -import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.RECENTS; import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD; import android.animation.Animator; @@ -70,6 +71,7 @@ import com.android.launcher3.util.TraceHelper; import com.android.quickstep.BaseActivityInterface.AnimationFactory; import com.android.quickstep.BaseActivityInterface.AnimationFactory.ShelfAnimState; import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory; +import com.android.quickstep.GestureState.GestureEndTarget; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.inputconsumers.OverviewInputConsumer; import com.android.quickstep.util.ActiveGestureLog; @@ -138,42 +140,6 @@ public class WindowTransformSwipeHandler private static final int LAUNCHER_UI_STATES = STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED; - public enum GestureEndTarget { - HOME(1, STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT, true, false, - ContainerType.WORKSPACE, false), - - RECENTS(1, STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT - | STATE_SCREENSHOT_VIEW_SHOWN, true, false, ContainerType.TASKSWITCHER, true), - - NEW_TASK(0, STATE_START_NEW_TASK | STATE_CAPTURE_SCREENSHOT, false, true, - ContainerType.APP, true), - - LAST_TASK(0, STATE_RESUME_LAST_TASK, false, true, ContainerType.APP, false); - - GestureEndTarget(float endShift, int endState, boolean isLauncher, boolean canBeContinued, - int containerType, boolean recentsAttachedToAppWindow) { - this.endShift = endShift; - this.endState = endState; - this.isLauncher = isLauncher; - this.canBeContinued = canBeContinued; - this.containerType = containerType; - this.recentsAttachedToAppWindow = recentsAttachedToAppWindow; - } - - /** 0 is app, 1 is overview */ - public final float endShift; - /** The state to apply when we reach this final target */ - public final int endState; - /** Whether the target is in the launcher activity */ - public final boolean isLauncher; - /** Whether the user can start a new gesture while this one is finishing */ - public final boolean canBeContinued; - /** Used to log where the user ended up after the gesture ends */ - public final int containerType; - /** Whether RecentsView should be attached to the window as we animate to this target */ - public final boolean recentsAttachedToAppWindow; - } - public static final long MAX_SWIPE_DURATION = 350; public static final long MIN_SWIPE_DURATION = 80; public static final long MIN_OVERSHOOT_DURATION = 120; @@ -195,7 +161,6 @@ public class WindowTransformSwipeHandler private final TaskAnimationManager mTaskAnimationManager; private final GestureState mGestureState; - private GestureEndTarget mGestureEndTarget; // Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise private RunningWindowAnim mRunningWindowAnim; private boolean mIsShelfPeeking; @@ -287,6 +252,9 @@ public class WindowTransformSwipeHandler | STATE_GESTURE_STARTED, this::setupLauncherUiAfterSwipeUpToRecentsAnimation); + mGestureState.addCallback(STATE_END_TARGET_ANIMATION_FINISHED, + this::onEndTargetSet); + mStateCallback.addCallback(STATE_HANDLER_INVALIDATED, this::invalidateHandler); mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED, this::invalidateHandlerWithLauncher); @@ -338,7 +306,7 @@ public class WindowTransformSwipeHandler @Override protected boolean moveWindowWithRecentsScroll() { - return mGestureEndTarget != HOME; + return mGestureState.getEndTarget() != HOME; } private void onLauncherStart(final T activity) { @@ -351,7 +319,7 @@ public class WindowTransformSwipeHandler // 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) { + if (mGestureState.getEndTarget() != HOME) { Runnable initAnimFactory = () -> { mAnimationFactory = mActivityInterface.prepareRecentsUI(mActivity, mWasLauncherAlreadyVisible, true, @@ -419,7 +387,6 @@ public class WindowTransformSwipeHandler mOverviewComponentObserver.getActivityInterface().switchRunningTaskViewToScreenshot( null, () -> { mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */); - TouchInteractionService.getSwipeSharedState().clearAllState(); }); } else { mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */); @@ -460,13 +427,6 @@ public class WindowTransformSwipeHandler .getHighResLoadingState().setVisible(true); } - private float getTaskCurveScaleForOffsetX(float offsetX, float taskWidth) { - float distanceToReachEdge = mDp.widthPx / 2 + taskWidth / 2 + - mContext.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing); - float interpolation = Math.min(1, offsetX / distanceToReachEdge); - return TaskView.getCurveScaleForInterpolation(interpolation); - } - @Override public void onMotionPauseChanged(boolean isPaused) { setShelfState(isPaused ? PEEK : HIDE, OVERSHOOT_1_2, SHELF_ANIM_DURATION); @@ -491,9 +451,8 @@ public class WindowTransformSwipeHandler ? null : mRecentsAnimationTargets.findTask(mRunningTaskId); final boolean recentsAttachedToAppWindow; - int runningTaskIndex = mRecentsView.getRunningTaskIndex(); - if (mGestureEndTarget != null) { - recentsAttachedToAppWindow = mGestureEndTarget.recentsAttachedToAppWindow; + if (mGestureState.getEndTarget() != null) { + recentsAttachedToAppWindow = mGestureState.getEndTarget().recentsAttachedToAppWindow; } else if (mContinuingLastGesture && mRecentsView.getRunningTaskIndex() != mRecentsView.getNextPage()) { recentsAttachedToAppWindow = true; @@ -540,9 +499,10 @@ public class WindowTransformSwipeHandler } private void buildAnimationController() { - if (mGestureEndTarget == HOME || mHasLauncherTransitionControllerStarted) { - // We don't want a new mLauncherTransitionController if mGestureEndTarget == HOME (it - // has its own animation) or if we're already animating the current controller. + if (mGestureState.getEndTarget() == HOME || mHasLauncherTransitionControllerStarted) { + // We don't want a new mLauncherTransitionController if + // mGestureState.getEndTarget() == HOME (it has its own animation) or if we're already + // animating the current controller. return; } initTransitionEndpoints(mActivity.getDeviceProfile()); @@ -599,7 +559,7 @@ public class WindowTransformSwipeHandler } private void updateLauncherTransitionProgress() { - if (mGestureEndTarget == HOME) { + if (mGestureState.getEndTarget() == HOME) { return; } // Normalize the progress to 0 to 1, as the animation controller will clamp it to that @@ -709,7 +669,7 @@ public class WindowTransformSwipeHandler @Override protected InputConsumer createNewInputProxyHandler() { - endRunningWindowAnim(mGestureEndTarget == HOME /* cancel */); + endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */); endLauncherTransitionController(); if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) { // Hide the task view, if not already hidden @@ -731,6 +691,24 @@ public class WindowTransformSwipeHandler } } + private void onEndTargetSet() { + switch (mGestureState.getEndTarget()) { + case HOME: + mStateCallback.setState(STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT); + break; + case RECENTS: + mStateCallback.setState(STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT + | STATE_SCREENSHOT_VIEW_SHOWN); + break; + case NEW_TASK: + mStateCallback.setState(STATE_START_NEW_TASK | STATE_CAPTURE_SCREENSHOT); + break; + case LAST_TASK: + mStateCallback.setState(STATE_RESUME_LAST_TASK); + break; + } + } + private GestureEndTarget calculateEndTarget(PointF velocity, float endVelocity, boolean isFling, boolean isCancel) { final GestureEndTarget endTarget; @@ -800,7 +778,7 @@ public class WindowTransformSwipeHandler float currentShift = mCurrentShift.value; final GestureEndTarget endTarget = calculateEndTarget(velocity, endVelocity, isFling, isCancel); - float endShift = endTarget.endShift; + float endShift = endTarget.isLauncher ? 1 : 0; final float startShift; Interpolator interpolator = DEACCEL; if (!isFling) { @@ -903,11 +881,12 @@ public class WindowTransformSwipeHandler @UiThread private void animateToProgressInternal(float start, float end, long duration, Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) { - mGestureEndTarget = target; + // Set the state, but don't notify until the animation completes + mGestureState.setEndTarget(target, false /* isAtomic */); maybeUpdateRecentsAttachedState(); - if (mGestureEndTarget == HOME) { + if (mGestureState.getEndTarget() == HOME) { HomeAnimationFactory homeAnimFactory; if (mActivity != null) { homeAnimFactory = mActivityInterface.prepareHomeUI(mActivity); @@ -934,7 +913,8 @@ public class WindowTransformSwipeHandler windowAnim.addAnimatorListener(new AnimationSuccessListener() { @Override public void onAnimationSuccess(Animator animator) { - setStateOnUiThread(target.endState); + // Finalize the state and notify of the change + mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED); } }); windowAnim.start(velocityPxPerMs); @@ -959,10 +939,9 @@ public class WindowTransformSwipeHandler // We are about to launch the current running task, so use LAST_TASK state // instead of NEW_TASK. This could happen, for example, if our scroll is // aborted after we determined the target to be NEW_TASK. - setStateOnUiThread(LAST_TASK.endState); - } else { - setStateOnUiThread(target.endState); + mGestureState.setEndTarget(LAST_TASK); } + mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED); } }); windowAnim.start(); @@ -970,7 +949,7 @@ public class WindowTransformSwipeHandler } // Always play the entire launcher animation when going home, since it is separate from // the animation that has been controlled thus far. - if (mGestureEndTarget == HOME) { + if (mGestureState.getEndTarget() == HOME) { start = 0; } @@ -1029,14 +1008,9 @@ public class WindowTransformSwipeHandler } @Override - public void onConsumerAboutToBeSwitched(SwipeSharedState sharedState) { - if (mGestureEndTarget != null) { - sharedState.canGestureBeContinued = mGestureEndTarget.canBeContinued; - sharedState.goingToLauncher = mGestureEndTarget.isLauncher; - } - - if (sharedState.canGestureBeContinued) { - cancelCurrentAnimation(sharedState); + public void onConsumerAboutToBeSwitched() { + if (!mGestureState.isRunningAnimationToLauncher()) { + cancelCurrentAnimation(); } else { reset(); } @@ -1075,7 +1049,7 @@ public class WindowTransformSwipeHandler * Cancels any running animation so that the active target can be overriden by a new swipe * handle (in case of quick switch). */ - private void cancelCurrentAnimation(SwipeSharedState sharedState) { + private void cancelCurrentAnimation() { mCanceled = true; mCurrentShift.cancelAnimation(); if (mLauncherTransitionController != null && mLauncherTransitionController @@ -1093,7 +1067,7 @@ public class WindowTransformSwipeHandler ? newRunningTaskView.getTask().key.id : -1; mRecentsView.setCurrentTask(newRunningTaskId); - sharedState.setRecentsAnimationFinishInterrupted(newRunningTaskId); + mGestureState.setFinishingRecentsAnimationTaskId(newRunningTaskId); } } @@ -1160,7 +1134,7 @@ public class WindowTransformSwipeHandler mTaskSnapshot = mRecentsAnimationController.screenshotTask(mRunningTaskId); } final TaskView taskView; - if (mGestureEndTarget == HOME) { + if (mGestureState.getEndTarget() == HOME) { // Capture the screenshot before finishing the transition to home to ensure it's // taken in the correct orientation, but no need to update the thumbnail. taskView = null; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java index 0b5129c079..2f73fc1c57 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java @@ -22,11 +22,6 @@ public abstract class DelegateInputConsumer implements InputConsumer { mState = STATE_INACTIVE; } - @Override - public boolean useSharedSwipeState() { - return mDelegate.useSharedSwipeState(); - } - @Override public boolean allowInterceptByParent() { return mDelegate.allowInterceptByParent() && mState != STATE_ACTIVE; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java index 980cfad4e9..8fb2e2ae64 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java @@ -44,7 +44,6 @@ import com.android.quickstep.LockScreenRecentsActivity; import com.android.quickstep.MultiStateCallback; import com.android.quickstep.RecentsAnimationController; import com.android.quickstep.RecentsAnimationDeviceState; -import com.android.quickstep.SwipeSharedState; import com.android.quickstep.RecentsAnimationCallbacks; import com.android.quickstep.RecentsAnimationTargets; import com.android.quickstep.TaskAnimationManager; @@ -79,12 +78,10 @@ public class DeviceLockedInputConsumer implements InputConsumer, private final TaskAnimationManager mTaskAnimationManager; private final GestureState mGestureState; private final float mTouchSlopSquared; - private final SwipeSharedState mSwipeSharedState; private final InputMonitorCompat mInputMonitorCompat; private final PointF mTouchDown = new PointF(); private final AppWindowAnimationHelper mAppWindowAnimationHelper; - private int mLogId; private final AppWindowAnimationHelper.TransformParams mTransformParams; private final Point mDisplaySize; private final MultiStateCallback mStateCallback; @@ -100,16 +97,13 @@ public class DeviceLockedInputConsumer implements InputConsumer, public DeviceLockedInputConsumer(Context context, RecentsAnimationDeviceState deviceState, TaskAnimationManager taskAnimationManager, GestureState gestureState, - SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat, - int runningTaskId, int logId) { + InputMonitorCompat inputMonitorCompat, int runningTaskId) { mContext = context; mDeviceState = deviceState; mTaskAnimationManager = taskAnimationManager; mGestureState = gestureState; mTouchSlopSquared = squaredTouchSlop(context); - mSwipeSharedState = swipeSharedState; mAppWindowAnimationHelper = new AppWindowAnimationHelper(context); - mLogId = logId; mTransformParams = new AppWindowAnimationHelper.TransformParams(); mInputMonitorCompat = inputMonitorCompat; mRunningTaskId = runningTaskId; @@ -216,7 +210,7 @@ public class DeviceLockedInputConsumer implements InputConsumer, .addCategory(Intent.CATEGORY_DEFAULT) .setComponent(new ComponentName(mContext, LockScreenRecentsActivity.class)) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) - .putExtra(INTENT_EXTRA_LOG_TRACE_ID, mLogId); + .putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId()); mTaskAnimationManager.startRecentsAnimation(mGestureState, intent, this); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java index 4e01f6f632..5b76ba508f 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java @@ -15,14 +15,14 @@ */ package com.android.quickstep.inputconsumers; +import static com.android.quickstep.GestureState.GestureEndTarget.HOME; +import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK; +import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK; +import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS; import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; import static com.android.quickstep.RecentsActivity.EXTRA_TASK_ID; import static com.android.quickstep.RecentsActivity.EXTRA_THUMBNAIL; import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW; -import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.HOME; -import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.LAST_TASK; -import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.NEW_TASK; -import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.RECENTS; import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD; import android.animation.Animator; @@ -35,6 +35,7 @@ import android.graphics.PointF; import android.graphics.RectF; import android.os.Bundle; +import android.util.ArrayMap; import com.android.launcher3.R; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; @@ -43,13 +44,13 @@ import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory; import com.android.quickstep.AnimatedFloat; import com.android.quickstep.BaseSwipeUpHandler; import com.android.quickstep.GestureState; +import com.android.quickstep.GestureState.GestureEndTarget; import com.android.quickstep.InputConsumer; import com.android.quickstep.MultiStateCallback; import com.android.quickstep.OverviewComponentObserver; import com.android.quickstep.RecentsActivity; import com.android.quickstep.RecentsAnimationController; import com.android.quickstep.RecentsModel; -import com.android.quickstep.SwipeSharedState; import com.android.quickstep.fallback.FallbackRecentsView; import com.android.quickstep.util.RectFSpringAnim; import com.android.quickstep.RecentsAnimationTargets; @@ -83,27 +84,23 @@ public class FallbackNoButtonInputConsumer extends private static final int STATE_APP_CONTROLLER_RECEIVED = getFlagForIndex(4, "STATE_APP_CONTROLLER_RECEIVED"); - public enum GestureEndTarget { - HOME(3, 100, 1), - RECENTS(1, 300, 0), - LAST_TASK(0, 150, 1), - NEW_TASK(0, 150, 1); - + public static class EndTargetAnimationParams { private final float mEndProgress; private final long mDurationMultiplier; private final float mLauncherAlpha; - GestureEndTarget(float endProgress, long durationMultiplier, float launcherAlpha) { + EndTargetAnimationParams(float endProgress, long durationMultiplier, float launcherAlpha) { mEndProgress = endProgress; mDurationMultiplier = durationMultiplier; mLauncherAlpha = launcherAlpha; } } + private static ArrayMap + mEndTargetAnimationParams = new ArrayMap(); private final AnimatedFloat mLauncherAlpha = new AnimatedFloat(this::onLauncherAlphaChanged); private boolean mIsMotionPaused = false; - private GestureEndTarget mEndTarget; private final boolean mInQuickSwitchMode; private final boolean mContinuingLastGesture; @@ -136,6 +133,12 @@ public class FallbackNoButtonInputConsumer extends mAppWindowAnimationHelper.setBaseAlphaCallback((t, a) -> mLauncherAlpha.value); } + // Going home has an extra long progress to ensure that it animates into the screen + mEndTargetAnimationParams.put(HOME, new EndTargetAnimationParams(3, 100, 1)); + mEndTargetAnimationParams.put(RECENTS, new EndTargetAnimationParams(1, 300, 0)); + mEndTargetAnimationParams.put(LAST_TASK, new EndTargetAnimationParams(0, 150, 1)); + mEndTargetAnimationParams.put(NEW_TASK, new EndTargetAnimationParams(0, 150, 1)); + initStateCallbacks(); } @@ -161,7 +164,7 @@ public class FallbackNoButtonInputConsumer extends } private void onLauncherAlphaChanged() { - if (mRecentsAnimationTargets != null && mEndTarget == null) { + if (mRecentsAnimationTargets != null && mGestureState.getEndTarget() == null) { applyTransformUnchecked(); } } @@ -247,7 +250,7 @@ public class FallbackNoButtonInputConsumer extends @Override public void onGestureCancelled() { updateDisplacement(0); - mEndTarget = LAST_TASK; + mGestureState.setEndTarget(LAST_TASK); setStateOnUiThread(STATE_GESTURE_CANCELLED); } @@ -256,28 +259,29 @@ public class FallbackNoButtonInputConsumer extends mEndVelocityPxPerMs.set(0, velocity.y / 1000); if (mInQuickSwitchMode) { // For now set it to non-null, it will be reset before starting the animation - mEndTarget = LAST_TASK; + mGestureState.setEndTarget(LAST_TASK); } else { float flingThreshold = mContext.getResources() .getDimension(R.dimen.quickstep_fling_threshold_velocity); boolean isFling = Math.abs(endVelocity) > flingThreshold; if (isFling) { - mEndTarget = endVelocity < 0 ? HOME : LAST_TASK; + mGestureState.setEndTarget(endVelocity < 0 ? HOME : LAST_TASK); } else if (mIsMotionPaused) { - mEndTarget = RECENTS; + mGestureState.setEndTarget(RECENTS); } else { - mEndTarget = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW ? HOME : LAST_TASK; + mGestureState.setEndTarget(mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW + ? HOME + : LAST_TASK); } } setStateOnUiThread(STATE_GESTURE_COMPLETED); } @Override - public void onConsumerAboutToBeSwitched(SwipeSharedState sharedState) { - if (mInQuickSwitchMode && mEndTarget != null) { - sharedState.canGestureBeContinued = true; - sharedState.goingToLauncher = false; + public void onConsumerAboutToBeSwitched() { + if (mInQuickSwitchMode && mGestureState.getEndTarget() != null) { + mGestureState.setEndTarget(HOME); mCanceled = true; mCurrentShift.cancelAnimation(); @@ -293,7 +297,7 @@ public class FallbackNoButtonInputConsumer extends ? newRunningTaskView.getTask().key.id : -1; mRecentsView.setCurrentTask(newRunningTaskId); - sharedState.setRecentsAnimationFinishInterrupted(newRunningTaskId); + mGestureState.setFinishingRecentsAnimationTaskId(newRunningTaskId); } mRecentsView.setOnScrollChangeListener(null); } @@ -319,7 +323,7 @@ public class FallbackNoButtonInputConsumer extends } private void finishAnimationTargetSetAnimationComplete() { - switch (mEndTarget) { + switch (mGestureState.getEndTarget()) { case HOME: { if (mSwipeUpOverHome) { mRecentsAnimationController.finish(false, null, false); @@ -370,17 +374,20 @@ public class FallbackNoButtonInputConsumer extends // Recalculate the end target, some views might have been initialized after // gesture has ended. if (mRecentsView == null || !hasTargets()) { - mEndTarget = LAST_TASK; + mGestureState.setEndTarget(LAST_TASK); } else { final int runningTaskIndex = mRecentsView.getRunningTaskIndex(); final int taskToLaunch = mRecentsView.getNextPage(); - mEndTarget = (runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex) - ? NEW_TASK : LAST_TASK; + mGestureState.setEndTarget( + (runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex) + ? NEW_TASK + : LAST_TASK); } } - float endProgress = mEndTarget.mEndProgress; - long duration = (long) (mEndTarget.mDurationMultiplier * + EndTargetAnimationParams params = mEndTargetAnimationParams.get(mGestureState.getEndTarget()); + float endProgress = params.mEndProgress; + long duration = (long) (params.mDurationMultiplier * Math.abs(endProgress - mCurrentShift.value)); if (mRecentsView != null) { duration = Math.max(duration, mRecentsView.getScroller().getDuration()); @@ -395,7 +402,7 @@ public class FallbackNoButtonInputConsumer extends } }; - if (mEndTarget == HOME && !mRunningOverHome) { + if (mGestureState.getEndTarget() == HOME && !mRunningOverHome) { RectFSpringAnim anim = createWindowAnimationToHome(mCurrentShift.value, duration); anim.addAnimatorListener(endListener); anim.start(mEndVelocityPxPerMs); @@ -404,7 +411,7 @@ public class FallbackNoButtonInputConsumer extends AnimatorSet anim = new AnimatorSet(); anim.play(mLauncherAlpha.animateToValue( - mLauncherAlpha.value, mEndTarget.mLauncherAlpha)); + mLauncherAlpha.value, params.mLauncherAlpha)); anim.play(mCurrentShift.animateToValue(mCurrentShift.value, endProgress)); anim.setDuration(duration); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index 6ba326c650..c4792504d7 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -54,7 +54,6 @@ import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.RecentsAnimationCallbacks; import com.android.quickstep.RecentsAnimationDeviceState; -import com.android.quickstep.SwipeSharedState; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.TaskAnimationManager; @@ -85,7 +84,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC private RecentsAnimationCallbacks mActiveCallbacks; private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher(); private final RunningTaskInfo mRunningTask; - private final SwipeSharedState mSwipeSharedState; private final InputMonitorCompat mInputMonitorCompat; private final SysUINavigationMode.Mode mMode; private final BaseActivityInterface mActivityInterface; @@ -126,16 +124,14 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC ActivityManagerWrapper.getInstance().cancelRecentsAnimation( true /* restoreHomeStackPosition */); }; - private int mLogId; public OtherActivityInputConsumer(Context base, RecentsAnimationDeviceState deviceState, TaskAnimationManager taskAnimationManager, GestureState gestureState, RunningTaskInfo runningTaskInfo, boolean isDeferredDownTarget, Consumer onCompleteCallback, - SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat, - boolean disableHorizontalSwipe, Factory handlerFactory, int logId) { + InputMonitorCompat inputMonitorCompat, boolean disableHorizontalSwipe, + Factory handlerFactory) { super(base); - mLogId = logId; mDeviceState = deviceState; mTaskAnimationManager = taskAnimationManager; mGestureState = gestureState; @@ -154,7 +150,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC boolean continuingPreviousGesture = mTaskAnimationManager.isRecentsAnimationRunning(); mIsDeferredDownTarget = !continuingPreviousGesture && isDeferredDownTarget; - mSwipeSharedState = swipeSharedState; mNavBarPosition = new NavBarPosition(base); mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop(); @@ -347,7 +342,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC notifyGestureStarted(); } else { Intent intent = mInteractionHandler.getLaunchIntent(); - intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mLogId); + intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId()); mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation(mGestureState, intent, mInteractionHandler); } @@ -404,7 +399,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC // The consumer is being switched while we are active. Set up the shared state to be // used by the next animation removeListener(); - mInteractionHandler.onConsumerAboutToBeSwitched(mSwipeSharedState); + mInteractionHandler.onConsumerAboutToBeSwitched(); } } @@ -432,11 +427,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC } } - @Override - public boolean useSharedSwipeState() { - return mInteractionHandler != null; - } - @Override public boolean allowInterceptByParent() { return !mPassedPilferInputSlop; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java index b22a75b7c7..5ef5246c08 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/ResetGestureInputConsumer.java @@ -42,7 +42,6 @@ public class ResetGestureInputConsumer implements InputConsumer { if (ev.getAction() == MotionEvent.ACTION_DOWN && mTaskAnimationManager.isRecentsAnimationRunning()) { mTaskAnimationManager.finishRunningRecentsAnimation(false /* toHome */); - TouchInteractionService.getSwipeSharedState().clearAllState(); } } } diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java index 4bd962a5ff..67eb9de1b9 100644 --- a/quickstep/src/com/android/quickstep/GestureState.java +++ b/quickstep/src/com/android/quickstep/GestureState.java @@ -15,8 +15,12 @@ */ package com.android.quickstep; +import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; + import com.android.launcher3.BaseDraggingActivity; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.systemui.shared.recents.model.ThumbnailData; +import java.util.ArrayList; /** * Manages the state for an active system gesture, listens for events from the system and Launcher, @@ -24,30 +28,202 @@ import com.android.systemui.shared.recents.model.ThumbnailData; */ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationListener { - // Needed to interact with the current activity - private BaseActivityInterface mActivityInterface; + /** + * Defines the end targets of a gesture and the associated state. + */ + public enum GestureEndTarget { + HOME(true, ContainerType.WORKSPACE, false), - public GestureState(BaseActivityInterface activityInterface) { - mActivityInterface = activityInterface; + RECENTS(true, ContainerType.TASKSWITCHER, true), + + NEW_TASK(false, ContainerType.APP, true), + + LAST_TASK(false, ContainerType.APP, false); + + GestureEndTarget(boolean isLauncher, int containerType, + boolean recentsAttachedToAppWindow) { + this.isLauncher = isLauncher; + this.containerType = containerType; + this.recentsAttachedToAppWindow = recentsAttachedToAppWindow; + } + + /** Whether the target is in the launcher activity. Implicitly, if the end target is going + to Launcher, then we can not interrupt the animation to start another gesture. */ + public final boolean isLauncher; + /** Used to log where the user ended up after the gesture ends */ + public final int containerType; + /** Whether RecentsView should be attached to the window as we animate to this target */ + public final boolean recentsAttachedToAppWindow; } + private static final ArrayList STATE_NAMES = new ArrayList<>(); + private static int FLAG_COUNT = 0; + private static int getFlagForIndex(String name) { + if (DEBUG_STATES) { + STATE_NAMES.add(name); + } + int index = 1 << FLAG_COUNT; + FLAG_COUNT++; + return index; + } + + // Called when the end target as been set + public static final int STATE_END_TARGET_SET = + getFlagForIndex("STATE_END_TARGET_SET"); + + // Called when the end target animation has finished + public static final int STATE_END_TARGET_ANIMATION_FINISHED = + getFlagForIndex("STATE_END_TARGET_ANIMATION_FINISHED"); + + // Called when the recents animation has been requested to start + public static final int STATE_RECENTS_ANIMATION_INITIALIZED = + getFlagForIndex("STATE_RECENTS_ANIMATION_INITIALIZED"); + + // Called when the recents animation is started and the TaskAnimationManager has been updated + // with the controller and targets + public static final int STATE_RECENTS_ANIMATION_STARTED = + getFlagForIndex("STATE_RECENTS_ANIMATION_STARTED"); + + // Called when the recents animation is canceled + public static final int STATE_RECENTS_ANIMATION_CANCELED = + getFlagForIndex("STATE_RECENTS_ANIMATION_CANCELED"); + + // Called when the recents animation finishes + public static final int STATE_RECENTS_ANIMATION_FINISHED = + getFlagForIndex("STATE_RECENTS_ANIMATION_FINISHED"); + + // Always called when the recents animation ends (regardless of cancel or finish) + public static final int STATE_RECENTS_ANIMATION_ENDED = + getFlagForIndex("STATE_RECENTS_ANIMATION_ENDED"); + + + // Needed to interact with the current activity + private final BaseActivityInterface mActivityInterface; + private final MultiStateCallback mStateCallback; + private final int mGestureId; + + private GestureEndTarget mEndTarget; + // TODO: This can be removed once we stop finishing the animation when starting a new task + private int mFinishingRecentsAnimationTaskId = -1; + + public GestureState(BaseActivityInterface activityInterface, int gestureId) { + mActivityInterface = activityInterface; + mGestureId = gestureId; + mStateCallback = new MultiStateCallback(STATE_NAMES.toArray(new String[0])); + } + + public GestureState() { + // Do nothing, only used for initializing the gesture state prior to user unlock + mActivityInterface = null; + mGestureId = -1; + mStateCallback = new MultiStateCallback(STATE_NAMES.toArray(new String[0])); + } + + /** + * Sets the given {@param stateFlag}s. + */ + public void setState(int stateFlag) { + mStateCallback.setState(stateFlag); + } + + /** + * Adds a callback for when the states matching the given {@param stateMask} is set. + */ + public void addCallback(int stateMask, Runnable callback) { + mStateCallback.addCallback(stateMask, callback); + } + + /** + * @return the interface to the activity handing the UI updates for this gesture. + */ public BaseActivityInterface getActivityInterface() { return mActivityInterface; } + /** + * @return the id for this particular gesture. + */ + public int getGestureId() { + return mGestureId; + } + + /** + * @return the end target for this gesture (if known). + */ + public GestureEndTarget getEndTarget() { + return mEndTarget; + } + + /** + * @return whether the current gesture is still running a recents animation to a state in the + * Launcher or Recents activity. + */ + public boolean isRunningAnimationToLauncher() { + return isRecentsAnimationRunning() && mEndTarget != null && mEndTarget.isLauncher; + } + + /** + * Sets the end target of this gesture and immediately notifies the state changes. + */ + public void setEndTarget(GestureEndTarget target) { + setEndTarget(target, true /* isAtomic */); + } + + /** + * Sets the end target of this gesture, but if {@param isAtomic} is {@code false}, then the + * caller must explicitly set {@link #STATE_END_TARGET_ANIMATION_FINISHED} themselves. + */ + public void setEndTarget(GestureEndTarget target, boolean isAtomic) { + mEndTarget = target; + mStateCallback.setState(STATE_END_TARGET_SET); + if (isAtomic) { + mStateCallback.setState(STATE_END_TARGET_ANIMATION_FINISHED); + } + } + + /** + * @return the id for the task that was about to be launched following the finish of the recents + * animation. Only defined between when the finish-recents call was made and the launch + * activity call is made. + */ + public int getFinishingRecentsAnimationTaskId() { + return mFinishingRecentsAnimationTaskId; + } + + /** + * Sets the id for the task will be launched after the recents animation is finished. Once the + * animation has finished then the id will be reset to -1. + */ + public void setFinishingRecentsAnimationTaskId(int taskId) { + mFinishingRecentsAnimationTaskId = taskId; + mStateCallback.addCallback(STATE_RECENTS_ANIMATION_FINISHED, () -> { + mFinishingRecentsAnimationTaskId = -1; + }); + } + + /** + * @return whether the recents animation is started but not yet ended + */ + public boolean isRecentsAnimationRunning() { + return mStateCallback.hasStates(STATE_RECENTS_ANIMATION_INITIALIZED) && + !mStateCallback.hasStates(STATE_RECENTS_ANIMATION_ENDED); + } + @Override public void onRecentsAnimationStart(RecentsAnimationController controller, RecentsAnimationTargets targets) { - // To be implemented + mStateCallback.setState(STATE_RECENTS_ANIMATION_STARTED); } @Override public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) { - // To be implemented + mStateCallback.setState(STATE_RECENTS_ANIMATION_CANCELED); + mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED); } @Override public void onRecentsAnimationFinished(RecentsAnimationController controller) { - // To be implemented + mStateCallback.setState(STATE_RECENTS_ANIMATION_FINISHED); + mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED); } } diff --git a/quickstep/src/com/android/quickstep/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java index 62c0ded534..918645d9aa 100644 --- a/quickstep/src/com/android/quickstep/InputConsumer.java +++ b/quickstep/src/com/android/quickstep/InputConsumer.java @@ -52,10 +52,6 @@ public interface InputConsumer { int getType(); - default boolean useSharedSwipeState() { - return false; - } - /** * Returns true if the user has crossed the threshold for it to be an explicit action. */ @@ -65,6 +61,8 @@ public interface InputConsumer { /** * Called by the event queue when the consumer is about to be switched to a new consumer. + * Consumers should update the state accordingly here before the state is passed to the new + * consumer. */ default void onConsumerAboutToBeSwitched() { } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/MultiStateCallback.java b/quickstep/src/com/android/quickstep/MultiStateCallback.java similarity index 100% rename from quickstep/recents_ui_overrides/src/com/android/quickstep/MultiStateCallback.java rename to quickstep/src/com/android/quickstep/MultiStateCallback.java diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java index 557be5b554..6873899c6b 100644 --- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java +++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java @@ -17,6 +17,7 @@ package com.android.quickstep; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; +import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED; import android.content.Intent; import android.util.Log; @@ -95,6 +96,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn mCallbacks.addListener(listener); UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance() .startRecentsActivity(intent, null, mCallbacks, null, null)); + gestureState.setState(STATE_RECENTS_ANIMATION_INITIALIZED); return mCallbacks; }