Make recents animation work with fallback activity.
Bug: 77157702
Bug: 77152886
Change-Id: Ide312b750efb8214a7c262f7380b5dbd2ef4647f
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index e4a8f36..307345a 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -106,6 +106,8 @@
private DeviceProfile mDeviceProfile;
private View mFloatingView;
+ private RemoteAnimationRunnerCompat mRemoteAnimationOverride;
+
private final AnimatorListenerAdapter mReapplyStateListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -175,6 +177,10 @@
return getDefaultActivityLaunchOptions(launcher, v);
}
+ public void setRemoteAnimationOverride(RemoteAnimationRunnerCompat remoteAnimationOverride) {
+ mRemoteAnimationOverride = remoteAnimationOverride;
+ }
+
/**
* Try to find a TaskView that corresponds with the component of the launched view.
*
@@ -635,6 +641,7 @@
* Registers remote animations used when closing apps to home screen.
*/
private void registerRemoteAnimations() {
+ // Unregister this
if (hasControlRemoteAppTransitionPermission()) {
try {
RemoteAnimationDefinitionCompat definition = new RemoteAnimationDefinitionCompat();
@@ -669,12 +676,36 @@
private RemoteAnimationRunnerCompat getWallpaperOpenRunner() {
return new LauncherAnimationRunner(mHandler) {
@Override
- public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) {
- if (mLauncher.getStateManager().getState().overviewUi) {
- // We use a separate transition for Overview mode.
- return null;
+ public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats,
+ Runnable runnable) {
+ if (mLauncher.getStateManager().getState().overviewUi
+ && mRemoteAnimationOverride != null) {
+ // This transition is only used for the fallback activity and should not be
+ // managed here (but necessary to implement here since the defined remote
+ // animation currently takes precendence over the one defined in the activity
+ // options).
+ mRemoteAnimationOverride.onAnimationStart(targetCompats, runnable);
+ return;
}
+ super.onAnimationStart(targetCompats, runnable);
+ }
+ @Override
+ public void onAnimationCancelled() {
+ if (mLauncher.getStateManager().getState().overviewUi
+ && mRemoteAnimationOverride != null) {
+ // This transition is only used for the fallback activity and should not be
+ // managed here (but necessary to implement here since the defined remote
+ // animation currently takes precendence over the one defined in the activity
+ // options).
+ mRemoteAnimationOverride.onAnimationCancelled();
+ return;
+ }
+ super.onAnimationCancelled();
+ }
+
+ @Override
+ public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) {
AnimatorSet anim = new AnimatorSet();
anim.play(getClosingWindowAnimators(targetCompats));
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index 4e3528c..3e96c44 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -36,8 +36,10 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppTransitionManagerImpl;
import com.android.launcher3.LauncherInitListener;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.util.ViewOnDrawExecutor;
@@ -80,7 +82,10 @@
ActivityInitListener createActivityInitListener(BiPredicate<T, Boolean> onInitListener);
- void startRecents(Context context, Intent intent, AssistDataReceiver assistDataReceiver,
+ void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver,
+ final RecentsAnimationListener remoteAnimationListener);
+
+ void startRecentsFromButton(Context context, Intent intent,
RecentsAnimationListener remoteAnimationListener);
@UiThread
@@ -203,21 +208,44 @@
}
@Override
- public void startRecents(Context context, Intent intent,
- AssistDataReceiver assistDataReceiver,
- RecentsAnimationListener remoteAnimationListener) {
+ public void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver,
+ final RecentsAnimationListener remoteAnimationListener) {
ActivityManagerWrapper.getInstance().startRecentsActivity(
intent, assistDataReceiver, remoteAnimationListener, null, null);
}
+ @Override
+ public void startRecentsFromButton(Context context, Intent intent,
+ RecentsAnimationListener remoteAnimationListener) {
+ // We should use the remove animation for the fallback activity recents button case,
+ // it works better with PiP. In Launcher, we have already registered the remote
+ // animation definition, which takes priority over explicitly defined remote
+ // animations in the provided activity options when starting the activity, so we
+ // just register a remote animation factory to get a callback to handle this.
+ LauncherAppTransitionManagerImpl appTransitionManager =
+ (LauncherAppTransitionManagerImpl) getLauncher().getAppTransitionManager();
+ appTransitionManager.setRemoteAnimationOverride(new RecentsAnimationActivityOptions(
+ remoteAnimationListener, () -> {
+ // Once the controller is finished, also reset the remote animation override
+ appTransitionManager.setRemoteAnimationOverride(null);
+ }));
+ context.startActivity(intent);
+ }
+
+ @Nullable
+ @UiThread
+ private Launcher getLauncher() {
+ LauncherAppState app = LauncherAppState.getInstanceNoCreate();
+ if (app == null) {
+ return null;
+ }
+ return (Launcher) app.getModel().getCallback();
+ }
+
@Nullable
@UiThread
private Launcher getVisibleLaucher() {
- LauncherAppState app = LauncherAppState.getInstanceNoCreate();
- if (app == null) {
- return null;
- }
- Launcher launcher = (Launcher) app.getModel().getCallback();
+ Launcher launcher = getLauncher();
return (launcher != null) && launcher.isStarted() && launcher.hasWindowFocus() ?
launcher : null;
}
@@ -325,12 +353,23 @@
}
@Override
- public void startRecents(Context context, Intent intent,
- AssistDataReceiver assistDataReceiver,
+ public void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver,
final RecentsAnimationListener remoteAnimationListener) {
- ActivityOptions options =
- ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
- new FallbackActivityOptions(remoteAnimationListener), 10000, 10000));
+ // We can use the normal recents animation for swipe up
+ ActivityManagerWrapper.getInstance().startRecentsActivity(
+ intent, assistDataReceiver, remoteAnimationListener, null, null);
+ }
+
+ @Override
+ public void startRecentsFromButton(Context context, Intent intent,
+ RecentsAnimationListener remoteAnimationListener) {
+ // We should use the remove animation for the fallback activity recents button case,
+ // it works better with PiP. For the fallback activity, we should not have registered
+ // the launcher app transition manager, so we should just start the remote animation here.
+ ActivityOptions options = ActivityOptionsCompat.makeRemoteAnimation(
+ new RemoteAnimationAdapterCompat(
+ new RecentsAnimationActivityOptions(remoteAnimationListener, null),
+ 10000, 10000));
context.startActivity(intent, options.toBundle());
}
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index 0ab2df7..4d695de 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -218,7 +218,7 @@
handler.initWhenReady();
TraceHelper.beginSection("RecentsController");
- Runnable startActivity = () -> mActivityControlHelper.startRecents(this, mHomeIntent,
+ Runnable startActivity = () -> mActivityControlHelper.startRecentsFromSwipe(mHomeIntent,
new AssistDataReceiver() {
@Override
public void onHandleAssistData(Bundle bundle) {
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 985a364..8e59578 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -53,6 +53,7 @@
import com.android.quickstep.util.SysuiEventLogger;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
+import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;
@@ -77,7 +78,7 @@
private static final int RID_CANCEL_CONTROLLER = 1;
private static final int RID_CANCEL_ZOOM_OUT_ANIMATION = 2;
- private static final long RECENTS_LAUNCH_DURATION = 150;
+ private static final long RECENTS_LAUNCH_DURATION = 200;
private static final String TAG = "OverviewCommandHelper";
private static final boolean DEBUG_START_FALLBACK_ACTIVITY = false;
@@ -151,12 +152,13 @@
private void initSwipeHandler(ActivityControlHelper helper, long time,
Consumer<WindowTransformSwipeHandler> onAnimationInitCallback) {
final int commandId = mCurrentCommandId;
- RunningTaskInfo taskInfo = ActivityManagerWrapper.getInstance().getRunningTask();
+ final RunningTaskInfo runningTask = ActivityManagerWrapper.getInstance().getRunningTask();
+ final int runningTaskId = runningTask.id;
final WindowTransformSwipeHandler handler =
- new WindowTransformSwipeHandler(taskInfo, mContext, time, helper);
+ new WindowTransformSwipeHandler(runningTask, mContext, time, helper);
// Preload the plan
- mRecentsModel.loadTasks(taskInfo.id, null);
+ mRecentsModel.loadTasks(runningTaskId, null);
mWindowTransformSwipeHandler = handler;
mTempTaskTargetRect.setEmpty();
@@ -172,13 +174,8 @@
addFinishCommand(commandId, RID_RESET_SWIPE_HANDLER, handler::reset);
TraceHelper.beginSection(TAG);
- Runnable startActivity = () -> helper.startRecents(mContext, homeIntent,
- new AssistDataReceiver() {
- @Override
- public void onHandleAssistData(Bundle bundle) {
- mRecentsModel.preloadAssistData(taskInfo.id, bundle);
- }
- },
+ Runnable startActivity = () -> helper.startRecentsFromButton(mContext,
+ addToIntent(homeIntent),
new RecentsAnimationListener() {
public void onAnimationStart(
RecentsAnimationControllerCompat controller,
@@ -190,11 +187,17 @@
minimizedHomeBounds);
mTempTaskTargetRect.set(handler.getTargetRect(mWindowSize));
+ ThumbnailData thumbnail = mAM.getTaskThumbnail(runningTaskId,
+ true /* reducedResolution */);
mMainThreadExecutor.execute(() -> {
addFinishCommand(commandId,
RID_CANCEL_CONTROLLER, () -> controller.finish(true));
if (commandId == mCurrentCommandId) {
onAnimationInitCallback.accept(handler);
+
+ // The animation has started, which means the other activity
+ // should be paused, lets update the thumbnail
+ handler.switchToScreenshotImmediate(thumbnail);
}
});
} else {
@@ -230,7 +233,7 @@
});
handler.onGestureStarted();
anim.setDuration(RECENTS_LAUNCH_DURATION);
- anim.setInterpolator(Interpolators.AGGRESSIVE_EASE);
+ anim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
anim.start();
addFinishCommand(commandId, RID_CANCEL_ZOOM_OUT_ANIMATION, anim::cancel);
}
@@ -241,6 +244,7 @@
return;
}
+ ActivityManagerWrapper.getInstance().closeSystemWindows("recentapps");
long time = SystemClock.elapsedRealtime();
mMainThreadExecutor.execute(() -> {
long elapsedTime = time - mLastToggleTime;
@@ -248,40 +252,37 @@
mCurrentCommandId++;
mTempTaskTargetRect.round(mTaskTargetRect);
- boolean isQuickTap = elapsedTime < ViewConfiguration.getDoubleTapTimeout();
int runnableCount = mCurrentCommandFinishRunnables.size();
if (runnableCount > 0) {
for (int i = 0; i < runnableCount; i++) {
mCurrentCommandFinishRunnables.valueAt(i).run();
}
mCurrentCommandFinishRunnables.clear();
- isQuickTap = true;
}
+ // TODO: We need to fix this case with PIP, when an activity first enters PIP, it shows
+ // the menu activity which takes window focus, prevening the right condition from
+ // being run below
ActivityControlHelper helper = getActivityControlHelper();
RecentsView recents = helper.getVisibleRecentsView();
if (recents != null) {
- int childCount = recents.getChildCount();
- if (childCount != 0) {
- ((TaskView) recents.getChildAt(childCount >= 2 ? 1 : 0)).launchTask(true);
+ // Launch the next task
+ recents.showNextTask();
+ } else {
+ if (elapsedTime < ViewConfiguration.getDoubleTapTimeout()) {
+ // The user tried to launch back into overview too quickly, either after
+ // launching an app, or before overview has actually shown, just ignore for now
+ return;
}
- // There are not enough tasks. Skip
- return;
+ // Start overview
+ if (helper.switchToRecentsIfVisible()) {
+ SysuiEventLogger.writeDummyRecentsTransition(0);
+ // Do nothing
+ } else {
+ initSwipeHandler(helper, time, this::startZoomOutAnim);
+ }
}
-
- if (isQuickTap) {
- // Focus last task. Start is on background thread so that all ActivityManager calls
- // are serialized
- BackgroundExecutor.get().submit(this::startLastTask);
- return;
- }
- if (helper.switchToRecentsIfVisible()) {
- SysuiEventLogger.writeDummyRecentsTransition(0);
- return;
- }
-
- initSwipeHandler(helper, time, this::startZoomOutAnim);
});
}
@@ -362,10 +363,6 @@
return false;
}
- public boolean isUsingFallbackActivity() {
- return DEBUG_START_FALLBACK_ACTIVITY;
- }
-
public ActivityControlHelper getActivityControlHelper() {
if (DEBUG_START_FALLBACK_ACTIVITY) {
return new FallbackActivityControllerHelper();
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityOptions.java b/quickstep/src/com/android/quickstep/RecentsAnimationActivityOptions.java
similarity index 71%
rename from quickstep/src/com/android/quickstep/FallbackActivityOptions.java
rename to quickstep/src/com/android/quickstep/RecentsAnimationActivityOptions.java
index 04352c3..a25e192 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityOptions.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationActivityOptions.java
@@ -24,24 +24,33 @@
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.TransactionCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import java.util.function.Consumer;
/**
- * Temporary class to create activity options to emulate recents transition for fallback activtiy.
+ * Class to create activity options to emulate recents transition.
*/
-public class FallbackActivityOptions implements RemoteAnimationRunnerCompat {
+public class RecentsAnimationActivityOptions implements RemoteAnimationRunnerCompat {
private final RecentsAnimationListener mListener;
+ private final Runnable mFinishCallback;
- public FallbackActivityOptions(RecentsAnimationListener listener) {
+ public RecentsAnimationActivityOptions(RecentsAnimationListener listener,
+ Runnable finishCallback) {
mListener = listener;
+ mFinishCallback = finishCallback;
}
@Override
public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats,
Runnable runnable) {
showOpeningTarget(targetCompats);
- DummyRecentsAnimationControllerCompat dummyRecentsAnim =
- new DummyRecentsAnimationControllerCompat(runnable);
+ RemoteRecentsAnimationControllerCompat dummyRecentsAnim =
+ new RemoteRecentsAnimationControllerCompat(() -> {
+ runnable.run();
+ if (mFinishCallback != null) {
+ mFinishCallback.run();
+ }
+ });
Rect insets = new Rect();
WindowManagerWrapper.getInstance().getStableInsets(insets);
@@ -54,23 +63,22 @@
}
private void showOpeningTarget(RemoteAnimationTargetCompat[] targetCompats) {
+ TransactionCompat t = new TransactionCompat();
for (RemoteAnimationTargetCompat target : targetCompats) {
- TransactionCompat t = new TransactionCompat();
int layer = target.mode == RemoteAnimationTargetCompat.MODE_CLOSING
? Integer.MAX_VALUE
: target.prefixOrderIndex;
t.setLayer(target.leash, layer);
t.show(target.leash);
- t.apply();
}
+ t.apply();
}
- private static class DummyRecentsAnimationControllerCompat
- extends RecentsAnimationControllerCompat {
+ private class RemoteRecentsAnimationControllerCompat extends RecentsAnimationControllerCompat {
final Runnable mFinishCallback;
- public DummyRecentsAnimationControllerCompat(Runnable finishCallback) {
+ public RemoteRecentsAnimationControllerCompat(Runnable finishCallback) {
mFinishCallback = finishCallback;
}
@@ -87,7 +95,8 @@
@Override
public void finish(boolean toHome) {
- if (toHome) {
+ // This should never be called with toHome == false
+ if (mFinishCallback != null) {
mFinishCallback.run();
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 1e43202..4652f2d 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -159,6 +159,16 @@
}
@Override
+ public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
+ mTaskChangeId++;
+ }
+
+ @Override
+ public void onActivityUnpinned() {
+ mTaskChangeId++;
+ }
+
+ @Override
public void onTaskStackChanged() {
mTaskChangeId++;
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 36a9d56..975c62b 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -196,6 +196,10 @@
private final long mTouchTimeMs;
private long mLauncherFrameDrawnTime;
+ // Only used with the recents activity, when the screenshot should be fetched at the beginning
+ // of the animation and not at the end when the activity is already paused
+ private boolean mSkipScreenshotAtEndOfTransition;
+
WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs,
ActivityControlHelper<T> controller) {
mContext = context;
@@ -582,7 +586,6 @@
mSourceStackBounds.set(target.sourceContainerBounds);
initTransitionEndpoints(dp);
- break;
}
}
}
@@ -725,8 +728,9 @@
() -> setStateOnUiThread(STATE_SWITCH_TO_SCREENSHOT_COMPLETE));
}
};
+
synchronized (mRecentsAnimationWrapper) {
- if (mRecentsAnimationWrapper.controller != null) {
+ if (mRecentsAnimationWrapper.controller != null && !mSkipScreenshotAtEndOfTransition) {
TransactionCompat transaction = new TransactionCompat();
for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) {
if (app.mode == MODE_CLOSING) {
@@ -753,6 +757,12 @@
doLogGesture(true /* toLauncher */);
}
+ @UiThread
+ public void switchToScreenshotImmediate(ThumbnailData thumbnail) {
+ mRecentsView.updateThumbnail(mRunningTaskId, thumbnail);
+ mSkipScreenshotAtEndOfTransition = true;
+ }
+
private void setupLauncherUiAfterSwipeUpAnimation() {
if (mLauncherTransitionController != null) {
mLauncherTransitionController.getAnimationPlayer().end();
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index e7f69b7..592dc2d 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -126,6 +126,26 @@
}
}
}
+
+ @Override
+ public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
+ // Check this is for the right user
+ if (!checkCurrentUserId(userId, false /* debug */)) {
+ return;
+ }
+
+ // Remove the task immediately from the task list
+ TaskView taskView = getTaskView(taskId);
+ if (taskView != null) {
+ removeView(taskView);
+ }
+ }
+
+ @Override
+ public void onActivityUnpinned() {
+ // TODO: Re-enable layout transitions for addition of the unpinned task
+ reloadIfNeeded();
+ }
};
private int mLoadPlanId = -1;
@@ -581,6 +601,23 @@
}
}
+ public void showNextTask() {
+ TaskView runningTaskView = getTaskView(mRunningTaskId);
+ if (runningTaskView == null) {
+ // Launch the first task
+ if (getChildCount() > 0) {
+ ((TaskView) getChildAt(0)).launchTask(true /* animate */);
+ }
+ } else {
+ // Get the next launch task
+ int runningTaskIndex = indexOfChild(runningTaskView);
+ int nextTaskIndex = Math.max(0, Math.min(getChildCount() - 1, runningTaskIndex + 1));
+ if (nextTaskIndex < getChildCount()) {
+ ((TaskView) getChildAt(nextTaskIndex)).launchTask(true /* animate */);
+ }
+ }
+ }
+
public QuickScrubController getQuickScrubController() {
return mQuickScrubController;
}