Merge "Add multi-task support to recents-animation task-appeared" into sc-v2-dev am: 35b8e2b997 am: c7e8bbf286
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16184046
Change-Id: I739695f78712172bb90836df465e0b76492c99e9
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
index 1c40a06..42fb24f 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
@@ -217,7 +217,7 @@
}
@Override
- public void onTaskAppeared(RemoteAnimationTarget app) throws RemoteException {
+ public void onTasksAppeared(RemoteAnimationTarget[] app) throws RemoteException {
/* no-op */
}
};
diff --git a/core/java/android/view/IRecentsAnimationRunner.aidl b/core/java/android/view/IRecentsAnimationRunner.aidl
index aca17e4..c7fd380 100644
--- a/core/java/android/view/IRecentsAnimationRunner.aidl
+++ b/core/java/android/view/IRecentsAnimationRunner.aidl
@@ -63,5 +63,5 @@
* Called when the task of an activity that has been started while the recents animation
* was running becomes ready for control.
*/
- void onTaskAppeared(in RemoteAnimationTarget app) = 3;
+ void onTasksAppeared(in RemoteAnimationTarget[] app) = 3;
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index b95123d..38eded8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -195,8 +195,13 @@
}
@Override
- public void onTaskAppeared(RemoteAnimationTarget app) {
- animationHandler.onTaskAppeared(new RemoteAnimationTargetCompat(app));
+ public void onTasksAppeared(RemoteAnimationTarget[] apps) {
+ final RemoteAnimationTargetCompat[] compats =
+ new RemoteAnimationTargetCompat[apps.length];
+ for (int i = 0; i < apps.length; ++i) {
+ compats[i] = new RemoteAnimationTargetCompat(apps[i]);
+ }
+ animationHandler.onTasksAppeared(compats);
}
};
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
index a74de2e..48f1b76 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
@@ -39,5 +39,5 @@
* Called when the task of an activity that has been started while the recents animation
* was running becomes ready for control.
*/
- void onTaskAppeared(RemoteAnimationTargetCompat app);
+ void onTasksAppeared(RemoteAnimationTargetCompat[] app);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index 99b6aed..954cf9f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -53,6 +53,7 @@
import com.android.internal.util.DataClass;
import com.android.systemui.shared.recents.model.ThumbnailData;
+import java.util.ArrayList;
import java.util.concurrent.Executor;
/**
@@ -127,7 +128,7 @@
mToken = transition;
// This transition is for opening recents, so recents is on-top. We want to draw
// the current going-away task on top of recents, though, so move it to front
- WindowContainerToken pausingTask = null;
+ final ArrayList<WindowContainerToken> pausingTasks = new ArrayList<>();
WindowContainerToken pipTask = null;
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
@@ -138,7 +139,8 @@
if (taskInfo == null) {
continue;
}
- pausingTask = taskInfo.token;
+ // Add to front since we are iterating backwards.
+ pausingTasks.add(0, taskInfo.token);
if (taskInfo.pictureInPictureParams != null
&& taskInfo.pictureInPictureParams.isAutoEnterEnabled()) {
pipTask = taskInfo.token;
@@ -150,7 +152,7 @@
t.setAlpha(wallpapers[i].leash.mSurfaceControl, 1);
}
t.apply();
- mRecentsSession.setup(controller, info, finishedCallback, pausingTask, pipTask,
+ mRecentsSession.setup(controller, info, finishedCallback, pausingTasks, pipTask,
leashMap, mToken);
recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0),
new Rect());
@@ -198,18 +200,18 @@
static class RecentsControllerWrap extends RecentsAnimationControllerCompat {
private RecentsAnimationControllerCompat mWrapped = null;
private IRemoteTransitionFinishedCallback mFinishCB = null;
- private WindowContainerToken mPausingTask = null;
+ private ArrayList<WindowContainerToken> mPausingTasks = null;
private WindowContainerToken mPipTask = null;
private TransitionInfo mInfo = null;
- private SurfaceControl mOpeningLeash = null;
+ private ArrayList<SurfaceControl> mOpeningLeashes = null;
private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null;
private PictureInPictureSurfaceTransaction mPipTransaction = null;
private IBinder mTransition = null;
void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info,
- IRemoteTransitionFinishedCallback finishCB, WindowContainerToken pausingTask,
- WindowContainerToken pipTask, ArrayMap<SurfaceControl, SurfaceControl> leashMap,
- IBinder transition) {
+ IRemoteTransitionFinishedCallback finishCB,
+ ArrayList<WindowContainerToken> pausingTasks, WindowContainerToken pipTask,
+ ArrayMap<SurfaceControl, SurfaceControl> leashMap, IBinder transition) {
if (mInfo != null) {
throw new IllegalStateException("Trying to run a new recents animation while"
+ " recents is already active.");
@@ -217,7 +219,7 @@
mWrapped = wrapped;
mInfo = info;
mFinishCB = finishCB;
- mPausingTask = pausingTask;
+ mPausingTasks = pausingTasks;
mPipTask = pipTask;
mLeashMap = leashMap;
mTransition = transition;
@@ -226,36 +228,57 @@
@SuppressLint("NewApi")
boolean merge(TransitionInfo info, SurfaceControl.Transaction t,
RecentsAnimationListener recents) {
- TransitionInfo.Change openingTask = null;
+ ArrayList<TransitionInfo.Change> openingTasks = null;
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) {
if (change.getTaskInfo() != null) {
- if (openingTask != null) {
- Log.w(TAG, " Expecting to merge a task-open, but got >1 opening "
- + "tasks");
+ if (openingTasks == null) {
+ openingTasks = new ArrayList<>();
}
- openingTask = change;
+ openingTasks.add(change);
}
}
}
- if (openingTask == null) return false;
- mOpeningLeash = openingTask.getLeash();
- if (openingTask.getContainer().equals(mPausingTask)) {
- // In this case, we are "returning" to the already running app, so just consume
+ if (openingTasks == null) return false;
+ int pauseMatches = 0;
+ for (int i = 0; i < openingTasks.size(); ++i) {
+ if (mPausingTasks.contains(openingTasks.get(i).getContainer())) {
+ ++pauseMatches;
+ }
+ if (openingTasks.get(i).getContainer().equals(mPausingTasks.get(i))) {
+ // In this case, we are "returning" to an already running app, so just consume
+ // the merge and do nothing.
+ }
+ }
+ if (pauseMatches > 0) {
+ if (pauseMatches != mPausingTasks.size()) {
+ // We are not really "returning" properly... something went wrong.
+ throw new IllegalStateException("\"Concelling\" a recents transitions by "
+ + "unpausing " + pauseMatches + " apps after pausing "
+ + mPausingTasks.size() + " apps.");
+ }
+ // In this case, we are "returning" to an already running app, so just consume
// the merge and do nothing.
return true;
}
- // We are receiving a new opening task, so convert to onTaskAppeared.
final int layer = mInfo.getChanges().size() * 3;
- final RemoteAnimationTargetCompat target = new RemoteAnimationTargetCompat(
- openingTask, layer, mInfo, t);
- mLeashMap.put(mOpeningLeash, target.leash.mSurfaceControl);
- t.reparent(target.leash.mSurfaceControl, mInfo.getRootLeash());
- t.setLayer(target.leash.mSurfaceControl, layer);
- t.hide(target.leash.mSurfaceControl);
- t.apply();
- recents.onTaskAppeared(target);
+ mOpeningLeashes = new ArrayList<>();
+ final RemoteAnimationTargetCompat[] targets =
+ new RemoteAnimationTargetCompat[openingTasks.size()];
+ for (int i = 0; i < openingTasks.size(); ++i) {
+ mOpeningLeashes.add(openingTasks.get(i).getLeash());
+ // We are receiving new opening tasks, so convert to onTasksAppeared.
+ final RemoteAnimationTargetCompat target = new RemoteAnimationTargetCompat(
+ openingTasks.get(i), layer, mInfo, t);
+ mLeashMap.put(mOpeningLeashes.get(i), target.leash.mSurfaceControl);
+ t.reparent(target.leash.mSurfaceControl, mInfo.getRootLeash());
+ t.setLayer(target.leash.mSurfaceControl, layer);
+ t.hide(target.leash.mSurfaceControl);
+ t.apply();
+ targets[i] = target;
+ }
+ recents.onTasksAppeared(targets);
return true;
}
@@ -292,21 +315,26 @@
}
if (mWrapped != null) mWrapped.finish(toHome, sendUserLeaveHint);
try {
- if (!toHome && mPausingTask != null && mOpeningLeash == null) {
+ if (!toHome && mPausingTasks != null && mOpeningLeashes == null) {
// The gesture went back to opening the app rather than continuing with
// recents, so end the transition by moving the app back to the top (and also
// re-showing it's task).
final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.reorder(mPausingTask, true /* onTop */);
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- t.show(mInfo.getChange(mPausingTask).getLeash());
+ for (int i = mPausingTasks.size() - 1; i >= 0; ++i) {
+ // reverse order so that index 0 ends up on top
+ wct.reorder(mPausingTasks.get(i), true /* onTop */);
+ t.show(mInfo.getChange(mPausingTasks.get(i)).getLeash());
+ }
mFinishCB.onTransitionFinished(wct, t);
} else {
- if (mOpeningLeash != null) {
+ if (mOpeningLeashes != null) {
// TODO: the launcher animation should handle this
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- t.show(mOpeningLeash);
- t.setAlpha(mOpeningLeash, 1.f);
+ for (int i = 0; i < mOpeningLeashes.size(); ++i) {
+ t.show(mOpeningLeashes.get(i));
+ t.setAlpha(mOpeningLeashes.get(i), 1.f);
+ }
t.apply();
}
if (mPipTask != null && mPipTransaction != null) {
@@ -339,9 +367,9 @@
// Reset all members.
mWrapped = null;
mFinishCB = null;
- mPausingTask = null;
+ mPausingTasks = null;
mInfo = null;
- mOpeningLeash = null;
+ mOpeningLeashes = null;
mLeashMap = null;
mTransition = null;
}
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 535a061..f947773 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -934,6 +934,10 @@
voiceInteraction);
applyAnimations(closingWcs, closingApps, transit, false /* visible */, animLp,
voiceInteraction);
+ final RecentsAnimationController rac = mService.getRecentsAnimationController();
+ if (rac != null) {
+ rac.sendTasksAppeared();
+ }
for (int i = 0; i < openingApps.size(); ++i) {
openingApps.valueAtUnchecked(i).mOverrideTaskTransition = false;
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 634f489..38e3e3a 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
@@ -162,6 +163,8 @@
private boolean mNavigationBarAttachedToApp;
private ActivityRecord mNavBarAttachedApp;
+ private final ArrayList<RemoteAnimationTarget> mPendingTaskAppears = new ArrayList<>();
+
/**
* An app transition listener to cancel the recents animation only after the app transition
* starts or is canceled.
@@ -731,11 +734,19 @@
return;
}
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addTaskToTargets, target: %s", target);
- try {
- mRunner.onTaskAppeared(target);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to report task appeared", e);
- }
+ mPendingTaskAppears.add(target);
+ }
+ }
+
+ void sendTasksAppeared() {
+ if (mPendingTaskAppears.isEmpty() || mRunner == null) return;
+ try {
+ final RemoteAnimationTarget[] targets = mPendingTaskAppears.toArray(
+ new RemoteAnimationTarget[0]);
+ mRunner.onTasksAppeared(targets);
+ mPendingTaskAppears.clear();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to report task appeared", e);
}
}
@@ -743,10 +754,15 @@
OnAnimationFinishedCallback finishedCallback) {
final SparseBooleanArray recentTaskIds =
mService.mAtmService.getRecentTasks().getRecentTaskIds();
+ // The target must be built off the root task (the leaf task surface would be cropped
+ // within the root surface). However, recents only tracks leaf task ids, so we'll replace
+ // the task-id with the leaf id.
+ final Task leafTask = task.getTopLeafTask();
+ int taskId = leafTask.mTaskId;
TaskAnimationAdapter adapter = (TaskAnimationAdapter) addAnimation(task,
- !recentTaskIds.get(task.mTaskId), true /* hidden */, finishedCallback);
- mPendingNewTaskTargets.add(task.mTaskId);
- return adapter.createRemoteAnimationTarget();
+ !recentTaskIds.get(taskId), true /* hidden */, finishedCallback);
+ mPendingNewTaskTargets.add(taskId);
+ return adapter.createRemoteAnimationTarget(taskId);
}
void logRecentsAnimationStartTime(int durationMs) {
@@ -781,7 +797,8 @@
final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
- final RemoteAnimationTarget target = taskAdapter.createRemoteAnimationTarget();
+ final RemoteAnimationTarget target =
+ taskAdapter.createRemoteAnimationTarget(INVALID_TASK_ID);
if (target != null) {
targets.add(target);
} else {
@@ -994,6 +1011,8 @@
removeAnimation(taskAdapter);
taskAdapter.onCleanup();
}
+ // Should already be empty, but clean-up pending task-appears in-case they weren't sent.
+ mPendingTaskAppears.clear();
for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) {
final WallpaperAnimationAdapter wallpaperAdapter = mPendingWallpaperAnimations.get(i);
@@ -1217,7 +1236,14 @@
mLocalBounds.offsetTo(tmpPos.x, tmpPos.y);
}
- RemoteAnimationTarget createRemoteAnimationTarget() {
+ /**
+ * @param overrideTaskId overrides the target's taskId. It may differ from mTaskId and thus
+ * can differ from taskInfo. This mismatch is needed, however, in
+ * some cases where we are animating root tasks but need need leaf
+ * ids for identification. If this is INVALID (-1), then mTaskId
+ * will be used.
+ */
+ RemoteAnimationTarget createRemoteAnimationTarget(int overrideTaskId) {
final ActivityRecord topApp = mTask.getTopVisibleActivity();
final WindowState mainWindow = topApp != null
? topApp.findMainWindow()
@@ -1231,7 +1257,10 @@
final int mode = topApp.getActivityType() == mTargetActivityType
? MODE_OPENING
: MODE_CLOSING;
- mTarget = new RemoteAnimationTarget(mTask.mTaskId, mode, mCapturedLeash,
+ if (overrideTaskId < 0) {
+ overrideTaskId = mTask.mTaskId;
+ }
+ mTarget = new RemoteAnimationTarget(overrideTaskId, mode, mCapturedLeash,
!topApp.fillsParent(), new Rect(),
insets, mTask.getPrefixOrderIndex(), new Point(mBounds.left, mBounds.top),
mLocalBounds, mBounds, mTask.getWindowConfiguration(),
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 367feac..4a8f362 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2366,6 +2366,16 @@
return true;
}
+ /** Return the top-most leaf-task under this one, or this task if it is a leaf. */
+ public Task getTopLeafTask() {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final Task child = mChildren.get(i).asTask();
+ if (child == null) continue;
+ return child.getTopLeafTask();
+ }
+ return this;
+ }
+
int getDescendantTaskCount() {
final int[] currentCount = {0};
final PooledConsumer c = PooledLambda.obtainConsumer((t, count) -> { count[0]++; },