Merge "Reducing the time for expected launcher initialization back to 10 sec" into ub-launcher3-master
diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
index f2aa842..d5ea1ec 100644
--- a/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
+++ b/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
@@ -88,6 +88,4 @@
public static RotationMode getRotationMode(DeviceProfile dp) {
return RotationMode.NORMAL;
}
-
- public static void clearSwipeSharedState(Launcher launcher, boolean finishAnimation) { }
}
diff --git a/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
index 6b50088..04753d2 100644
--- a/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
+++ b/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
@@ -46,13 +46,13 @@
RemoteAnimationProvider {
private static final String TAG = "AppToOverviewAnimationProvider";
- private final BaseActivityInterface<T> mHelper;
+ private final BaseActivityInterface<T> mActivityInterface;
private final int mTargetTaskId;
private IconRecentsView mRecentsView;
private AppToOverviewAnimationListener mAnimationReadyListener;
- AppToOverviewAnimationProvider(BaseActivityInterface<T> helper, int targetTaskId) {
- mHelper = helper;
+ AppToOverviewAnimationProvider(BaseActivityInterface<T> activityInterface, int targetTaskId) {
+ mActivityInterface = activityInterface;
mTargetTaskId = targetTaskId;
}
@@ -68,15 +68,15 @@
/**
* Callback for when the activity is ready/initialized.
*
- * @param activity the activity that is ready
* @param wasVisible true if it was visible before
*/
- boolean onActivityReady(T activity, Boolean wasVisible) {
+ boolean onActivityReady(Boolean wasVisible) {
+ T activity = mActivityInterface.getCreatedActivity();
if (mAnimationReadyListener != null) {
mAnimationReadyListener.onActivityReady(activity);
}
BaseActivityInterface.AnimationFactory factory =
- mHelper.prepareRecentsUI(activity, wasVisible,
+ mActivityInterface.prepareRecentsUI(wasVisible,
false /* animate activity */, (controller) -> {
controller.dispatchOnStart();
ValueAnimator anim = controller.getAnimationPlayer()
diff --git a/go/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/go/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index 2af8441..ecb9472 100644
--- a/go/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/go/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -29,8 +29,8 @@
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.views.IconRecentsView;
-import java.util.function.BiPredicate;
import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* {@link BaseActivityInterface} for recents when the default launcher is different than the
@@ -43,12 +43,13 @@
public FallbackActivityInterface() { }
@Override
- public AnimationFactory prepareRecentsUI(RecentsActivity activity, boolean activityVisible,
+ public AnimationFactory prepareRecentsUI(boolean activityVisible,
boolean animateActivity, Consumer<AnimatorPlaybackController> callback) {
if (activityVisible) {
return (transitionLength) -> { };
}
+ RecentsActivity activity = getCreatedActivity();
IconRecentsView rv = activity.getOverviewPanel();
rv.setUsingRemoteAnimation(true);
rv.setAlpha(0);
@@ -84,8 +85,9 @@
@Override
public ActivityInitListener createActivityInitListener(
- BiPredicate<RecentsActivity, Boolean> onInitListener) {
- return new ActivityInitListener(onInitListener, RecentsActivity.ACTIVITY_TRACKER);
+ Predicate<Boolean> onInitListener) {
+ return new ActivityInitListener<>((activity, alreadyOnHome) ->
+ onInitListener.test(alreadyOnHome), RecentsActivity.ACTIVITY_TRACKER);
}
@Nullable
@@ -115,5 +117,5 @@
}
@Override
- public void onLaunchTaskSuccess(RecentsActivity activity) { }
+ public void onLaunchTaskSuccess() { }
}
diff --git a/go/quickstep/src/com/android/quickstep/GoActivityInterface.java b/go/quickstep/src/com/android/quickstep/GoActivityInterface.java
index 5ce0f4c..b62d17c 100644
--- a/go/quickstep/src/com/android/quickstep/GoActivityInterface.java
+++ b/go/quickstep/src/com/android/quickstep/GoActivityInterface.java
@@ -17,7 +17,7 @@
BaseActivityInterface<T> {
@Override
- public void onTransitionCancelled(T activity, boolean activityVisible) {
+ public void onTransitionCancelled(boolean activityVisible) {
// Go transitions to overview are all atomic.
}
@@ -29,7 +29,7 @@
}
@Override
- public void onSwipeUpToRecentsComplete(T activity) {
+ public void onSwipeUpToRecentsComplete() {
// Go does not support swipe up gesture.
}
@@ -39,7 +39,7 @@
}
@Override
- public HomeAnimationFactory prepareHomeUI(T activity) {
+ public HomeAnimationFactory prepareHomeUI() {
// Go does not support gestures from app to home.
return null;
}
@@ -63,7 +63,7 @@
}
@Override
- public void onLaunchTaskFailed(T activity) {
+ public void onLaunchTaskFailed() {
// Go does not support gestures from one task to another.
}
}
diff --git a/go/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/go/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 5bff8e8..3e93480 100644
--- a/go/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/go/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -26,8 +26,8 @@
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.views.IconRecentsView;
-import java.util.function.BiPredicate;
import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* {@link BaseActivityInterface} for the in-launcher recents.
@@ -36,15 +36,15 @@
public final class LauncherActivityInterface extends GoActivityInterface<Launcher> {
@Override
- public AnimationFactory prepareRecentsUI(Launcher activity,
- boolean activityVisible, boolean animateActivity,
+ public AnimationFactory prepareRecentsUI(boolean activityVisible, boolean animateActivity,
Consumer<AnimatorPlaybackController> callback) {
- LauncherState fromState = activity.getStateManager().getState();
- activity.<IconRecentsView>getOverviewPanel().setUsingRemoteAnimation(true);
+ Launcher launcher = getCreatedActivity();
+ LauncherState fromState = launcher.getStateManager().getState();
+ launcher.<IconRecentsView>getOverviewPanel().setUsingRemoteAnimation(true);
//TODO: Implement this based off where the recents view needs to be for app => recents anim.
return new AnimationFactory() {
public void createActivityInterface(long transitionLength) {
- callback.accept(activity.getStateManager().createAnimationToNewWorkspace(
+ callback.accept(launcher.getStateManager().createAnimationToNewWorkspace(
fromState, OVERVIEW, transitionLength));
}
@@ -54,9 +54,9 @@
}
@Override
- public LauncherInitListener createActivityInitListener(
- BiPredicate<Launcher, Boolean> onInitListener) {
- return new LauncherInitListener(onInitListener);
+ public LauncherInitListener createActivityInitListener(Predicate<Boolean> onInitListener) {
+ return new LauncherInitListener((activity, alreadyOnHome) ->
+ onInitListener.test(alreadyOnHome));
}
@Override
@@ -105,7 +105,8 @@
}
@Override
- public void onLaunchTaskSuccess(Launcher launcher) {
+ public void onLaunchTaskSuccess() {
+ Launcher launcher = getCreatedActivity();
launcher.getStateManager().moveToRestState();
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
index ff73679..2a22e9d 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
@@ -18,7 +18,6 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import android.content.Context;
@@ -45,7 +44,6 @@
import com.android.launcher3.util.UiThreadHelper.AsyncCommand;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
-import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.views.RecentsView;
@@ -188,17 +186,6 @@
return new RecentsViewStateController(launcher);
}
- /** Clears the swipe shared state for the current swipe gesture. */
- public static void clearSwipeSharedState(Launcher launcher, boolean finishAnimation) {
- if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
- launcher.<RecentsView>getOverviewPanel().switchToScreenshot(
- () -> TouchInteractionService.getSwipeSharedState().clearAllState(
- finishAnimation));
- } else {
- TouchInteractionService.getSwipeSharedState().clearAllState(finishAnimation);
- }
- }
-
/**
* Recents logic that triggers when launcher state changes or launcher activity stops/resumes.
*
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 6c9f46f..1279270 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 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/AppToOverviewAnimationProvider.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
index 8a11ac8..59b117f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java
@@ -70,7 +70,7 @@
activity.<RecentsView>getOverviewPanel().showCurrentTask(mTargetTaskId);
AbstractFloatingView.closeAllOpenViews(activity, wasVisible);
BaseActivityInterface.AnimationFactory factory =
- mHelper.prepareRecentsUI(activity, wasVisible,
+ mHelper.prepareRecentsUI(wasVisible,
false /* animate activity */, (controller) -> {
controller.dispatchOnStart();
ValueAnimator anim = controller.getAnimationPlayer()
@@ -102,7 +102,7 @@
anim.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
- mHelper.onSwipeUpToRecentsComplete(mActivity);
+ mHelper.onSwipeUpToRecentsComplete();
if (mRecentsView != null) {
mRecentsView.animateUpRunningTaskIconScale();
}
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 e1e994c..939656e 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 @@
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;
@@ -129,7 +130,6 @@
protected Runnable mGestureEndCallback;
- protected final Handler mMainThreadHandler = MAIN_EXECUTOR.getHandler();
protected MultiStateCallback mStateCallback;
protected boolean mCanceled;
@@ -139,6 +139,7 @@
OverviewComponentObserver overviewComponentObserver,
RecentsModel recentsModel, InputConsumerController inputConsumer, int runningTaskId) {
mContext = context;
+ mGestureState = gestureState;
mOverviewComponentObserver = overviewComponentObserver;
mActivityInterface = gestureState.getActivityInterface();
mRecentsModel = recentsModel;
@@ -155,14 +156,6 @@
.getDeviceProfile(mContext));
}
- protected void setStateOnUiThread(int stateFlag) {
- if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
- mStateCallback.setState(stateFlag);
- } else {
- postAsyncCallback(mMainThreadHandler, () -> mStateCallback.setState(stateFlag));
- }
- }
-
protected void performHapticFeedback() {
if (!mVibrator.hasVibrator()) {
return;
@@ -246,14 +239,14 @@
success -> {
resultCallback.accept(success);
if (!success) {
- mActivityInterface.onLaunchTaskFailed(mActivity);
+ mActivityInterface.onLaunchTaskFailed();
nextTask.notifyTaskLaunchFailed(TAG);
} else {
- mActivityInterface.onLaunchTaskSuccess(mActivity);
+ mActivityInterface.onLaunchTaskSuccess();
}
- }, mMainThreadHandler);
+ }, MAIN_EXECUTOR.getHandler());
}
- setStateOnUiThread(successStateFlag);
+ mStateCallback.setStateOnUiThread(successStateFlag);
}
mCanceled = false;
mFinishingRecentsAnimationForNewTaskId = -1;
@@ -366,7 +359,7 @@
*/
protected abstract boolean moveWindowWithRecentsScroll();
- protected abstract boolean onActivityInit(final T activity, Boolean alreadyOnHome);
+ protected abstract boolean onActivityInit(Boolean alreadyOnHome);
/**
* Called to create a input proxy for the running task
@@ -394,7 +387,7 @@
@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) { }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
index 8deb835..3d1ecef 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
@@ -30,6 +30,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
@@ -40,8 +41,8 @@
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import java.util.function.BiPredicate;
import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* {@link BaseActivityInterface} for recents when the default launcher is different than the
@@ -54,7 +55,7 @@
public FallbackActivityInterface() { }
@Override
- public void onTransitionCancelled(RecentsActivity activity, boolean activityVisible) {
+ public void onTransitionCancelled(boolean activityVisible) {
// TODO:
}
@@ -72,7 +73,8 @@
}
@Override
- public void onSwipeUpToRecentsComplete(RecentsActivity activity) {
+ public void onSwipeUpToRecentsComplete() {
+ RecentsActivity activity = getCreatedActivity();
RecentsView recentsView = activity.getOverviewPanel();
recentsView.getClearAllButton().setVisibilityAlpha(1);
recentsView.setDisallowScrollToClearAll(false);
@@ -87,7 +89,8 @@
@NonNull
@Override
- public HomeAnimationFactory prepareHomeUI(RecentsActivity activity) {
+ public HomeAnimationFactory prepareHomeUI() {
+ RecentsActivity activity = getCreatedActivity();
RecentsView recentsView = activity.getOverviewPanel();
return new HomeAnimationFactory() {
@@ -118,8 +121,9 @@
}
@Override
- public AnimationFactory prepareRecentsUI(RecentsActivity activity, boolean activityVisible,
+ public AnimationFactory prepareRecentsUI(boolean activityVisible,
boolean animateActivity, Consumer<AnimatorPlaybackController> callback) {
+ RecentsActivity activity = getCreatedActivity();
if (activityVisible) {
return (transitionLength) -> { };
}
@@ -176,8 +180,9 @@
@Override
public ActivityInitListener createActivityInitListener(
- BiPredicate<RecentsActivity, Boolean> onInitListener) {
- return new ActivityInitListener(onInitListener, RecentsActivity.ACTIVITY_TRACKER);
+ Predicate<Boolean> onInitListener) {
+ return new ActivityInitListener<>((activity, alreadyOnHome) ->
+ onInitListener.test(alreadyOnHome), RecentsActivity.ACTIVITY_TRACKER);
}
@Nullable
@@ -228,13 +233,15 @@
}
@Override
- public void onLaunchTaskFailed(RecentsActivity activity) {
+ public void onLaunchTaskFailed() {
// TODO: probably go back to overview instead.
+ RecentsActivity activity = getCreatedActivity();
activity.<RecentsView>getOverviewPanel().startHome();
}
@Override
- public void onLaunchTaskSuccess(RecentsActivity activity) {
+ public void onLaunchTaskSuccess() {
+ RecentsActivity activity = getCreatedActivity();
activity.onTaskLaunched();
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
index f6b3654..87db83d 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
@@ -69,8 +69,8 @@
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import java.util.function.BiPredicate;
import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* {@link BaseActivityInterface} for the in-launcher recents.
@@ -92,23 +92,26 @@
}
@Override
- public void onTransitionCancelled(Launcher activity, boolean activityVisible) {
- LauncherState startState = activity.getStateManager().getRestState();
- activity.getStateManager().goToState(startState, activityVisible);
+ public void onTransitionCancelled(boolean activityVisible) {
+ Launcher launcher = getCreatedActivity();
+ LauncherState startState = launcher.getStateManager().getRestState();
+ launcher.getStateManager().goToState(startState, activityVisible);
}
@Override
- public void onSwipeUpToRecentsComplete(Launcher activity) {
+ public void onSwipeUpToRecentsComplete() {
// Re apply state in case we did something funky during the transition.
- activity.getStateManager().reapplyState();
- DiscoveryBounce.showForOverviewIfNeeded(activity);
+ Launcher launcher = getCreatedActivity();
+ launcher.getStateManager().reapplyState();
+ DiscoveryBounce.showForOverviewIfNeeded(launcher);
}
@Override
- public void onSwipeUpToHomeComplete(Launcher activity) {
+ public void onSwipeUpToHomeComplete() {
// Ensure recents is at the correct position for NORMAL state. For example, when we detach
// recents, we assume the first task is invisible, making translation off by one task.
- activity.getStateManager().reapplyState();
+ Launcher launcher = getCreatedActivity();
+ launcher.getStateManager().reapplyState();
setLauncherHideBackArrow(false);
}
@@ -129,13 +132,14 @@
@NonNull
@Override
- public HomeAnimationFactory prepareHomeUI(Launcher activity) {
- final DeviceProfile dp = activity.getDeviceProfile();
- final RecentsView recentsView = activity.getOverviewPanel();
+ public HomeAnimationFactory prepareHomeUI() {
+ Launcher launcher = getCreatedActivity();
+ final DeviceProfile dp = launcher.getDeviceProfile();
+ final RecentsView recentsView = launcher.getOverviewPanel();
final TaskView runningTaskView = recentsView.getRunningTaskView();
final View workspaceView;
if (runningTaskView != null && runningTaskView.getTask().key.getComponent() != null) {
- workspaceView = activity.getWorkspace().getFirstMatchForAppClose(
+ workspaceView = launcher.getWorkspace().getFirstMatchForAppClose(
runningTaskView.getTask().key.getComponent().getPackageName(),
UserHandle.of(runningTaskView.getTask().key.userId));
} else {
@@ -144,7 +148,7 @@
final RectF iconLocation = new RectF();
boolean canUseWorkspaceView = workspaceView != null && workspaceView.isAttachedToWindow();
FloatingIconView floatingIconView = canUseWorkspaceView
- ? FloatingIconView.getFloatingIconView(activity, workspaceView,
+ ? FloatingIconView.getFloatingIconView(launcher, workspaceView,
true /* hideOriginal */, iconLocation, false /* isOpening */)
: null;
setLauncherHideBackArrow(true);
@@ -170,14 +174,14 @@
public AnimatorPlaybackController createActivityAnimationToHome() {
// Return an empty APC here since we have an non-user controlled animation to home.
long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
- return activity.getStateManager().createAnimationToNewWorkspace(NORMAL, accuracy,
+ return launcher.getStateManager().createAnimationToNewWorkspace(NORMAL, accuracy,
0 /* animComponents */);
}
@Override
public void playAtomicAnimation(float velocity) {
// Setup workspace with 0 duration to prepare for our staggered animation.
- LauncherStateManager stateManager = activity.getStateManager();
+ LauncherStateManager stateManager = launcher.getStateManager();
AnimatorSetBuilder builder = new AnimatorSetBuilder();
// setRecentsAttachedToAppWindow() will animate recents out.
builder.addFlag(AnimatorSetBuilder.FLAG_DONT_ANIMATE_OVERVIEW);
@@ -187,27 +191,28 @@
// Stop scrolling so that it doesn't interfere with the translation offscreen.
recentsView.getScroller().forceFinished(true);
- new StaggeredWorkspaceAnim(activity, workspaceView, velocity).start();
+ new StaggeredWorkspaceAnim(launcher, workspaceView, velocity).start();
}
};
}
@Override
- public AnimationFactory prepareRecentsUI(Launcher activity, boolean activityVisible,
+ public AnimationFactory prepareRecentsUI(boolean activityVisible,
boolean animateActivity, Consumer<AnimatorPlaybackController> callback) {
- final LauncherState startState = activity.getStateManager().getState();
+ Launcher launcher = getCreatedActivity();
+ final LauncherState startState = launcher.getStateManager().getState();
LauncherState resetState = startState;
if (startState.disableRestore) {
- resetState = activity.getStateManager().getRestState();
+ resetState = launcher.getStateManager().getRestState();
}
- activity.getStateManager().setRestState(resetState);
+ launcher.getStateManager().setRestState(resetState);
final LauncherState fromState = animateActivity ? BACKGROUND_APP : OVERVIEW;
- activity.getStateManager().goToState(fromState, false);
+ launcher.getStateManager().goToState(fromState, false);
// Since all apps is not visible, we can safely reset the scroll position.
// This ensures then the next swipe up to all-apps starts from scroll 0.
- activity.getAppsView().reset(false /* animate */);
+ launcher.getAppsView().reset(false /* animate */);
return new AnimationFactory() {
private ShelfAnimState mShelfState;
@@ -215,11 +220,11 @@
@Override
public void createActivityInterface(long transitionLength) {
- createActivityInterfaceInternal(activity, fromState, transitionLength, callback);
+ createActivityInterfaceInternal(launcher, fromState, transitionLength, callback);
// Creating the activity controller animation sometimes reapplies the launcher state
// (because we set the animation as the current state animation), so we reapply the
// attached state here as well to ensure recents is shown/hidden appropriately.
- if (SysUINavigationMode.getMode(activity) == Mode.NO_BUTTON) {
+ if (SysUINavigationMode.getMode(launcher) == Mode.NO_BUTTON) {
setRecentsAttachedToAppWindow(mIsAttachedToWindow, false);
}
}
@@ -233,7 +238,7 @@
@Override
public void onTransitionCancelled() {
- activity.getStateManager().goToState(startState, false /* animate */);
+ launcher.getStateManager().goToState(startState, false /* animate */);
}
@Override
@@ -243,15 +248,15 @@
return;
}
mShelfState = shelfState;
- activity.getStateManager().cancelStateElementAnimation(INDEX_SHELF_ANIM);
+ launcher.getStateManager().cancelStateElementAnimation(INDEX_SHELF_ANIM);
if (mShelfState == ShelfAnimState.CANCEL) {
return;
}
- float shelfHiddenProgress = BACKGROUND_APP.getVerticalProgress(activity);
- float shelfOverviewProgress = OVERVIEW.getVerticalProgress(activity);
+ float shelfHiddenProgress = BACKGROUND_APP.getVerticalProgress(launcher);
+ float shelfOverviewProgress = OVERVIEW.getVerticalProgress(launcher);
// Peek based on default overview progress so we can see hotseat if we're showing
// that instead of predictions in overview.
- float defaultOverviewProgress = OverviewState.getDefaultVerticalProgress(activity);
+ float defaultOverviewProgress = OverviewState.getDefaultVerticalProgress(launcher);
float shelfPeekingProgress = shelfHiddenProgress
- (shelfHiddenProgress - defaultOverviewProgress) * 0.25f;
float toProgress = mShelfState == ShelfAnimState.HIDE
@@ -259,7 +264,7 @@
: mShelfState == ShelfAnimState.PEEK
? shelfPeekingProgress
: shelfOverviewProgress;
- Animator shelfAnim = activity.getStateManager()
+ Animator shelfAnim = launcher.getStateManager()
.createStateElementAnimation(INDEX_SHELF_ANIM, toProgress);
shelfAnim.setInterpolator(interpolator);
shelfAnim.setDuration(duration).start();
@@ -271,8 +276,8 @@
return;
}
mIsAttachedToWindow = attached;
- LauncherRecentsView recentsView = activity.getOverviewPanel();
- Animator fadeAnim = activity.getStateManager()
+ LauncherRecentsView recentsView = launcher.getOverviewPanel();
+ Animator fadeAnim = launcher.getStateManager()
.createStateElementAnimation(
INDEX_RECENTS_FADE_ANIM, attached ? 1 : 0);
@@ -286,7 +291,7 @@
float fromTranslationX = attached ? offscreenX - scrollOffsetX : 0;
float toTranslationX = attached ? 0 : offscreenX - scrollOffsetX;
- activity.getStateManager()
+ launcher.getStateManager()
.cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM);
if (!recentsView.isShown() && animate) {
@@ -298,7 +303,7 @@
if (!animate) {
recentsView.setTranslationX(toTranslationX);
} else {
- activity.getStateManager().createStateElementAnimation(
+ launcher.getStateManager().createStateElementAnimation(
INDEX_RECENTS_TRANSLATE_X_ANIM,
fromTranslationX, toTranslationX).start();
}
@@ -396,9 +401,9 @@
}
@Override
- public ActivityInitListener createActivityInitListener(
- BiPredicate<Launcher, Boolean> onInitListener) {
- return new LauncherInitListenerEx(onInitListener);
+ public ActivityInitListener createActivityInitListener(Predicate<Boolean> onInitListener) {
+ return new LauncherInitListenerEx((activity, alreadyOnHome) ->
+ onInitListener.test(alreadyOnHome));
}
@Nullable
@@ -469,12 +474,14 @@
}
@Override
- public void onLaunchTaskFailed(Launcher launcher) {
+ public void onLaunchTaskFailed() {
+ Launcher launcher = getCreatedActivity();
launcher.getStateManager().goToState(OVERVIEW);
}
@Override
- public void onLaunchTaskSuccess(Launcher launcher) {
+ public void onLaunchTaskSuccess() {
+ Launcher launcher = getCreatedActivity();
launcher.getStateManager().moveToRestState();
}
@@ -493,22 +500,21 @@
}
@Override
- public void switchToScreenshot(ThumbnailData thumbnailData, Runnable runnable) {
+ public void switchRunningTaskViewToScreenshot(ThumbnailData thumbnailData,
+ Runnable onFinishRunnable) {
Launcher launcher = getCreatedActivity();
RecentsView recentsView = launcher.getOverviewPanel();
if (recentsView == null) {
- if (runnable != null) {
- runnable.run();
+ if (onFinishRunnable != null) {
+ onFinishRunnable.run();
}
return;
}
- TaskView taskView = recentsView.getRunningTaskView();
- if (taskView != null) {
- taskView.setShowScreenshot(true);
- taskView.getThumbnail().setThumbnail(taskView.getTask(), thumbnailData);
- ViewUtils.postDraw(taskView, runnable);
- } else if (runnable != null) {
- runnable.run();
- }
+ recentsView.switchToScreenshot(thumbnailData, onFinishRunnable);
+ }
+
+ @Override
+ public void setOnDeferredActivityLaunchCallback(Runnable r) {
+ getCreatedActivity().setOnDeferredActivityLaunchCallback(r);
}
}
\ No newline at end of file
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/MultiStateCallback.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/MultiStateCallback.java
deleted file mode 100644
index 357c9fc..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/MultiStateCallback.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2017 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 android.util.Log;
-import android.util.SparseArray;
-
-import com.android.launcher3.config.FeatureFlags;
-
-import java.util.StringJoiner;
-import java.util.function.Consumer;
-
-/**
- * Utility class to help manage multiple callbacks based on different states.
- */
-public class MultiStateCallback {
-
- private static final String TAG = "MultiStateCallback";
- public static final boolean DEBUG_STATES = false;
-
- private final SparseArray<Runnable> mCallbacks = new SparseArray<>();
- private final SparseArray<Consumer<Boolean>> mStateChangeHandlers = new SparseArray<>();
-
- private final String[] mStateNames;
-
- public MultiStateCallback(String[] stateNames) {
- mStateNames = DEBUG_STATES ? stateNames : null;
- }
-
- private int mState = 0;
-
- /**
- * Adds the provided state flags to the global state and executes any callbacks as a result.
- */
- public void setState(int stateFlag) {
- if (DEBUG_STATES) {
- Log.d(TAG, "[" + System.identityHashCode(this) + "] Adding "
- + convertToFlagNames(stateFlag) + " to " + convertToFlagNames(mState));
- }
-
- int oldState = mState;
- mState = mState | stateFlag;
-
- int count = mCallbacks.size();
- for (int i = 0; i < count; i++) {
- int state = mCallbacks.keyAt(i);
-
- if ((mState & state) == state) {
- Runnable callback = mCallbacks.valueAt(i);
- if (callback != null) {
- // Set the callback to null, so that it does not run again.
- mCallbacks.setValueAt(i, null);
- callback.run();
- }
- }
- }
- notifyStateChangeHandlers(oldState);
- }
-
- /**
- * Adds the provided state flags to the global state and executes any change handlers
- * as a result.
- */
- public void clearState(int stateFlag) {
- if (DEBUG_STATES) {
- Log.d(TAG, "[" + System.identityHashCode(this) + "] Removing "
- + convertToFlagNames(stateFlag) + " from " + convertToFlagNames(mState));
- }
-
- int oldState = mState;
- mState = mState & ~stateFlag;
- notifyStateChangeHandlers(oldState);
- }
-
- private void notifyStateChangeHandlers(int oldState) {
- int count = mStateChangeHandlers.size();
- for (int i = 0; i < count; i++) {
- int state = mStateChangeHandlers.keyAt(i);
- boolean wasOn = (state & oldState) == state;
- boolean isOn = (state & mState) == state;
-
- if (wasOn != isOn) {
- mStateChangeHandlers.valueAt(i).accept(isOn);
- }
- }
- }
-
- /**
- * Sets the callbacks to be run when the provided states are enabled.
- * The callback is only run once.
- */
- public void addCallback(int stateMask, Runnable callback) {
- if (FeatureFlags.IS_DOGFOOD_BUILD && mCallbacks.get(stateMask) != null) {
- throw new IllegalStateException("Multiple callbacks on same state");
- }
- mCallbacks.put(stateMask, callback);
- }
-
- /**
- * Sets the handler to be called when the provided states are enabled or disabled.
- */
- public void addChangeHandler(int stateMask, Consumer<Boolean> handler) {
- mStateChangeHandlers.put(stateMask, handler);
- }
-
- public int getState() {
- return mState;
- }
-
- public boolean hasStates(int stateMask) {
- return (mState & stateMask) == stateMask;
- }
-
- private String convertToFlagNames(int flags) {
- StringJoiner joiner = new StringJoiner(", ", "[", " (" + flags + ")]");
- for (int i = 0; i < mStateNames.length; i++) {
- if ((flags & (1 << i)) != 0) {
- joiner.add(mStateNames[i]);
- }
- }
- return joiner.toString();
- }
-
-}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java
index 150c44d..7f53d83 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java
@@ -203,7 +203,8 @@
return false;
}
- private boolean onActivityReady(T activity, Boolean wasVisible) {
+ private boolean onActivityReady(Boolean wasVisible) {
+ final T activity = mActivityInterface.getCreatedActivity();
if (!mUserEventLogged) {
activity.getUserEventDispatcher().logActionCommand(
LauncherLogProto.Action.Command.RECENTS_BUTTON,
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java
deleted file mode 100644
index cd8e1a4..0000000
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/SwipeSharedState.java
+++ /dev/null
@@ -1,183 +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 static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-
-import android.util.Log;
-
-import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.util.Preconditions;
-import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
-
-import com.android.systemui.shared.recents.model.ThumbnailData;
-
-import java.io.PrintWriter;
-
-/**
- * Utility class used to store state information shared across multiple transitions.
- */
-public class SwipeSharedState implements RecentsAnimationListener {
-
- private OverviewComponentObserver mOverviewComponentObserver;
-
- private RecentsAnimationCallbacks mRecentsAnimationListener;
- private RecentsAnimationController mLastRecentsAnimationController;
- private RecentsAnimationTargets mLastAnimationTarget;
-
- private boolean mLastAnimationCancelled = false;
- private boolean mLastAnimationRunning = false;
-
- public boolean canGestureBeContinued;
- public boolean goingToLauncher;
- public boolean recentsAnimationFinishInterrupted;
- public int nextRunningTaskId = -1;
- private int mLogId;
-
- public void setOverviewComponentObserver(OverviewComponentObserver observer) {
- mOverviewComponentObserver = observer;
- }
-
- @Override
- public final void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targets) {
- mLastRecentsAnimationController = controller;
- mLastAnimationTarget = targets;
-
- mLastAnimationCancelled = false;
- mLastAnimationRunning = true;
- }
-
- @Override
- public final void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
- if (thumbnailData != null) {
- mOverviewComponentObserver.getActivityInterface().switchToScreenshot(thumbnailData,
- () -> {
- mLastRecentsAnimationController.cleanupScreenshot();
- clearAnimationState();
- });
- } else {
- clearAnimationState();
- }
- }
-
- @Override
- public final void onRecentsAnimationFinished(RecentsAnimationController controller) {
- if (mLastRecentsAnimationController == controller) {
- mLastAnimationRunning = false;
- }
- }
-
- private void clearAnimationTarget() {
- if (mLastAnimationTarget != null) {
- mLastAnimationTarget.release();
- mLastAnimationTarget = null;
- }
- }
-
- private void clearAnimationState() {
- clearAnimationTarget();
-
- mLastAnimationCancelled = true;
- mLastAnimationRunning = false;
- }
-
- private void clearListenerState(boolean finishAnimation) {
- if (mRecentsAnimationListener != null) {
- mRecentsAnimationListener.removeListener(this);
- mRecentsAnimationListener.notifyAnimationCanceled();
- if (mLastAnimationRunning && mLastRecentsAnimationController != null) {
- Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(),
- finishAnimation
- ? mLastRecentsAnimationController::finishAnimationToHome
- : mLastRecentsAnimationController::finishAnimationToApp);
- mLastRecentsAnimationController = null;
- mLastAnimationTarget = null;
- }
- }
- mRecentsAnimationListener = null;
- clearAnimationTarget();
- mLastAnimationCancelled = false;
- mLastAnimationRunning = false;
- }
-
- public RecentsAnimationCallbacks newRecentsAnimationCallbacks() {
- Preconditions.assertUIThread();
-
- if (mLastAnimationRunning) {
- String msg = "New animation started before completing old animation";
- if (FeatureFlags.IS_DOGFOOD_BUILD) {
- throw new IllegalArgumentException(msg);
- } else {
- Log.e("SwipeSharedState", msg, new Exception());
- }
- }
-
- clearListenerState(false /* finishAnimation */);
- boolean shouldMinimiseSplitScreen = mOverviewComponentObserver == null ? false
- : mOverviewComponentObserver.getActivityInterface().shouldMinimizeSplitScreen();
- mRecentsAnimationListener = new RecentsAnimationCallbacks(shouldMinimiseSplitScreen);
- mRecentsAnimationListener.addListener(this);
- return mRecentsAnimationListener;
- }
-
- public RecentsAnimationCallbacks getActiveListener() {
- return mRecentsAnimationListener;
- }
-
- public void applyActiveRecentsAnimationState(RecentsAnimationListener listener) {
- if (mLastRecentsAnimationController != null) {
- listener.onRecentsAnimationStart(mLastRecentsAnimationController,
- mLastAnimationTarget);
- } else if (mLastAnimationCancelled) {
- listener.onRecentsAnimationCanceled(null);
- }
- }
-
- /**
- * 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;
- mLastAnimationTarget = mLastAnimationTarget.cloneWithoutTargets();
- }
-
- public void clearAllState(boolean finishAnimation) {
- clearListenerState(finishAnimation);
- 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 + "lastAnimationCancelled=" + mLastAnimationCancelled);
- pw.println(prefix + "lastAnimationRunning=" + mLastAnimationRunning);
- pw.println(prefix + "logTraceId=" + mLogId);
- }
-
- public void setLogTraceId(int logId) {
- this.mLogId = logId;
- }
-}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 0eafb44..e3fcd2f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -129,10 +129,11 @@
public void onInitialize(Bundle bundle) {
ISystemUiProxy proxy = ISystemUiProxy.Stub.asInterface(
bundle.getBinder(KEY_EXTRA_SYSUI_PROXY));
- MAIN_EXECUTOR.execute(() -> SystemUiProxy.INSTANCE.get(TouchInteractionService.this)
- .setProxy(proxy));
- MAIN_EXECUTOR.execute(TouchInteractionService.this::initInputMonitor);
- MAIN_EXECUTOR.execute(() -> preloadOverview(true /* fromInit */));
+ MAIN_EXECUTOR.execute(() -> {
+ SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy);
+ TouchInteractionService.this.initInputMonitor();
+ preloadOverview(true /* fromInit */);
+ });
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.LAUNCHER_DIDNT_INITIALIZE, "TIS initialized");
}
@@ -169,15 +170,19 @@
@BinderThread
@Override
public void onAssistantAvailable(boolean available) {
- MAIN_EXECUTOR.execute(() -> mDeviceState.setAssistantAvailable(available));
- MAIN_EXECUTOR.execute(TouchInteractionService.this::onAssistantVisibilityChanged);
+ MAIN_EXECUTOR.execute(() -> {
+ mDeviceState.setAssistantAvailable(available);
+ TouchInteractionService.this.onAssistantVisibilityChanged();
+ });
}
@BinderThread
@Override
public void onAssistantVisibilityChanged(float visibility) {
- MAIN_EXECUTOR.execute(() -> mDeviceState.setAssistantVisibility(visibility));
- MAIN_EXECUTOR.execute(TouchInteractionService.this::onAssistantVisibilityChanged);
+ MAIN_EXECUTOR.execute(() -> {
+ mDeviceState.setAssistantVisibility(visibility);
+ TouchInteractionService.this.onAssistantVisibilityChanged();
+ });
}
@BinderThread
@@ -199,8 +204,10 @@
@BinderThread
public void onSystemUiStateChanged(int stateFlags) {
- MAIN_EXECUTOR.execute(() -> mDeviceState.setSystemUiFlags(stateFlags));
- MAIN_EXECUTOR.execute(TouchInteractionService.this::onSystemUiFlagsChanged);
+ MAIN_EXECUTOR.execute(() -> {
+ mDeviceState.setSystemUiFlags(stateFlags);
+ TouchInteractionService.this.onSystemUiFlagsChanged();
+ });
}
@BinderThread
@@ -228,8 +235,6 @@
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;
@@ -239,14 +244,7 @@
return sIsInitialized;
}
- public static SwipeSharedState getSwipeSharedState() {
- return sSwipeSharedState;
- }
-
- private final InputConsumer mResetGestureInputConsumer =
- new ResetGestureInputConsumer(sSwipeSharedState);
-
- private final BaseSwipeUpHandler.Factory mWindowTreansformFactory =
+ private final BaseSwipeUpHandler.Factory mWindowTransformFactory =
this::createWindowTransformSwipeHandler;
private final BaseSwipeUpHandler.Factory mFallbackNoButtonFactory =
this::createFallbackNoButtonSwipeHandler;
@@ -257,10 +255,13 @@
private OverviewComponentObserver mOverviewComponentObserver;
private InputConsumerController mInputConsumer;
private RecentsAnimationDeviceState mDeviceState;
+ private TaskAnimationManager mTaskAnimationManager;
private InputConsumer mUncheckedConsumer = InputConsumer.NO_OP;
private InputConsumer mConsumer = InputConsumer.NO_OP;
private Choreographer mMainChoreographer;
+ private InputConsumer mResetGestureInputConsumer;
+ private GestureState mGestureState = new GestureState();
private InputMonitorCompat mInputMonitorCompat;
private InputEventReceiver mInputEventReceiver;
@@ -331,13 +332,13 @@
@UiThread
public void onUserUnlocked() {
+ mTaskAnimationManager = new TaskAnimationManager();
mRecentsModel = RecentsModel.INSTANCE.get(this);
mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState);
mOverviewCommandHelper = new OverviewCommandHelper(this, mDeviceState,
mOverviewComponentObserver);
+ mResetGestureInputConsumer = new ResetGestureInputConsumer(mTaskAnimationManager);
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
-
- sSwipeSharedState.setOverviewComponentObserver(mOverviewComponentObserver);
mInputConsumer.registerInputConsumer();
onSystemUiFlagsChanged();
onAssistantVisibilityChanged();
@@ -349,6 +350,17 @@
resetHomeBounceSeenOnQuickstepEnabledFirstTime();
}
+ private void onDeferredActivityLaunch() {
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ mOverviewComponentObserver.getActivityInterface().switchRunningTaskViewToScreenshot(
+ null, () -> {
+ mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */);
+ });
+ } else {
+ mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */);
+ }
+ }
+
private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() {
if (!mDeviceState.isUserUnlocked() || !mMode.hasGestures) {
// Skip if not yet unlocked (can't read user shared prefs) or if the current navigation
@@ -422,15 +434,13 @@
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
@@ -443,6 +453,9 @@
} else {
mUncheckedConsumer = InputConsumer.NO_OP;
}
+
+ // Save the current gesture state
+ mGestureState = newGestureState;
}
ActiveGestureLog.INSTANCE.addLog("onMotionEvent", event.getActionMasked());
@@ -450,39 +463,42 @@
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()) {
@@ -497,13 +513,10 @@
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) {
- sSwipeSharedState.clearAllState(false /* finishAnimation */);
- }
if (mDeviceState.isKeyguardShowingOccluded()) {
// This handles apps showing over the lockscreen (e.g. camera)
return createDeviceLockedInputConsumer(gestureState, runningTaskInfo);
@@ -524,26 +537,27 @@
}
}
- 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);
}
}
@@ -553,44 +567,47 @@
&& (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,
event);
- factory = mWindowTreansformFactory;
+ factory = mWindowTransformFactory;
}
final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
- return new OtherActivityInputConsumer(this, mDeviceState, gestureState, runningTaskInfo,
- shouldDefer, this::onConsumerInactive, sSwipeSharedState, mInputMonitorCompat,
- disableHorizontalSwipe, factory, mLogId);
+ return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager,
+ gestureState, runningTaskInfo, shouldDefer, this::onConsumerInactive,
+ mInputMonitorCompat, disableHorizontalSwipe, factory);
}
private InputConsumer createDeviceLockedInputConsumer(GestureState gestureState,
RunningTaskInfo taskInfo) {
if (mMode == Mode.NO_BUTTON && taskInfo != null) {
- return new DeviceLockedInputConsumer(this, mDeviceState, gestureState,
- sSwipeSharedState, mInputMonitorCompat, taskInfo.taskId, mLogId);
+ return new DeviceLockedInputConsumer(this, mDeviceState, mTaskAnimationManager,
+ 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 {
@@ -629,8 +646,8 @@
mOverviewComponentObserver.getActivityInterface();
if (activityInterface.getCreatedActivity() == null) {
// Make sure that UI states will be initialized.
- activityInterface.createActivityInitListener((activity, wasVisible) -> {
- AppLaunchTracker.INSTANCE.get(activity);
+ activityInterface.createActivityInitListener((wasVisible) -> {
+ AppLaunchTracker.INSTANCE.get(TouchInteractionService.this);
return false;
}).register();
} else if (fromInit) {
@@ -640,9 +657,8 @@
return;
}
- // Pass null animation handler to indicate this start is preload.
- startRecentsActivityAsync(mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState(),
- null);
+ mTaskAnimationManager.preloadRecentsAnimation(
+ mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState());
}
@Override
@@ -686,10 +702,6 @@
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());
@@ -718,9 +730,9 @@
private BaseSwipeUpHandler createWindowTransformSwipeHandler(GestureState gestureState,
RunningTaskInfo runningTask, long touchTimeMs, boolean continuingLastGesture,
boolean isLikelyToStartNewTask) {
- return new WindowTransformSwipeHandler(this, mDeviceState, gestureState, runningTask,
- touchTimeMs, mOverviewComponentObserver, continuingLastGesture, mInputConsumer,
- mRecentsModel);
+ return new WindowTransformSwipeHandler(this, mDeviceState, mTaskAnimationManager,
+ gestureState, runningTask, touchTimeMs, mOverviewComponentObserver,
+ continuingLastGesture, mInputConsumer, mRecentsModel);
}
private BaseSwipeUpHandler createFallbackNoButtonSwipeHandler(GestureState gestureState,
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 1168758..22ad180 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.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.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 @@
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;
@@ -192,9 +158,9 @@
private static final int LOG_NO_OP_PAGE_INDEX = -1;
private final RecentsAnimationDeviceState mDeviceState;
+ 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;
@@ -225,12 +191,17 @@
private final long mTouchTimeMs;
private long mLauncherFrameDrawnTime;
+ private final Runnable mOnDeferredActivityLaunch = this::onDeferredActivityLaunch;
+
public WindowTransformSwipeHandler(Context context, RecentsAnimationDeviceState deviceState,
- GestureState gestureState, RunningTaskInfo runningTaskInfo, long touchTimeMs,
+ TaskAnimationManager taskAnimationManager, GestureState gestureState,
+ RunningTaskInfo runningTaskInfo, long touchTimeMs,
OverviewComponentObserver overviewComponentObserver, boolean continuingLastGesture,
InputConsumerController inputConsumer, RecentsModel recentsModel) {
- super(context, gestureState, overviewComponentObserver, recentsModel, inputConsumer, runningTaskInfo.id);
+ super(context, gestureState, overviewComponentObserver, recentsModel, inputConsumer,
+ runningTaskInfo.id);
mDeviceState = deviceState;
+ mTaskAnimationManager = taskAnimationManager;
mGestureState = gestureState;
mTouchTimeMs = touchTimeMs;
mContinuingLastGesture = continuingLastGesture;
@@ -240,62 +211,65 @@
private void initStateCallbacks() {
mStateCallback = new MultiStateCallback(STATE_NAMES);
- mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_STARTED,
+ mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_GESTURE_STARTED,
this::onLauncherPresentAndGestureStarted);
- mStateCallback.addCallback(STATE_LAUNCHER_DRAWN | STATE_GESTURE_STARTED,
+ mStateCallback.runOnceAtState(STATE_LAUNCHER_DRAWN | STATE_GESTURE_STARTED,
this::initializeLauncherAnimationController);
- mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN,
+ mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN,
this::launcherFrameDrawn);
- mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_STARTED
+ mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_STARTED
| STATE_GESTURE_CANCELLED,
this::resetStateForAnimationCancel);
- mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_APP_CONTROLLER_RECEIVED,
+ mStateCallback.runOnceAtState(STATE_LAUNCHER_STARTED | STATE_APP_CONTROLLER_RECEIVED,
this::sendRemoteAnimationsToAnimationFactory);
- mStateCallback.addCallback(STATE_RESUME_LAST_TASK | STATE_APP_CONTROLLER_RECEIVED,
+ mStateCallback.runOnceAtState(STATE_RESUME_LAST_TASK | STATE_APP_CONTROLLER_RECEIVED,
this::resumeLastTask);
- mStateCallback.addCallback(STATE_START_NEW_TASK | STATE_SCREENSHOT_CAPTURED,
+ mStateCallback.runOnceAtState(STATE_START_NEW_TASK | STATE_SCREENSHOT_CAPTURED,
this::startNewTask);
- mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED
+ mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED
| STATE_LAUNCHER_DRAWN | STATE_CAPTURE_SCREENSHOT,
this::switchToScreenshot);
- mStateCallback.addCallback(STATE_SCREENSHOT_CAPTURED | STATE_GESTURE_COMPLETED
+ mStateCallback.runOnceAtState(STATE_SCREENSHOT_CAPTURED | STATE_GESTURE_COMPLETED
| STATE_SCALED_CONTROLLER_RECENTS,
this::finishCurrentTransitionToRecents);
- mStateCallback.addCallback(STATE_SCREENSHOT_CAPTURED | STATE_GESTURE_COMPLETED
+ mStateCallback.runOnceAtState(STATE_SCREENSHOT_CAPTURED | STATE_GESTURE_COMPLETED
| STATE_SCALED_CONTROLLER_HOME,
this::finishCurrentTransitionToHome);
- mStateCallback.addCallback(STATE_SCALED_CONTROLLER_HOME | STATE_CURRENT_TASK_FINISHED,
+ mStateCallback.runOnceAtState(STATE_SCALED_CONTROLLER_HOME | STATE_CURRENT_TASK_FINISHED,
this::reset);
- mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED
+ mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED
| STATE_LAUNCHER_DRAWN | STATE_SCALED_CONTROLLER_RECENTS
| STATE_CURRENT_TASK_FINISHED | STATE_GESTURE_COMPLETED
| STATE_GESTURE_STARTED,
this::setupLauncherUiAfterSwipeUpToRecentsAnimation);
- mStateCallback.addCallback(STATE_HANDLER_INVALIDATED, this::invalidateHandler);
- mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
+ mGestureState.runOnceAtState(STATE_END_TARGET_ANIMATION_FINISHED, this::onEndTargetSet);
+
+ mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED, this::invalidateHandler);
+ mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
this::invalidateHandlerWithLauncher);
- mStateCallback.addCallback(STATE_HANDLER_INVALIDATED | STATE_RESUME_LAST_TASK,
+ mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED | STATE_RESUME_LAST_TASK,
this::notifyTransitionCancelled);
if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) {
- mStateCallback.addChangeHandler(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT
+ mStateCallback.addChangeListener(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT
| STATE_SCREENSHOT_VIEW_SHOWN | STATE_CAPTURE_SCREENSHOT,
(b) -> mRecentsView.setRunningTaskHidden(!b));
}
}
@Override
- protected boolean onActivityInit(final T activity, Boolean alreadyOnHome) {
+ protected boolean onActivityInit(Boolean alreadyOnHome) {
+ final T activity = mActivityInterface.getCreatedActivity();
if (mActivity == activity) {
return true;
}
@@ -332,7 +306,7 @@
@Override
protected boolean moveWindowWithRecentsScroll() {
- return mGestureEndTarget != HOME;
+ return mGestureState.getEndTarget() != HOME;
}
private void onLauncherStart(final T activity) {
@@ -345,9 +319,9 @@
// 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,
+ mAnimationFactory = mActivityInterface.prepareRecentsUI(
mWasLauncherAlreadyVisible, true,
this::onAnimatorPlaybackControllerCreated);
maybeUpdateRecentsAttachedState(false /* animate */);
@@ -356,7 +330,7 @@
// Launcher is visible, but might be about to stop. Thus, if we prepare recents
// now, it might get overridden by moveToRestState() in onStop(). To avoid this,
// wait until the next gesture (and possibly launcher) starts.
- mStateCallback.addCallback(STATE_GESTURE_STARTED, initAnimFactory);
+ mStateCallback.runOnceAtState(STATE_GESTURE_STARTED, initAnimFactory);
} else {
initAnimFactory.run();
}
@@ -400,9 +374,25 @@
// that time by a previous window transition.
setupRecentsViewUi();
+ // For the duration of the gesture, in cases where an activity is launched while the
+ // activity is not yet resumed, finish the animation to ensure we get resumed
+ mGestureState.getActivityInterface().setOnDeferredActivityLaunchCallback(
+ mOnDeferredActivityLaunch);
+
notifyGestureStartedAsync();
}
+ private void onDeferredActivityLaunch() {
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ mOverviewComponentObserver.getActivityInterface().switchRunningTaskViewToScreenshot(
+ null, () -> {
+ mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */);
+ });
+ } else {
+ mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */);
+ }
+ }
+
private void setupRecentsViewUi() {
if (mContinuingLastGesture) {
updateSysUiFlags(mCurrentShift.value);
@@ -437,13 +427,6 @@
.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);
@@ -468,9 +451,8 @@
? 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;
@@ -517,9 +499,10 @@
}
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());
@@ -576,7 +559,7 @@
}
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
@@ -613,9 +596,9 @@
super.onRecentsAnimationStart(controller, targets);
// Only add the callback to enable the input consumer after we actually have the controller
- mStateCallback.addCallback(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED,
+ mStateCallback.runOnceAtState(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED,
mRecentsAnimationController::enableInputConsumer);
- setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
+ mStateCallback.setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
mPassedOverviewThreshold = false;
}
@@ -625,7 +608,7 @@
super.onRecentsAnimationCanceled(thumbnailData);
mRecentsView.setRecentsAnimationTargets(null, null);
mActivityInitListener.unregister();
- setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
+ mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
ActiveGestureLog.INSTANCE.addLog("cancelRecentsAnimation");
}
@@ -633,7 +616,7 @@
public void onGestureStarted() {
notifyGestureStartedAsync();
mShiftAtGestureStart = mCurrentShift.value;
- setStateOnUiThread(STATE_GESTURE_STARTED);
+ mStateCallback.setStateOnUiThread(STATE_GESTURE_STARTED);
mGestureStarted = true;
}
@@ -656,7 +639,7 @@
@Override
public void onGestureCancelled() {
updateDisplacement(0);
- setStateOnUiThread(STATE_GESTURE_COMPLETED);
+ mStateCallback.setStateOnUiThread(STATE_GESTURE_COMPLETED);
mLogAction = Touch.SWIPE_NOOP;
handleNormalGestureEnd(0, false, new PointF(), true /* isCancel */);
}
@@ -671,7 +654,7 @@
float flingThreshold = mContext.getResources()
.getDimension(R.dimen.quickstep_fling_threshold_velocity);
boolean isFling = mGestureStarted && Math.abs(endVelocity) > flingThreshold;
- setStateOnUiThread(STATE_GESTURE_COMPLETED);
+ mStateCallback.setStateOnUiThread(STATE_GESTURE_COMPLETED);
mLogAction = isFling ? Touch.FLING : Touch.SWIPE;
boolean isVelocityVertical = Math.abs(velocity.y) > Math.abs(velocity.x);
@@ -686,7 +669,7 @@
@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
@@ -708,6 +691,24 @@
}
}
+ 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;
@@ -777,7 +778,7 @@
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) {
@@ -880,14 +881,15 @@
@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);
+ homeAnimFactory = mActivityInterface.prepareHomeUI();
} else {
homeAnimFactory = new HomeAnimationFactory() {
@NonNull
@@ -904,14 +906,15 @@
return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
}
};
- mStateCallback.addChangeHandler(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
+ mStateCallback.addChangeListener(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
isPresent -> mRecentsView.startHome());
}
RectFSpringAnim windowAnim = createWindowAnimationToHome(start, homeAnimFactory);
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);
@@ -936,10 +939,9 @@
// 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();
@@ -947,7 +949,7 @@
}
// 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;
}
@@ -999,21 +1001,16 @@
}
// Make sure recents is in its final state
maybeUpdateRecentsAttachedState(false);
- mActivityInterface.onSwipeUpToHomeComplete(mActivity);
+ mActivityInterface.onSwipeUpToHomeComplete();
}
});
return anim;
}
@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();
}
@@ -1045,14 +1042,14 @@
}
private void reset() {
- setStateOnUiThread(STATE_HANDLER_INVALIDATED);
+ mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
}
/**
* 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
@@ -1070,7 +1067,7 @@
? newRunningTaskView.getTask().key.id
: -1;
mRecentsView.setCurrentTask(newRunningTaskId);
- sharedState.setRecentsAnimationFinishInterrupted(newRunningTaskId);
+ mGestureState.setFinishingRecentsAnimationTaskId(newRunningTaskId);
}
}
@@ -1090,6 +1087,8 @@
mRecentsView.onGestureAnimationEnd();
+ // Reset the callback for deferred activity launches
+ mActivityInterface.setOnDeferredActivityLaunchCallback(null);
mActivity.getRootView().setOnApplyWindowInsetsListener(null);
removeLiveTileOverlay();
}
@@ -1108,7 +1107,7 @@
private void resetStateForAnimationCancel() {
boolean wasVisible = mWasLauncherAlreadyVisible || mGestureStarted;
- mActivityInterface.onTransitionCancelled(mActivity, wasVisible);
+ mActivityInterface.onTransitionCancelled(wasVisible);
// Leave the pending invisible flag, as it may be used by wallpaper open animation.
mActivity.clearForceInvisibleFlag(INVISIBLE_BY_STATE_HANDLER);
@@ -1123,10 +1122,10 @@
}
mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot, false /* refreshNow */);
}
- setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
+ mStateCallback.setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
} else if (!hasTargets()) {
// If there are no targets, then we don't need to capture anything
- setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
+ mStateCallback.setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
} else {
boolean finishTransitionPosted = false;
if (mRecentsAnimationController != null) {
@@ -1135,7 +1134,7 @@
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;
@@ -1146,14 +1145,15 @@
// Defer finishing the animation until the next launcher frame with the
// new thumbnail
finishTransitionPosted = ViewUtils.postDraw(taskView,
- () -> setStateOnUiThread(STATE_SCREENSHOT_CAPTURED), this::isCanceled);
+ () -> mStateCallback.setStateOnUiThread(STATE_SCREENSHOT_CAPTURED),
+ this::isCanceled);
}
}
if (!finishTransitionPosted) {
// If we haven't posted a draw callback, set the state immediately.
Object traceToken = TraceHelper.INSTANCE.beginSection(SCREENSHOT_CAPTURED_EVT,
TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS);
- setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
+ mStateCallback.setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
TraceHelper.INSTANCE.endSection(traceToken);
}
}
@@ -1161,14 +1161,14 @@
private void finishCurrentTransitionToRecents() {
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
- setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
+ mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
} else if (!hasTargets()) {
// If there are no targets, then there is nothing to finish
- setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
+ mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
} else {
synchronized (mRecentsAnimationController) {
mRecentsAnimationController.finish(true /* toRecents */,
- () -> setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
+ () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
}
}
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true);
@@ -1177,7 +1177,7 @@
private void finishCurrentTransitionToHome() {
synchronized (mRecentsAnimationController) {
mRecentsAnimationController.finish(true /* toRecents */,
- () -> setStateOnUiThread(STATE_CURRENT_TASK_FINISHED),
+ () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED),
true /* sendUserLeaveHint */);
}
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true);
@@ -1186,7 +1186,7 @@
private void setupLauncherUiAfterSwipeUpToRecentsAnimation() {
endLauncherTransitionController();
- mActivityInterface.onSwipeUpToRecentsComplete(mActivity);
+ mActivityInterface.onSwipeUpToRecentsComplete();
if (mRecentsAnimationController != null) {
mRecentsAnimationController.setDeferCancelUntilNextTransition(true /* defer */,
true /* screenshot */);
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 0b5129c..2f73fc1 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
@@ -23,11 +23,6 @@
}
@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 12b7c26..370f161 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
@@ -22,7 +22,6 @@
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
-import static com.android.quickstep.TouchInteractionService.startRecentsActivityAsync;
import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
@@ -45,9 +44,9 @@
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;
import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InputMonitorCompat;
@@ -76,14 +75,13 @@
private final Context mContext;
private final RecentsAnimationDeviceState mDeviceState;
+ 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;
@@ -98,15 +96,14 @@
private RecentsAnimationTargets mRecentsAnimationTargets;
public DeviceLockedInputConsumer(Context context, RecentsAnimationDeviceState deviceState,
- GestureState gestureState, SwipeSharedState swipeSharedState,
- InputMonitorCompat inputMonitorCompat, int runningTaskId, int logId) {
+ TaskAnimationManager taskAnimationManager, GestureState gestureState,
+ 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;
@@ -116,7 +113,7 @@
// Init states
mStateCallback = new MultiStateCallback(STATE_NAMES);
- mStateCallback.addCallback(STATE_TARGET_RECEIVED | STATE_HANDLER_INVALIDATED,
+ mStateCallback.runOnceAtState(STATE_TARGET_RECEIVED | STATE_HANDLER_INVALIDATED,
this::endRemoteAnimation);
mVelocityTracker = VelocityTracker.obtain();
@@ -207,16 +204,14 @@
private void startRecentsTransition() {
mThresholdCrossed = true;
- RecentsAnimationCallbacks callbacks = mSwipeSharedState.newRecentsAnimationCallbacks();
- callbacks.addListener(this);
+ mInputMonitorCompat.pilferPointers();
+
Intent intent = new Intent(Intent.ACTION_MAIN)
.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);
-
- mInputMonitorCompat.pilferPointers();
- startRecentsActivityAsync(intent, callbacks);
+ .putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId());
+ mTaskAnimationManager.startRecentsAnimation(mGestureState, intent, this);
}
@Override
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 370b487..152b9c9 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.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.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 @@
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,40 +133,46 @@
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();
}
private void initStateCallbacks() {
mStateCallback = new MultiStateCallback(STATE_NAMES);
- mStateCallback.addCallback(STATE_HANDLER_INVALIDATED,
+ mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED,
this::onHandlerInvalidated);
- mStateCallback.addCallback(STATE_RECENTS_PRESENT | STATE_HANDLER_INVALIDATED,
+ mStateCallback.runOnceAtState(STATE_RECENTS_PRESENT | STATE_HANDLER_INVALIDATED,
this::onHandlerInvalidatedWithRecents);
- mStateCallback.addCallback(STATE_GESTURE_CANCELLED | STATE_APP_CONTROLLER_RECEIVED,
+ mStateCallback.runOnceAtState(STATE_GESTURE_CANCELLED | STATE_APP_CONTROLLER_RECEIVED,
this::finishAnimationTargetSetAnimationComplete);
if (mInQuickSwitchMode) {
- mStateCallback.addCallback(STATE_GESTURE_COMPLETED | STATE_APP_CONTROLLER_RECEIVED
+ mStateCallback.runOnceAtState(STATE_GESTURE_COMPLETED | STATE_APP_CONTROLLER_RECEIVED
| STATE_RECENTS_PRESENT,
this::finishAnimationTargetSet);
} else {
- mStateCallback.addCallback(STATE_GESTURE_COMPLETED | STATE_APP_CONTROLLER_RECEIVED,
+ mStateCallback.runOnceAtState(STATE_GESTURE_COMPLETED | STATE_APP_CONTROLLER_RECEIVED,
this::finishAnimationTargetSet);
}
}
private void onLauncherAlphaChanged() {
- if (mRecentsAnimationTargets != null && mEndTarget == null) {
+ if (mRecentsAnimationTargets != null && mGestureState.getEndTarget() == null) {
applyTransformUnchecked();
}
}
@Override
- protected boolean onActivityInit(final RecentsActivity activity, Boolean alreadyOnHome) {
- mActivity = activity;
- mRecentsView = activity.getOverviewPanel();
+ protected boolean onActivityInit(Boolean alreadyOnHome) {
+ mActivity = mActivityInterface.getCreatedActivity();
+ mRecentsView = mActivity.getOverviewPanel();
linkRecentsViewScroll();
mRecentsView.setDisallowScrollToClearAll(true);
mRecentsView.getClearAllButton().setVisibilityAlpha(0);
@@ -183,7 +186,7 @@
mRecentsView.onGestureAnimationStart(mRunningTaskId);
}
}
- setStateOnUiThread(STATE_RECENTS_PRESENT);
+ mStateCallback.setStateOnUiThread(STATE_RECENTS_PRESENT);
return true;
}
@@ -247,8 +250,8 @@
@Override
public void onGestureCancelled() {
updateDisplacement(0);
- mEndTarget = LAST_TASK;
- setStateOnUiThread(STATE_GESTURE_CANCELLED);
+ mGestureState.setEndTarget(LAST_TASK);
+ mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED);
}
@Override
@@ -256,28 +259,29 @@
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);
+ mStateCallback.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,12 +297,12 @@
? newRunningTaskView.getTask().key.id
: -1;
mRecentsView.setCurrentTask(newRunningTaskId);
- sharedState.setRecentsAnimationFinishInterrupted(newRunningTaskId);
+ mGestureState.setFinishingRecentsAnimationTaskId(newRunningTaskId);
}
mRecentsView.setOnScrollChangeListener(null);
}
} else {
- setStateOnUiThread(STATE_HANDLER_INVALIDATED);
+ mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
}
}
@@ -319,7 +323,7 @@
}
private void finishAnimationTargetSetAnimationComplete() {
- switch (mEndTarget) {
+ switch (mGestureState.getEndTarget()) {
case HOME: {
if (mSwipeUpOverHome) {
mRecentsAnimationController.finish(false, null, false);
@@ -362,7 +366,7 @@
}
}
- setStateOnUiThread(STATE_HANDLER_INVALIDATED);
+ mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
}
private void finishAnimationTargetSet() {
@@ -370,17 +374,20 @@
// 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 @@
}
};
- 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 @@
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);
@@ -429,13 +436,14 @@
}
applyTransformUnchecked();
- setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
+ mStateCallback.setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
}
@Override
public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
+ super.onRecentsAnimationCanceled(thumbnailData);
mRecentsView.setRecentsAnimationTargets(null, null);
- setStateOnUiThread(STATE_HANDLER_INVALIDATED);
+ mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
}
/**
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 02f4c40..c479250 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
@@ -26,7 +26,6 @@
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.util.TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS;
-import static com.android.quickstep.TouchInteractionService.startRecentsActivityAsync;
import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
@@ -55,9 +54,9 @@
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;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.CachedEventDispatcher;
import com.android.quickstep.util.MotionPauseDetector;
@@ -80,10 +79,11 @@
public static final float QUICKSTEP_TOUCH_SLOP_RATIO = 3;
private final RecentsAnimationDeviceState mDeviceState;
+ private final TaskAnimationManager mTaskAnimationManager;
private final GestureState mGestureState;
+ 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;
@@ -95,6 +95,7 @@
private final Consumer<OtherActivityInputConsumer> mOnCompleteCallback;
private final MotionPauseDetector mMotionPauseDetector;
private final float mMotionPauseMinDisplacement;
+
private VelocityTracker mVelocityTracker;
private BaseSwipeUpHandler mInteractionHandler;
@@ -123,16 +124,16 @@
ActivityManagerWrapper.getInstance().cancelRecentsAnimation(
true /* restoreHomeStackPosition */);
};
- private int mLogId;
public OtherActivityInputConsumer(Context base, RecentsAnimationDeviceState deviceState,
- GestureState gestureState, RunningTaskInfo runningTaskInfo,
- boolean isDeferredDownTarget, Consumer<OtherActivityInputConsumer> onCompleteCallback,
- SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat,
- boolean disableHorizontalSwipe, Factory handlerFactory, int logId) {
+ TaskAnimationManager taskAnimationManager, GestureState gestureState,
+ RunningTaskInfo runningTaskInfo, boolean isDeferredDownTarget,
+ Consumer<OtherActivityInputConsumer> onCompleteCallback,
+ InputMonitorCompat inputMonitorCompat, boolean disableHorizontalSwipe,
+ Factory handlerFactory) {
super(base);
- mLogId = logId;
mDeviceState = deviceState;
+ mTaskAnimationManager = taskAnimationManager;
mGestureState = gestureState;
mMainThreadHandler = new Handler(Looper.getMainLooper());
mRunningTask = runningTaskInfo;
@@ -147,9 +148,8 @@
mVelocityTracker = VelocityTracker.obtain();
mInputMonitorCompat = inputMonitorCompat;
- boolean continuingPreviousGesture = swipeSharedState.getActiveListener() != null;
+ boolean continuingPreviousGesture = mTaskAnimationManager.isRecentsAnimationRunning();
mIsDeferredDownTarget = !continuingPreviousGesture && isDeferredDownTarget;
- mSwipeSharedState = swipeSharedState;
mNavBarPosition = new NavBarPosition(base);
mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
@@ -329,25 +329,22 @@
long touchTimeMs, boolean isLikelyToStartNewTask) {
ActiveGestureLog.INSTANCE.addLog("startRecentsAnimation");
- RecentsAnimationCallbacks listenerSet = mSwipeSharedState.getActiveListener();
- final BaseSwipeUpHandler handler = mHandlerFactory.newHandler(mGestureState, mRunningTask,
- touchTimeMs, listenerSet != null, isLikelyToStartNewTask);
+ mInteractionHandler = mHandlerFactory.newHandler(mGestureState, mRunningTask, touchTimeMs,
+ mTaskAnimationManager.isRecentsAnimationRunning(), isLikelyToStartNewTask);
+ mInteractionHandler.setGestureEndCallback(this::onInteractionGestureFinished);
+ mMotionPauseDetector.setOnMotionPauseListener(mInteractionHandler::onMotionPauseChanged);
+ mInteractionHandler.initWhenReady();
- mInteractionHandler = handler;
- handler.setGestureEndCallback(this::onInteractionGestureFinished);
- mMotionPauseDetector.setOnMotionPauseListener(handler::onMotionPauseChanged);
- handler.initWhenReady();
-
- if (listenerSet != null) {
- listenerSet.addListener(handler);
- mSwipeSharedState.applyActiveRecentsAnimationState(handler);
+ if (mTaskAnimationManager.isRecentsAnimationRunning()) {
+ mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(mGestureState);
+ mActiveCallbacks.addListener(mInteractionHandler);
+ mTaskAnimationManager.notifyRecentsAnimationState(mInteractionHandler);
notifyGestureStarted();
} else {
- RecentsAnimationCallbacks callbacks = mSwipeSharedState.newRecentsAnimationCallbacks();
- callbacks.addListener(handler);
- Intent intent = handler.getLaunchIntent();
- intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mLogId);
- startRecentsActivityAsync(intent, callbacks);
+ Intent intent = mInteractionHandler.getLaunchIntent();
+ intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId());
+ mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation(mGestureState, intent,
+ mInteractionHandler);
}
}
@@ -402,7 +399,7 @@
// 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();
}
}
@@ -415,9 +412,8 @@
}
private void removeListener() {
- RecentsAnimationCallbacks listenerSet = mSwipeSharedState.getActiveListener();
- if (listenerSet != null) {
- listenerSet.removeListener(mInteractionHandler);
+ if (mActiveCallbacks != null) {
+ mActiveCallbacks.removeListener(mInteractionHandler);
}
}
@@ -432,11 +428,6 @@
}
@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/QuickCaptureInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureInputConsumer.java
index 97ca730..9826b3a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/QuickCaptureInputConsumer.java
@@ -69,7 +69,8 @@
private final float mSquaredSlop;
- private Context mContext;
+ private final Context mContext;
+ private final GestureState mGestureState;
private RecentsView mRecentsView;
@@ -77,6 +78,7 @@
InputConsumer delegate, InputMonitorCompat inputMonitor) {
super(delegate, inputMonitor);
mContext = context;
+ mGestureState = gestureState;
float slop = ViewConfiguration.get(context).getScaledTouchSlop();
mSquaredSlop = slop * slop;
@@ -90,8 +92,8 @@
return TYPE_QUICK_CAPTURE | mDelegate.getType();
}
- private boolean onActivityInit(final BaseDraggingActivity activity, Boolean alreadyOnHome) {
- mRecentsView = activity.getOverviewPanel();
+ private boolean onActivityInit(Boolean alreadyOnHome) {
+ mRecentsView = mGestureState.getActivityInterface().getCreatedActivity().getOverviewPanel();
return true;
}
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 e04c0c7..d34b40b 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
@@ -18,17 +18,17 @@
import android.view.MotionEvent;
import com.android.quickstep.InputConsumer;
-import com.android.quickstep.SwipeSharedState;
+import com.android.quickstep.TaskAnimationManager;
/**
* A NO_OP input consumer which also resets any pending gesture
*/
public class ResetGestureInputConsumer implements InputConsumer {
- private final SwipeSharedState mSwipeSharedState;
+ private final TaskAnimationManager mTaskAnimationManager;
- public ResetGestureInputConsumer(SwipeSharedState swipeSharedState) {
- mSwipeSharedState = swipeSharedState;
+ public ResetGestureInputConsumer(TaskAnimationManager taskAnimationManager) {
+ mTaskAnimationManager = taskAnimationManager;
}
@Override
@@ -39,8 +39,8 @@
@Override
public void onMotionEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN
- && mSwipeSharedState.getActiveListener() != null) {
- mSwipeSharedState.clearAllState(false /* finishAnimation */);
+ && mTaskAnimationManager.isRecentsAnimationRunning()) {
+ mTaskAnimationManager.finishRunningRecentsAnimation(false /* toHome */);
}
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ActiveGestureLog.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ActiveGestureLog.java
index 9a3bb76..fabfc4b 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ActiveGestureLog.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ActiveGestureLog.java
@@ -33,7 +33,7 @@
*/
public static final String INTENT_EXTRA_LOG_TRACE_ID = "INTENT_EXTRA_LOG_TRACE_ID";
- public ActiveGestureLog() {
+ private ActiveGestureLog() {
super("touch_interaction_log", 40);
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
index 0655c73..5a65c15 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -102,8 +102,9 @@
@Override
public void startHome() {
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
- switchToScreenshot(() -> finishRecentsAnimation(true /* toRecents */,
- () -> mActivity.getStateManager().goToState(NORMAL)));
+ switchToScreenshot(null,
+ () -> finishRecentsAnimation(true /* toRecents */,
+ () -> mActivity.getStateManager().goToState(NORMAL)));
} else {
mActivity.getStateManager().goToState(NORMAL);
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index 6120b9e..5d4665d 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -1851,20 +1851,20 @@
return Math.max(insets.getSystemGestureInsets().right, insets.getSystemWindowInsetRight());
}
-
/** If it's in the live tile mode, switch the running task into screenshot mode. */
- public void switchToScreenshot(Runnable onFinishRunnable) {
+ public void switchToScreenshot(ThumbnailData thumbnailData, Runnable onFinishRunnable) {
TaskView taskView = getRunningTaskView();
- if (taskView == null) {
- if (onFinishRunnable != null) {
- onFinishRunnable.run();
+ if (taskView != null) {
+ taskView.setShowScreenshot(true);
+ if (thumbnailData != null) {
+ taskView.getThumbnail().setThumbnail(taskView.getTask(), thumbnailData);
+ } else {
+ taskView.getThumbnail().refresh();
}
- return;
+ ViewUtils.postDraw(taskView, onFinishRunnable);
+ } else {
+ onFinishRunnable.run();
}
-
- taskView.setShowScreenshot(true);
- taskView.getThumbnail().refresh();
- ViewUtils.postDraw(taskView, onFinishRunnable);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 409bec6..cb18001 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -35,8 +35,8 @@
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import java.util.function.BiPredicate;
import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* Utility class which abstracts out the logical differences between Launcher and RecentsActivity.
@@ -44,21 +44,26 @@
@TargetApi(Build.VERSION_CODES.P)
public interface BaseActivityInterface<T extends BaseDraggingActivity> {
- void onTransitionCancelled(T activity, boolean activityVisible);
+ void onTransitionCancelled(boolean activityVisible);
int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect);
- void onSwipeUpToRecentsComplete(T activity);
+ void onSwipeUpToRecentsComplete();
- default void onSwipeUpToHomeComplete(T activity) { }
+ default void onSwipeUpToHomeComplete() { }
void onAssistantVisibilityChanged(float visibility);
- @NonNull HomeAnimationFactory prepareHomeUI(T activity);
+ @NonNull HomeAnimationFactory prepareHomeUI();
- AnimationFactory prepareRecentsUI(T activity, boolean activityVisible,
- boolean animateActivity, Consumer<AnimatorPlaybackController> callback);
+ AnimationFactory prepareRecentsUI(boolean activityVisible, boolean animateActivity,
+ Consumer<AnimatorPlaybackController> callback);
- ActivityInitListener createActivityInitListener(BiPredicate<T, Boolean> onInitListener);
+ ActivityInitListener createActivityInitListener(Predicate<Boolean> onInitListener);
+
+ /**
+ * Sets a callback to be run when an activity launch happens while launcher is not yet resumed.
+ */
+ default void setOnDeferredActivityLaunchCallback(Runnable r) {}
@Nullable
T getCreatedActivity();
@@ -90,13 +95,14 @@
boolean isInLiveTileMode();
- void onLaunchTaskFailed(T activity);
+ void onLaunchTaskFailed();
- void onLaunchTaskSuccess(T activity);
+ void onLaunchTaskSuccess();
default void closeOverlay() { }
- default void switchToScreenshot(ThumbnailData thumbnailData, Runnable runnable) {}
+ default void switchRunningTaskViewToScreenshot(ThumbnailData thumbnailData,
+ Runnable runnable) {}
interface AnimationFactory {
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index de64227..98ff410 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -15,22 +15,215 @@
*/
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,
* and fires events when the states change.
*/
-public class GestureState {
+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 runOnceAtState(int stateMask, Runnable callback) {
+ mStateCallback.runOnceAtState(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.runOnceAtState(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) {
+ mStateCallback.setState(STATE_RECENTS_ANIMATION_STARTED);
+ }
+
+ @Override
+ public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
+ mStateCallback.setState(STATE_RECENTS_ANIMATION_CANCELED);
+ mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED);
+ }
+
+ @Override
+ public void onRecentsAnimationFinished(RecentsAnimationController controller) {
+ 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 62c0ded..918645d 100644
--- a/quickstep/src/com/android/quickstep/InputConsumer.java
+++ b/quickstep/src/com/android/quickstep/InputConsumer.java
@@ -52,10 +52,6 @@
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 @@
/**
* 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/src/com/android/quickstep/MultiStateCallback.java b/quickstep/src/com/android/quickstep/MultiStateCallback.java
new file mode 100644
index 0000000..6c65e01
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/MultiStateCallback.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2017 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 static com.android.launcher3.Utilities.postAsyncCallback;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+
+import android.os.Looper;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.launcher3.config.FeatureFlags;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.StringJoiner;
+import java.util.function.Consumer;
+
+/**
+ * Utility class to help manage multiple callbacks based on different states.
+ */
+public class MultiStateCallback {
+
+ private static final String TAG = "MultiStateCallback";
+ public static final boolean DEBUG_STATES = false;
+
+ private final SparseArray<LinkedList<Runnable>> mCallbacks = new SparseArray<>();
+ private final SparseArray<ArrayList<Consumer<Boolean>>> mStateChangeListeners =
+ new SparseArray<>();
+
+ private final String[] mStateNames;
+
+ private int mState = 0;
+
+ public MultiStateCallback(String[] stateNames) {
+ mStateNames = DEBUG_STATES ? stateNames : null;
+ }
+
+ /**
+ * Adds the provided state flags to the global state on the UI thread and executes any callbacks
+ * as a result.
+ */
+ public void setStateOnUiThread(int stateFlag) {
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ setState(stateFlag);
+ } else {
+ postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> setState(stateFlag));
+ }
+ }
+
+ /**
+ * Adds the provided state flags to the global state and executes any callbacks as a result.
+ */
+ public void setState(int stateFlag) {
+ if (DEBUG_STATES) {
+ Log.d(TAG, "[" + System.identityHashCode(this) + "] Adding "
+ + convertToFlagNames(stateFlag) + " to " + convertToFlagNames(mState));
+ }
+
+ final int oldState = mState;
+ mState = mState | stateFlag;
+
+ int count = mCallbacks.size();
+ for (int i = 0; i < count; i++) {
+ int state = mCallbacks.keyAt(i);
+
+ if ((mState & state) == state) {
+ LinkedList<Runnable> callbacks = mCallbacks.valueAt(i);
+ while (!callbacks.isEmpty()) {
+ callbacks.pollFirst().run();
+ }
+ }
+ }
+ notifyStateChangeListeners(oldState);
+ }
+
+ /**
+ * Adds the provided state flags to the global state and executes any change handlers
+ * as a result.
+ */
+ public void clearState(int stateFlag) {
+ if (DEBUG_STATES) {
+ Log.d(TAG, "[" + System.identityHashCode(this) + "] Removing "
+ + convertToFlagNames(stateFlag) + " from " + convertToFlagNames(mState));
+ }
+
+ int oldState = mState;
+ mState = mState & ~stateFlag;
+ notifyStateChangeListeners(oldState);
+ }
+
+ private void notifyStateChangeListeners(int oldState) {
+ int count = mStateChangeListeners.size();
+ for (int i = 0; i < count; i++) {
+ int state = mStateChangeListeners.keyAt(i);
+ boolean wasOn = (state & oldState) == state;
+ boolean isOn = (state & mState) == state;
+
+ if (wasOn != isOn) {
+ ArrayList<Consumer<Boolean>> listeners = mStateChangeListeners.valueAt(i);
+ for (Consumer<Boolean> listener : listeners) {
+ listener.accept(isOn);
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets a callback to be run when the provided states in the given {@param stateMask} is
+ * enabled. The callback is only run *once*, and if the states are already set at the time of
+ * this call then the callback will be made immediately.
+ */
+ public void runOnceAtState(int stateMask, Runnable callback) {
+ if ((mState & stateMask) == stateMask) {
+ callback.run();
+ } else {
+ final LinkedList<Runnable> callbacks;
+ if (mCallbacks.indexOfKey(stateMask) >= 0) {
+ callbacks = mCallbacks.get(stateMask);
+ if (FeatureFlags.IS_DOGFOOD_BUILD && callbacks.contains(callback)) {
+ throw new IllegalStateException("Existing callback for state found");
+ }
+ } else {
+ callbacks = new LinkedList<>();
+ mCallbacks.put(stateMask, callbacks);
+ }
+ callbacks.add(callback);
+ }
+ }
+
+ /**
+ * Adds a persistent listener to be called states in the given {@param stateMask} are enabled
+ * or disabled.
+ */
+ public void addChangeListener(int stateMask, Consumer<Boolean> listener) {
+ final ArrayList<Consumer<Boolean>> listeners;
+ if (mStateChangeListeners.indexOfKey(stateMask) >= 0) {
+ listeners = mStateChangeListeners.get(stateMask);
+ } else {
+ listeners = new ArrayList<>();
+ mStateChangeListeners.put(stateMask, listeners);
+ }
+ listeners.add(listener);
+ }
+
+ public int getState() {
+ return mState;
+ }
+
+ public boolean hasStates(int stateMask) {
+ return (mState & stateMask) == stateMask;
+ }
+
+ private String convertToFlagNames(int flags) {
+ StringJoiner joiner = new StringJoiner(", ", "[", " (" + flags + ")]");
+ for (int i = 0; i < mStateNames.length; i++) {
+ if ((flags & (1 << i)) != 0) {
+ joiner.add(mStateNames[i]);
+ }
+ }
+ return joiner.toString();
+ }
+
+}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 2918879..acf61b4 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -127,7 +127,7 @@
*/
public interface RecentsAnimationListener {
default void onRecentsAnimationStart(RecentsAnimationController controller,
- RecentsAnimationTargets targetSet) {}
+ RecentsAnimationTargets targets) {}
/**
* Callback from the system when the recents animation is canceled. {@param thumbnailData}
@@ -135,6 +135,9 @@
*/
default void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {}
+ /**
+ * Callback made whenever the recents animation is finished.
+ */
default void onRecentsAnimationFinished(RecentsAnimationController controller) {}
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index d938dc5..9d5120d 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -71,7 +71,7 @@
* currently being animated.
*/
public ThumbnailData screenshotTask(int taskId) {
- return mController != null ? mController.screenshotTask(taskId) : null;
+ return mController.screenshotTask(taskId);
}
/**
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
index 9353759..718c5ba 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
@@ -41,13 +41,4 @@
public boolean hasTargets() {
return unfilteredApps.length != 0;
}
-
- /**
- * Clones the target set without any actual targets. Used only when continuing a gesture after
- * the actual recents animation has finished.
- */
- public RecentsAnimationTargets cloneWithoutTargets() {
- return new RecentsAnimationTargets(new RemoteAnimationTargetCompat[0],
- new RemoteAnimationTargetCompat[0], homeContentInsets, minimizedHomeBounds);
- }
}
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
new file mode 100644
index 0000000..6873899
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -0,0 +1,175 @@
+/*
+ * 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 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;
+
+import androidx.annotation.UiThread;
+
+import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+
+public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
+
+ private RecentsAnimationController mController;
+ private RecentsAnimationCallbacks mCallbacks;
+ private RecentsAnimationTargets mTargets;
+ // Temporary until we can hook into gesture state events
+ private GestureState mLastGestureState;
+ private ThumbnailData mCanceledThumbnail;
+
+ /**
+ * Preloads the recents animation.
+ */
+ public void preloadRecentsAnimation(Intent intent) {
+ // Pass null animation handler to indicate this start is for preloading
+ UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance()
+ .startRecentsActivity(intent, null, null, null, null));
+ }
+
+ /**
+ * Starts a new recents animation for the activity with the given {@param intent}.
+ */
+ @UiThread
+ public RecentsAnimationCallbacks startRecentsAnimation(GestureState gestureState,
+ Intent intent, RecentsAnimationCallbacks.RecentsAnimationListener listener) {
+ // Notify if recents animation is still running
+ if (mController != null) {
+ String msg = "New recents animation started before old animation completed";
+ if (FeatureFlags.IS_DOGFOOD_BUILD) {
+ throw new IllegalArgumentException(msg);
+ } else {
+ Log.e("TaskAnimationManager", msg, new Exception());
+ }
+ }
+ // But force-finish it anyways
+ finishRunningRecentsAnimation(false /* toHome */);
+
+ final BaseActivityInterface activityInterface = gestureState.getActivityInterface();
+ mLastGestureState = gestureState;
+ mCallbacks = new RecentsAnimationCallbacks(activityInterface.shouldMinimizeSplitScreen());
+ mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
+ @Override
+ public void onRecentsAnimationStart(RecentsAnimationController controller,
+ RecentsAnimationTargets targets) {
+ mController = controller;
+ mTargets = targets;
+ }
+
+ @Override
+ public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
+ if (thumbnailData != null) {
+ // If a screenshot is provided, switch to the screenshot before cleaning up
+ activityInterface.switchRunningTaskViewToScreenshot(thumbnailData,
+ () -> cleanUpRecentsAnimation());
+ } else {
+ cleanUpRecentsAnimation();
+ }
+ }
+
+ @Override
+ public void onRecentsAnimationFinished(RecentsAnimationController controller) {
+ cleanUpRecentsAnimation();
+ }
+ });
+ mCallbacks.addListener(gestureState);
+ mCallbacks.addListener(listener);
+ UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance()
+ .startRecentsActivity(intent, null, mCallbacks, null, null));
+ gestureState.setState(STATE_RECENTS_ANIMATION_INITIALIZED);
+ return mCallbacks;
+ }
+
+ /**
+ * Continues the existing running recents animation for a new gesture.
+ */
+ public RecentsAnimationCallbacks continueRecentsAnimation(GestureState gestureState) {
+ mCallbacks.removeListener(mLastGestureState);
+ mLastGestureState = gestureState;
+ mCallbacks.addListener(gestureState);
+ return mCallbacks;
+ }
+
+ /**
+ * Finishes the running recents animation.
+ */
+ public void finishRunningRecentsAnimation(boolean toHome) {
+ if (mController != null) {
+ mCallbacks.notifyAnimationCanceled();
+ Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), toHome
+ ? mController::finishAnimationToHome
+ : mController::finishAnimationToApp);
+ cleanUpRecentsAnimation();
+ }
+ }
+
+ /**
+ * Used to notify a listener of the current recents animation state (used if the listener was
+ * not yet added to the callbacks at the point that the listener callbacks would have been
+ * made).
+ */
+ public void notifyRecentsAnimationState(
+ RecentsAnimationCallbacks.RecentsAnimationListener listener) {
+ if (isRecentsAnimationRunning()) {
+ listener.onRecentsAnimationStart(mController, mTargets);
+ }
+ // TODO: Do we actually need to report canceled/finished?
+ }
+
+ /**
+ * @return whether there is a recents animation running.
+ */
+ public boolean isRecentsAnimationRunning() {
+ return mController != null;
+ }
+
+ /**
+ * Cleans up the recents animation entirely.
+ */
+ private void cleanUpRecentsAnimation() {
+ // Clean up the screenshot if necessary
+ if (mController != null && mCanceledThumbnail != null) {
+ mController.cleanupScreenshot();
+ }
+
+ // Release all the target leashes
+ if (mTargets != null) {
+ mTargets.release();
+ }
+
+ // Remove gesture state from callbacks
+ if (mCallbacks != null && mLastGestureState != null) {
+ mCallbacks.removeListener(mLastGestureState);
+ }
+
+ mController = null;
+ mCallbacks = null;
+ mTargets = null;
+ mCanceledThumbnail = null;
+ mLastGestureState = null;
+ }
+
+ public void dump() {
+ // TODO
+ }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index aa5fce1..b17ed4c 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -130,6 +130,10 @@
@NavigationModeSwitch
@Test
public void goToOverviewFromHome() {
+ // b/142828227
+ if (android.os.Build.MODEL.contains("Cuttlefish") && TestHelpers.isInLauncherProcess()) {
+ return;
+ }
mDevice.pressHome();
assertTrue("Fallback Launcher not visible", mDevice.wait(Until.hasObject(By.pkg(
mOtherLauncherActivity.packageName)), WAIT_TIME_MS));
@@ -140,6 +144,10 @@
@NavigationModeSwitch
@Test
public void goToOverviewFromApp() {
+ // b/142828227
+ if (android.os.Build.MODEL.contains("Cuttlefish") && TestHelpers.isInLauncherProcess()) {
+ return;
+ }
startAppFastAndWaitForRecentTask(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
mLauncher.getBackground().switchToOverview();
@@ -174,6 +182,10 @@
@NavigationModeSwitch
@Test
public void testOverview() {
+ // b/142828227
+ if (android.os.Build.MODEL.contains("Cuttlefish") && TestHelpers.isInLauncherProcess()) {
+ return;
+ }
startAppFastAndWaitForRecentTask(getAppPackageName());
startAppFastAndWaitForRecentTask(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
startTestActivity(2);
diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
index 1d920f9..25224b0 100644
--- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
@@ -25,6 +25,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.Launcher;
+import com.android.launcher3.tapl.TestHelpers;
import com.android.launcher3.util.RaceConditionReproducer;
import com.android.quickstep.NavigationModeSwitchRule.Mode;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
@@ -91,6 +92,10 @@
@Test
@NavigationModeSwitch
public void testStressSwipeToOverview() {
+ // b/142828227
+ if (android.os.Build.MODEL.contains("Cuttlefish") && TestHelpers.isInLauncherProcess()) {
+ return;
+ }
for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
// Destroy Launcher activity.
closeLauncherActivity();
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 4b4d793..67c1a04 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -267,6 +267,10 @@
private ArrayList<OnResumeCallback> mOnResumeCallbacks = new ArrayList<>();
+ // Used to notify when an activity launch has been deferred because launcher is not yet resumed
+ // TODO: See if we can remove this later
+ private Runnable mOnDeferredActivityLaunchCallback;
+
private ViewOnDrawExecutor mPendingExecutor;
private LauncherModel mModel;
@@ -1886,7 +1890,10 @@
// recents animation into launcher. Defer launching the activity until Launcher is
// next resumed.
addOnResumeCallback(() -> startActivitySafely(v, intent, item, sourceContainer));
- UiFactory.clearSwipeSharedState(this, true /* finishAnimation */);
+ if (mOnDeferredActivityLaunchCallback != null) {
+ mOnDeferredActivityLaunchCallback.run();
+ mOnDeferredActivityLaunchCallback = null;
+ }
return true;
}
@@ -1948,6 +1955,14 @@
}
/**
+ * Persistant callback which notifies when an activity launch is deferred because the activity
+ * was not yet resumed.
+ */
+ public void setOnDeferredActivityLaunchCallback(Runnable callback) {
+ mOnDeferredActivityLaunchCallback = callback;
+ }
+
+ /**
* Implementation of the method from LauncherModel.Callbacks.
*/
@Override
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
index 6d9ed88..606c990 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
@@ -96,9 +96,6 @@
public static void resetPendingActivityResults(Launcher launcher, int requestCode) { }
- /** No-op. */
- public static void clearSwipeSharedState(Launcher launcher, boolean finishAnimation) { }
-
public static Person[] getPersons(ShortcutInfo si) {
return Utilities.EMPTY_PERSON_ARRAY;
}
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 5e87612..465cee2 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -34,6 +34,7 @@
import com.android.launcher3.tapl.AppIcon;
import com.android.launcher3.tapl.AppIconMenu;
import com.android.launcher3.tapl.AppIconMenuItem;
+import com.android.launcher3.tapl.TestHelpers;
import com.android.launcher3.tapl.Widgets;
import com.android.launcher3.tapl.Workspace;
import com.android.launcher3.views.OptionsPopupView;
@@ -172,6 +173,10 @@
@Test
public void testWorkspace() throws Exception {
+ // b/142828227
+ if (android.os.Build.MODEL.contains("Cuttlefish") && TestHelpers.isInLauncherProcess()) {
+ return;
+ }
final Workspace workspace = mLauncher.getWorkspace();
// Test that ensureWorkspaceIsScrollable adds a page by dragging an icon there.