10/ Migrate shared state to the gesture state

- Instead of a shared state which is written into, gestures update their
  own gesture state and that state is passed to the next gesture.
- The existing shared state encoded the final end target (which is
  currently directly correlated with canGestureBeContinued). If we move
  the end target calculations to the GestureState, the handlers can listen
  for those changes and we can use the previous gesture state to decide
  which consumer to choose.  In addition, we move over the interrupted-
  finish-launch-task id.

Bug: 141886704

Change-Id: Icb6a3815c16b23692dbcde316114bd3cea06634e
Signed-off-by: Winson Chung <winsonc@google.com>
This commit is contained in:
Winson Chung 2019-10-07 16:51:58 -07:00
parent c9bf6d45ac
commit c80b3224aa
14 changed files with 332 additions and 259 deletions

View File

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

View File

@ -96,6 +96,7 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
protected float mDragLengthFactor = 1;
protected final Context mContext;
protected final GestureState mGestureState;
protected final OverviewComponentObserver mOverviewComponentObserver;
protected final BaseActivityInterface<T> mActivityInterface;
protected final RecentsModel mRecentsModel;
@ -139,6 +140,7 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
OverviewComponentObserver overviewComponentObserver,
RecentsModel recentsModel, InputConsumerController inputConsumer, int runningTaskId) {
mContext = context;
mGestureState = gestureState;
mOverviewComponentObserver = overviewComponentObserver;
mActivityInterface = gestureState.getActivityInterface();
mRecentsModel = recentsModel;
@ -394,7 +396,7 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
@UiThread
public abstract void onGestureEnded(float endVelocity, PointF velocity, PointF downPos);
public abstract void onConsumerAboutToBeSwitched(SwipeSharedState sharedState);
public abstract void onConsumerAboutToBeSwitched();
public void setIsLikelyToStartNewTask(boolean isLikelyToStartNewTask) { }

View File

@ -1,59 +0,0 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep;
import java.io.PrintWriter;
/**
* Utility class used to store state information shared across multiple transitions.
*/
public class SwipeSharedState {
public boolean canGestureBeContinued;
public boolean goingToLauncher;
public boolean recentsAnimationFinishInterrupted;
public int nextRunningTaskId = -1;
private int mLogId;
/**
* Called when a recents animation has finished, but was interrupted before the next task was
* launched. The given {@param runningTaskId} should be used as the running task for the
* continuing input consumer.
*/
public void setRecentsAnimationFinishInterrupted(int runningTaskId) {
recentsAnimationFinishInterrupted = true;
nextRunningTaskId = runningTaskId;
}
public void clearAllState() {
canGestureBeContinued = false;
recentsAnimationFinishInterrupted = false;
nextRunningTaskId = -1;
goingToLauncher = false;
}
public void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "goingToLauncher=" + goingToLauncher);
pw.println(prefix + "canGestureBeContinued=" + canGestureBeContinued);
pw.println(prefix + "recentsAnimationFinishInterrupted=" + recentsAnimationFinishInterrupted);
pw.println(prefix + "nextRunningTaskId=" + nextRunningTaskId);
pw.println(prefix + "logTraceId=" + mLogId);
}
public void setLogTraceId(int logId) {
this.mLogId = logId;
}
}

View File

