Merge "Add multi-task support to recents-animation task-appeared" into sc-v2-dev am: 35b8e2b997

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16184046

Change-Id: I57d186d78773bbd2bbb5c5095ff6a7110a8cdd04
This commit is contained in:
Winson Chung 2021-11-10 17:28:05 +00:00 committed by Automerger Merge Worker
commit c7e8bbf286
8 changed files with 127 additions and 51 deletions

View File

@ -217,7 +217,7 @@ public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase
}
@Override
public void onTaskAppeared(RemoteAnimationTarget app) throws RemoteException {
public void onTasksAppeared(RemoteAnimationTarget[] app) throws RemoteException {
/* no-op */
}
};

View File

@ -63,5 +63,5 @@ oneway interface IRecentsAnimationRunner {
* 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;
}

View File

@ -195,8 +195,13 @@ public class ActivityManagerWrapper {
}
@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);
}
};
}

View File

@ -39,5 +39,5 @@ public interface RecentsAnimationListener {
* 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);
}

View File

@ -53,6 +53,7 @@ import com.android.internal.annotations.VisibleForTesting;
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 @@ public class RemoteTransitionCompat implements Parcelable {
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 @@ public class RemoteTransitionCompat implements Parcelable {
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 @@ public class RemoteTransitionCompat implements Parcelable {
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 @@ public class RemoteTransitionCompat implements Parcelable {
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 @@ public class RemoteTransitionCompat implements Parcelable {
mWrapped = wrapped;
mInfo = info;
mFinishCB = finishCB;
mPausingTask = pausingTask;
mPausingTasks = pausingTasks;
mPipTask = pipTask;
mLeashMap = leashMap;
mTransition = transition;
@ -226,36 +228,57 @@ public class RemoteTransitionCompat implements Parcelable {
@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 @@ public class RemoteTransitionCompat implements Parcelable {
}
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 @@ public class RemoteTransitionCompat implements Parcelable {
// Reset all members.
mWrapped = null;
mFinishCB = null;
mPausingTask = null;
mPausingTasks = null;
mInfo = null;
mOpeningLeash = null;
mOpeningLeashes = null;
mLeashMap = null;
mTransition = null;
}

View File

@ -934,6 +934,10 @@ public class AppTransitionController {
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;

View File

@ -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;
@ -163,6 +164,8 @@ public class RecentsAnimationController implements DeathRecipient {
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.
@ -732,11 +735,19 @@ public class RecentsAnimationController implements DeathRecipient {
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);
}
}
@ -744,10 +755,15 @@ public class RecentsAnimationController implements DeathRecipient {
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) {
@ -782,7 +798,8 @@ public class RecentsAnimationController implements DeathRecipient {
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 {
@ -995,6 +1012,8 @@ public class RecentsAnimationController implements DeathRecipient {
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);
@ -1224,7 +1243,14 @@ public class RecentsAnimationController implements DeathRecipient {
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()
@ -1238,7 +1264,10 @@ public class RecentsAnimationController implements DeathRecipient {
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(),

View File

@ -2380,6 +2380,16 @@ class Task extends TaskFragment {
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]++; },