Make sure that a recents-launch with remote gets its own transition
If a remote is attached to an activity-launch, it should be its own
transition so that the requester can get the proper transition
lifecycle events (handleRequest). Unfortunately, the current
startActivity API is synchronous, so we don't know if the caller
needs an accurate result or not so normally we have to merge all
launches meaning the remote can get lost.
Fortunately, for recents, we do know that launcher cares about
the transition lifecycle and not the startActivity result. So,
in this case, we can defer the activity start if necessary.
Bug: 250012839
Test: launch app with dialogactivity on top. Swipe to recents.
Change-Id: I715518bf9611b8ad50bbfb5b05dea8002cb5a6e5
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 0707b81..30454d4 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -50,6 +50,7 @@
import android.util.SparseArray;
import android.view.RemoteAnimationAdapter;
import android.view.WindowManager;
+import android.window.RemoteTransition;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
@@ -563,14 +564,39 @@
return false;
}
mService.mRootWindowContainer.startPowerModeLaunchIfNeeded(true /* forceSend */, r);
- final ActivityMetricsLogger.LaunchingState launchingState =
- mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent);
- final Task task = r.getTask();
- mService.deferWindowLayout();
- try {
+ final RemoteTransition remote = options.getRemoteTransition();
+ if (remote != null && rootTask.mTransitionController.isCollecting()) {
+ final Transition transition = new Transition(WindowManager.TRANSIT_TO_FRONT,
+ 0 /* flags */, rootTask.mTransitionController,
+ mService.mWindowManager.mSyncEngine);
+ // Special case: we are entering recents while an existing transition is running. In
+ // this case, we know it's safe to "defer" the activity launch, so lets do so now so
+ // that it can get its own transition and thus update launcher correctly.
+ mService.mWindowManager.mSyncEngine.queueSyncSet(
+ () -> rootTask.mTransitionController.moveToCollecting(transition),
+ () -> {
+ final Task task = r.getTask();
+ task.mTransitionController.requestStartTransition(transition,
+ task, remote, null /* displayChange */);
+ task.mTransitionController.collect(task);
+ startExistingRecentsIfPossibleInner(intent, options, r, task, rootTask);
+ });
+ } else {
+ final Task task = r.getTask();
task.mTransitionController.requestTransitionIfNeeded(WindowManager.TRANSIT_TO_FRONT,
0 /* flags */, task, task /* readyGroupRef */,
options.getRemoteTransition(), null /* displayChange */);
+ startExistingRecentsIfPossibleInner(intent, options, r, task, rootTask);
+ }
+ return true;
+ }
+
+ void startExistingRecentsIfPossibleInner(Intent intent, ActivityOptions options,
+ ActivityRecord r, Task task, Task rootTask) {
+ final ActivityMetricsLogger.LaunchingState launchingState =
+ mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent);
+ mService.deferWindowLayout();
+ try {
r.mTransitionController.setTransientLaunch(r,
TaskDisplayArea.getRootTaskAbove(rootTask));
task.moveToFront("startExistingRecents");
@@ -582,7 +608,6 @@
task.mInResumeTopActivity = false;
mService.continueWindowLayout();
}
- return true;
}
void registerRemoteAnimationForNextActivityStart(String packageName,