Merge "Add multi-task support to recents-animation task-appeared" into sc-v2-dev

This commit is contained in:
Winson Chung
2021-11-10 17:05:46 +00:00
committed by Android (Google) Code Review
8 changed files with 127 additions and 51 deletions

View File

@@ -217,7 +217,7 @@ public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase
} }
@Override @Override
public void onTaskAppeared(RemoteAnimationTarget app) throws RemoteException { public void onTasksAppeared(RemoteAnimationTarget[] app) throws RemoteException {
/* no-op */ /* 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 * Called when the task of an activity that has been started while the recents animation
* was running becomes ready for control. * 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 @Override
public void onTaskAppeared(RemoteAnimationTarget app) { public void onTasksAppeared(RemoteAnimationTarget[] apps) {
animationHandler.onTaskAppeared(new RemoteAnimationTargetCompat(app)); 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 * Called when the task of an activity that has been started while the recents animation
* was running becomes ready for control. * 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.internal.util.DataClass;
import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.recents.model.ThumbnailData;
import java.util.ArrayList;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
/** /**
@@ -127,7 +128,7 @@ public class RemoteTransitionCompat implements Parcelable {
mToken = transition; mToken = transition;
// This transition is for opening recents, so recents is on-top. We want to draw // 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 // 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; WindowContainerToken pipTask = null;
for (int i = info.getChanges().size() - 1; i >= 0; --i) { for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i); final TransitionInfo.Change change = info.getChanges().get(i);
@@ -138,7 +139,8 @@ public class RemoteTransitionCompat implements Parcelable {
if (taskInfo == null) { if (taskInfo == null) {
continue; continue;
} }
pausingTask = taskInfo.token; // Add to front since we are iterating backwards.
pausingTasks.add(0, taskInfo.token);
if (taskInfo.pictureInPictureParams != null if (taskInfo.pictureInPictureParams != null
&& taskInfo.pictureInPictureParams.isAutoEnterEnabled()) { && taskInfo.pictureInPictureParams.isAutoEnterEnabled()) {
pipTask = taskInfo.token; pipTask = taskInfo.token;
@@ -150,7 +152,7 @@ public class RemoteTransitionCompat implements Parcelable {
t.setAlpha(wallpapers[i].leash.mSurfaceControl, 1); t.setAlpha(wallpapers[i].leash.mSurfaceControl, 1);
} }
t.apply(); t.apply();
mRecentsSession.setup(controller, info, finishedCallback, pausingTask, pipTask, mRecentsSession.setup(controller, info, finishedCallback, pausingTasks, pipTask,
leashMap, mToken); leashMap, mToken);
recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0), recents.onAnimationStart(mRecentsSession, apps, wallpapers, new Rect(0, 0, 0, 0),
new Rect()); new Rect());
@@ -198,18 +200,18 @@ public class RemoteTransitionCompat implements Parcelable {
static class RecentsControllerWrap extends RecentsAnimationControllerCompat { static class RecentsControllerWrap extends RecentsAnimationControllerCompat {
private RecentsAnimationControllerCompat mWrapped = null; private RecentsAnimationControllerCompat mWrapped = null;
private IRemoteTransitionFinishedCallback mFinishCB = null; private IRemoteTransitionFinishedCallback mFinishCB = null;
private WindowContainerToken mPausingTask = null; private ArrayList<WindowContainerToken> mPausingTasks = null;
private WindowContainerToken mPipTask = null; private WindowContainerToken mPipTask = null;
private TransitionInfo mInfo = null; private TransitionInfo mInfo = null;
private SurfaceControl mOpeningLeash = null; private ArrayList<SurfaceControl> mOpeningLeashes = null;
private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null; private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null;
private PictureInPictureSurfaceTransaction mPipTransaction = null; private PictureInPictureSurfaceTransaction mPipTransaction = null;
private IBinder mTransition = null; private IBinder mTransition = null;
void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info, void setup(RecentsAnimationControllerCompat wrapped, TransitionInfo info,
IRemoteTransitionFinishedCallback finishCB, WindowContainerToken pausingTask, IRemoteTransitionFinishedCallback finishCB,
WindowContainerToken pipTask, ArrayMap<SurfaceControl, SurfaceControl> leashMap, ArrayList<WindowContainerToken> pausingTasks, WindowContainerToken pipTask,
IBinder transition) { ArrayMap<SurfaceControl, SurfaceControl> leashMap, IBinder transition) {
if (mInfo != null) { if (mInfo != null) {
throw new IllegalStateException("Trying to run a new recents animation while" throw new IllegalStateException("Trying to run a new recents animation while"
+ " recents is already active."); + " recents is already active.");
@@ -217,7 +219,7 @@ public class RemoteTransitionCompat implements Parcelable {
mWrapped = wrapped; mWrapped = wrapped;
mInfo = info; mInfo = info;
mFinishCB = finishCB; mFinishCB = finishCB;
mPausingTask = pausingTask; mPausingTasks = pausingTasks;
mPipTask = pipTask; mPipTask = pipTask;
mLeashMap = leashMap; mLeashMap = leashMap;
mTransition = transition; mTransition = transition;
@@ -226,36 +228,57 @@ public class RemoteTransitionCompat implements Parcelable {
@SuppressLint("NewApi") @SuppressLint("NewApi")
boolean merge(TransitionInfo info, SurfaceControl.Transaction t, boolean merge(TransitionInfo info, SurfaceControl.Transaction t,
RecentsAnimationListener recents) { RecentsAnimationListener recents) {
TransitionInfo.Change openingTask = null; ArrayList<TransitionInfo.Change> openingTasks = null;
for (int i = info.getChanges().size() - 1; i >= 0; --i) { for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i); final TransitionInfo.Change change = info.getChanges().get(i);
if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) { if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) {
if (change.getTaskInfo() != null) { if (change.getTaskInfo() != null) {
if (openingTask != null) { if (openingTasks == null) {
Log.w(TAG, " Expecting to merge a task-open, but got >1 opening " openingTasks = new ArrayList<>();
+ "tasks");
} }
openingTask = change; openingTasks.add(change);
} }
} }
} }
if (openingTask == null) return false; if (openingTasks == null) return false;
mOpeningLeash = openingTask.getLeash(); int pauseMatches = 0;
if (openingTask.getContainer().equals(mPausingTask)) { for (int i = 0; i < openingTasks.size(); ++i) {
// In this case, we are "returning" to the already running app, so just consume 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. // the merge and do nothing.
return true; return true;
} }
// We are receiving a new opening task, so convert to onTaskAppeared.
final int layer = mInfo.getChanges().size() * 3; final int layer = mInfo.getChanges().size() * 3;
final RemoteAnimationTargetCompat target = new RemoteAnimationTargetCompat( mOpeningLeashes = new ArrayList<>();
openingTask, layer, mInfo, t); final RemoteAnimationTargetCompat[] targets =
mLeashMap.put(mOpeningLeash, target.leash.mSurfaceControl); new RemoteAnimationTargetCompat[openingTasks.size()];
t.reparent(target.leash.mSurfaceControl, mInfo.getRootLeash()); for (int i = 0; i < openingTasks.size(); ++i) {
t.setLayer(target.leash.mSurfaceControl, layer); mOpeningLeashes.add(openingTasks.get(i).getLeash());
t.hide(target.leash.mSurfaceControl); // We are receiving new opening tasks, so convert to onTasksAppeared.
t.apply(); final RemoteAnimationTargetCompat target = new RemoteAnimationTargetCompat(
recents.onTaskAppeared(target); 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; return true;
} }
@@ -292,21 +315,26 @@ public class RemoteTransitionCompat implements Parcelable {
} }
if (mWrapped != null) mWrapped.finish(toHome, sendUserLeaveHint); if (mWrapped != null) mWrapped.finish(toHome, sendUserLeaveHint);
try { 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 // 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 // recents, so end the transition by moving the app back to the top (and also
// re-showing it's task). // re-showing it's task).
final WindowContainerTransaction wct = new WindowContainerTransaction(); final WindowContainerTransaction wct = new WindowContainerTransaction();
wct.reorder(mPausingTask, true /* onTop */);
final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); 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); mFinishCB.onTransitionFinished(wct, t);
} else { } else {
if (mOpeningLeash != null) { if (mOpeningLeashes != null) {
// TODO: the launcher animation should handle this // TODO: the launcher animation should handle this
final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
t.show(mOpeningLeash); for (int i = 0; i < mOpeningLeashes.size(); ++i) {
t.setAlpha(mOpeningLeash, 1.f); t.show(mOpeningLeashes.get(i));
t.setAlpha(mOpeningLeashes.get(i), 1.f);
}
t.apply(); t.apply();
} }
if (mPipTask != null && mPipTransaction != null) { if (mPipTask != null && mPipTransaction != null) {
@@ -339,9 +367,9 @@ public class RemoteTransitionCompat implements Parcelable {
// Reset all members. // Reset all members.
mWrapped = null; mWrapped = null;
mFinishCB = null; mFinishCB = null;
mPausingTask = null; mPausingTasks = null;
mInfo = null; mInfo = null;
mOpeningLeash = null; mOpeningLeashes = null;
mLeashMap = null; mLeashMap = null;
mTransition = null; mTransition = null;
} }

View File

@@ -934,6 +934,10 @@ public class AppTransitionController {
voiceInteraction); voiceInteraction);
applyAnimations(closingWcs, closingApps, transit, false /* visible */, animLp, applyAnimations(closingWcs, closingApps, transit, false /* visible */, animLp,
voiceInteraction); voiceInteraction);
final RecentsAnimationController rac = mService.getRecentsAnimationController();
if (rac != null) {
rac.sendTasksAppeared();
}
for (int i = 0; i < openingApps.size(); ++i) { for (int i = 0; i < openingApps.size(); ++i) {
openingApps.valueAtUnchecked(i).mOverrideTaskTransition = false; openingApps.valueAtUnchecked(i).mOverrideTaskTransition = false;

View File

@@ -16,6 +16,7 @@
package com.android.server.wm; 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.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
@@ -163,6 +164,8 @@ public class RecentsAnimationController implements DeathRecipient {
private boolean mNavigationBarAttachedToApp; private boolean mNavigationBarAttachedToApp;
private ActivityRecord mNavBarAttachedApp; private ActivityRecord mNavBarAttachedApp;
private final ArrayList<RemoteAnimationTarget> mPendingTaskAppears = new ArrayList<>();
/** /**
* An app transition listener to cancel the recents animation only after the app transition * An app transition listener to cancel the recents animation only after the app transition
* starts or is canceled. * starts or is canceled.
@@ -732,11 +735,19 @@ public class RecentsAnimationController implements DeathRecipient {
return; return;
} }
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addTaskToTargets, target: %s", target); ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addTaskToTargets, target: %s", target);
try { mPendingTaskAppears.add(target);
mRunner.onTaskAppeared(target); }
} catch (RemoteException e) { }
Slog.e(TAG, "Failed to report task appeared", e);
} 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) { OnAnimationFinishedCallback finishedCallback) {
final SparseBooleanArray recentTaskIds = final SparseBooleanArray recentTaskIds =
mService.mAtmService.getRecentTasks().getRecentTaskIds(); 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, TaskAnimationAdapter adapter = (TaskAnimationAdapter) addAnimation(task,
!recentTaskIds.get(task.mTaskId), true /* hidden */, finishedCallback); !recentTaskIds.get(taskId), true /* hidden */, finishedCallback);
mPendingNewTaskTargets.add(task.mTaskId); mPendingNewTaskTargets.add(taskId);
return adapter.createRemoteAnimationTarget(); return adapter.createRemoteAnimationTarget(taskId);
} }
void logRecentsAnimationStartTime(int durationMs) { void logRecentsAnimationStartTime(int durationMs) {
@@ -782,7 +798,8 @@ public class RecentsAnimationController implements DeathRecipient {
final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>(); final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i); final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
final RemoteAnimationTarget target = taskAdapter.createRemoteAnimationTarget(); final RemoteAnimationTarget target =
taskAdapter.createRemoteAnimationTarget(INVALID_TASK_ID);
if (target != null) { if (target != null) {
targets.add(target); targets.add(target);
} else { } else {
@@ -995,6 +1012,8 @@ public class RecentsAnimationController implements DeathRecipient {
removeAnimation(taskAdapter); removeAnimation(taskAdapter);
taskAdapter.onCleanup(); 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--) { for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) {
final WallpaperAnimationAdapter wallpaperAdapter = mPendingWallpaperAnimations.get(i); final WallpaperAnimationAdapter wallpaperAdapter = mPendingWallpaperAnimations.get(i);
@@ -1224,7 +1243,14 @@ public class RecentsAnimationController implements DeathRecipient {
mLocalBounds.offsetTo(tmpPos.x, tmpPos.y); 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 ActivityRecord topApp = mTask.getTopVisibleActivity();
final WindowState mainWindow = topApp != null final WindowState mainWindow = topApp != null
? topApp.findMainWindow() ? topApp.findMainWindow()
@@ -1238,7 +1264,10 @@ public class RecentsAnimationController implements DeathRecipient {
final int mode = topApp.getActivityType() == mTargetActivityType final int mode = topApp.getActivityType() == mTargetActivityType
? MODE_OPENING ? MODE_OPENING
: MODE_CLOSING; : 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(), !topApp.fillsParent(), new Rect(),
insets, mTask.getPrefixOrderIndex(), new Point(mBounds.left, mBounds.top), insets, mTask.getPrefixOrderIndex(), new Point(mBounds.left, mBounds.top),
mLocalBounds, mBounds, mTask.getWindowConfiguration(), mLocalBounds, mBounds, mTask.getWindowConfiguration(),

View File

@@ -2377,6 +2377,16 @@ class Task extends TaskFragment {
return true; 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() { int getDescendantTaskCount() {
final int[] currentCount = {0}; final int[] currentCount = {0};
final PooledConsumer c = PooledLambda.obtainConsumer((t, count) -> { count[0]++; }, final PooledConsumer c = PooledLambda.obtainConsumer((t, count) -> { count[0]++; },