@ -235,8 +235,6 @@ public class TouchInteractionService extends Service implements
private static boolean sConnected = false;
private static boolean sIsInitialized = false;
private static final SwipeSharedState sSwipeSharedState = new SwipeSharedState();
private int mLogId;
public static boolean isConnected() {
return sConnected;
@ -246,10 +244,6 @@ public class TouchInteractionService extends Service implements
return sIsInitialized;
}
public static SwipeSharedState getSwipeSharedState() {
return sSwipeSharedState;
}
private final BaseSwipeUpHandler.Factory mWindowTransformFactory =
this::createWindowTransformSwipeHandler;
private final BaseSwipeUpHandler.Factory mFallbackNoButtonFactory =
@ -267,6 +261,7 @@ public class TouchInteractionService extends Service implements
private InputConsumer mConsumer = InputConsumer.NO_OP;
private Choreographer mMainChoreographer;
private InputConsumer mResetGestureInputConsumer;
private GestureState mGestureState = new GestureState();
private InputMonitorCompat mInputMonitorCompat;
private InputEventReceiver mInputEventReceiver;
@ -360,7 +355,6 @@ public class TouchInteractionService extends Service implements
mOverviewComponentObserver.getActivityInterface().switchRunningTaskViewToScreenshot(
null, () -> {
mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */);
sSwipeSharedState.clearAllState();
});
} else {
mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */);
@ -440,15 +434,13 @@ public class TouchInteractionService extends Service implements
MotionEvent event = (MotionEvent) ev;
if (event.getAction() == ACTION_DOWN) {
GestureState newGestureState = new GestureState(
mOverviewComponentObserver.getActivityInterface());
mLogId = ActiveGestureLog.INSTANCE.generateAndSetLogId();
sSwipeSharedState.setLogTraceId(mLogId);
mOverviewComponentObserver.getActivityInterface(),
ActiveGestureLog.INSTANCE.generateAndSetLogId());
if (mDeviceState.isInSwipeUpTouchRegion(event)) {
boolean useSharedState = mConsumer.useSharedSwipeState();
mConsumer.onConsumerAboutToBeSwitched();
mConsumer = newConsumer(newGestureState, useSharedState, event);
mConsumer = newConsumer(mGestureState, newGestureState, event);
ActiveGestureLog.INSTANCE.addLog("setInputConsumer", mConsumer.getType());
mUncheckedConsumer = mConsumer;
} else if (mDeviceState.isUserUnlocked() && mMode == Mode.NO_BUTTON
@ -461,6 +453,9 @@ public class TouchInteractionService extends Service implements
} else {
mUncheckedConsumer = InputConsumer.NO_OP;
}
// Save the current gesture state
mGestureState = newGestureState;
}
ActiveGestureLog.INSTANCE.addLog("onMotionEvent", event.getActionMasked());
@ -468,39 +463,42 @@ public class TouchInteractionService extends Service implements
TraceHelper.INSTANCE.endFlagsOverride(traceToken);
}
private InputConsumer newConsumer(GestureState gestureState, boolean useSharedState,
MotionEvent event) {
private InputConsumer newConsumer(GestureState previousGestureState,
GestureState newGestureState, MotionEvent event) {
boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
if (!mDeviceState.isUserUnlocked()) {
if (canStartSystemGesture) {
// This handles apps launched in direct boot mode (e.g. dialer) as well as apps
// launched while device is locked even after exiting direct boot mode (e.g. camera).
return createDeviceLockedInputConsumer(gestureState,
return createDeviceLockedInputConsumer(newGestureState,
mAM.getRunningTask(ACTIVITY_TYPE_ASSISTANT));
} else {
return mResetGestureInputConsumer;
}
}
// When using sharedState, bypass systemState check as this is a followup gesture and the
// first gesture started in a valid system state.
InputConsumer base = canStartSystemGesture || useSharedState
? newBaseConsumer(gestureState, useSharedState, event) : mResetGestureInputConsumer;
// When there is an existing recents animation running, bypass systemState check as this is
// a followup gesture and the first gesture started in a valid system state.
InputConsumer base = canStartSystemGesture
|| previousGestureState.isRecentsAnimationRunning()
? newBaseConsumer(previousGestureState, newGestureState, event)
: mResetGestureInputConsumer;
if (mMode == Mode.NO_BUTTON) {
if (mDeviceState.canTriggerAssistantAction(event)) {
base = new AssistantInputConsumer(this, gestureState, base, mInputMonitorCompat);
base = new AssistantInputConsumer(this, newGestureState, base, mInputMonitorCompat);
}
if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()) {
// Put the Compose gesture as higher priority than the Assistant or base gestures
base = new QuickCaptureInputConsumer(this, gestureState, base, mInputMonitorCompat);
base = new QuickCaptureInputConsumer(this, newGestureState, base,
mInputMonitorCompat);
}
if (mDeviceState.isScreenPinningActive()) {
// Note: we only allow accessibility to wrap this, and it replaces the previous
// base input consumer (which should be NO_OP anyway since topTaskLocked == true).
base = new ScreenPinnedInputConsumer(this, gestureState);
base = new ScreenPinnedInputConsumer(this, newGestureState);
}
if (mDeviceState.isAccessibilityMenuAvailable()) {
@ -515,14 +513,10 @@ public class TouchInteractionService extends Service implements
return base;
}
private InputConsumer newBaseConsumer(GestureState gestureState, boolean useSharedState,
MotionEvent event) {
private InputConsumer newBaseConsumer(GestureState previousGestureState,
GestureState gestureState, MotionEvent event) {
RunningTaskInfo runningTaskInfo = TraceHelper.whitelistIpcs("getRunningTask.0",
() -> 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());

View File

@ -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<T extends BaseDraggingActivity>
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<T extends BaseDraggingActivity>
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<T extends BaseDraggingActivity>
| 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<T extends BaseDraggingActivity>
@Override
protected boolean moveWindowWithRecentsScroll() {
return mGestureEndTarget != HOME;
return mGestureState.getEndTarget() != HOME;
}
private void onLauncherStart(final T activity) {
@ -351,7 +319,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
// 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<T extends BaseDraggingActivity>
mOverviewComponentObserver.getActivityInterface().switchRunningTaskViewToScreenshot(
null, () -> {
mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */);
TouchInteractionService.getSwipeSharedState().clearAllState();
});
} else {
mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */);
@ -460,13 +427,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
.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<T extends BaseDraggingActivity>
? 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<T extends BaseDraggingActivity>
}
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<T extends BaseDraggingActivity>
}
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<T extends BaseDraggingActivity>
@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<T extends BaseDraggingActivity>
}
}
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<T extends BaseDraggingActivity>
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<T extends BaseDraggingActivity>
@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<T extends BaseDraggingActivity>
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<T extends BaseDraggingActivity>
// 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<T extends BaseDraggingActivity>
}
// 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<T extends BaseDraggingActivity>
}
@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<T extends BaseDraggingActivity>
* 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<T extends BaseDraggingActivity>
? newRunningTaskView.getTask().key.id
: -1;
mRecentsView.setCurrentTask(newRunningTaskId);
sharedState.setRecentsAnimationFinishInterrupted(newRunningTaskId);
mGestureState.setFinishingRecentsAnimationTaskId(newRunningTaskId);
}
}
@ -1160,7 +1134,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
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;

View File

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

View File

@ -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);
}

View File

@ -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<GestureEndTarget, EndTargetAnimationParams>
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);

View File

@ -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<OtherActivityInputConsumer> 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;

View File

@ -42,7 +42,6 @@ public class ResetGestureInputConsumer implements InputConsumer {
if (ev.getAction() == MotionEvent.ACTION_DOWN
&& mTaskAnimationManager.isRecentsAnimationRunning()) {
mTaskAnimationManager.finishRunningRecentsAnimation(false /* toHome */);
TouchInteractionService.getSwipeSharedState().clearAllState();
}
}
}

View File

@ -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<String> 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 <T extends BaseDraggingActivity> BaseActivityInterface<T> 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);
}
}

View File

@ -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() { }

View File

@ -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;
}