diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java index e5e06df003c93..8723f9b0181d1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java @@ -35,6 +35,7 @@ import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.util.ArrayMap; +import android.util.IntArray; import android.util.Pair; import android.util.Slog; import android.view.Display; @@ -422,26 +423,28 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { // About layering: we divide up the "layer space" into 3 regions (each the size of // the change count). This lets us categorize things into above/below/between // while maintaining their relative ordering. + final int belowLayers = info.getChanges().size(); + final int aboveLayers = info.getChanges().size() * 3; for (int i = 0; i < info.getChanges().size(); ++i) { final TransitionInfo.Change change = info.getChanges().get(i); final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); if (TransitionUtil.isWallpaper(change)) { final RemoteAnimationTarget target = TransitionUtil.newTarget(change, // wallpapers go into the "below" layer space - info.getChanges().size() - i, info, t, mLeashMap); + belowLayers - i, info, t, mLeashMap); wallpapers.add(target); // Make all the wallpapers opaque since we want them visible from the start t.setAlpha(target.leash, 1); } else if (leafTaskFilter.test(change)) { // start by putting everything into the "below" layer space. final RemoteAnimationTarget target = TransitionUtil.newTarget(change, - info.getChanges().size() - i, info, t, mLeashMap); + belowLayers - i, info, t, mLeashMap); apps.add(target); if (TransitionUtil.isClosingType(change.getMode())) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, - " adding pausing taskId=%d", taskInfo.taskId); + " adding pausing leaf taskId=%d", taskInfo.taskId); // raise closing (pausing) task to "above" layer so it isn't covered - t.setLayer(target.leash, info.getChanges().size() * 3 - i); + t.setLayer(target.leash, aboveLayers - i); mPausingTasks.add(new TaskState(change, target.leash)); if (taskInfo.topActivityType == ACTIVITY_TYPE_HOME) { // This can only happen if we have a separate recents/home (3p launcher) @@ -454,17 +457,32 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } else if (taskInfo != null && taskInfo.topActivityType == ACTIVITY_TYPE_RECENTS) { // There's a 3p launcher, so make sure recents goes above that. - t.setLayer(target.leash, info.getChanges().size() * 3 - i); + t.setLayer(target.leash, aboveLayers - i); } else if (taskInfo != null && taskInfo.topActivityType == ACTIVITY_TYPE_HOME) { // do nothing } else if (TransitionUtil.isOpeningType(change.getMode())) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, - " adding opening taskId=%d", taskInfo.taskId); + " adding opening leaf taskId=%d", taskInfo.taskId); mOpeningTasks.add(new TaskState(change, target.leash)); } + } else if (taskInfo != null && TransitionInfo.isIndependent(change, info)) { + // Root tasks + if (TransitionUtil.isClosingType(change.getMode())) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + " adding pausing taskId=%d", taskInfo.taskId); + // raise closing (pausing) task to "above" layer so it isn't covered + t.setLayer(change.getLeash(), aboveLayers - i); + mPausingTasks.add(new TaskState(change, null /* leash */)); + } else if (TransitionUtil.isOpeningType(change.getMode())) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + " adding opening taskId=%d", taskInfo.taskId); + // Put into the "below" layer space. + t.setLayer(change.getLeash(), belowLayers - i); + mOpeningTasks.add(new TaskState(change, null /* leash */)); + } } else if (TransitionUtil.isDividerBar(change)) { final RemoteAnimationTarget target = TransitionUtil.newTarget(change, - info.getChanges().size() - i, info, t, mLeashMap); + belowLayers - i, info, t, mLeashMap); // Add this as a app and we will separate them on launcher side by window type. apps.add(target); } @@ -519,7 +537,9 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "[%d] RecentsController.merge", mInstanceId); + // Keep all tasks in one list because order matters. ArrayList openingTasks = null; + IntArray openingTaskIsLeafs = null; ArrayList closingTasks = null; mOpeningSeparateHome = false; TransitionInfo.Change recentsOpening = null; @@ -538,25 +558,29 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { cancel("task #" + taskInfo.taskId + " is always_on_top"); return; } - hasTaskChange = hasTaskChange || taskInfo != null; + final boolean isRootTask = taskInfo != null + && TransitionInfo.isIndependent(change, info); + hasTaskChange = hasTaskChange || isRootTask; final boolean isLeafTask = leafTaskFilter.test(change); if (TransitionUtil.isOpeningType(change.getMode())) { if (mRecentsTask != null && mRecentsTask.equals(change.getContainer())) { recentsOpening = change; - } else if (isLeafTask) { - if (taskInfo.topActivityType == ACTIVITY_TYPE_HOME) { + } else if (isRootTask || isLeafTask) { + if (isLeafTask && taskInfo.topActivityType == ACTIVITY_TYPE_HOME) { // This is usually a 3p launcher mOpeningSeparateHome = true; } if (openingTasks == null) { openingTasks = new ArrayList<>(); + openingTaskIsLeafs = new IntArray(); } openingTasks.add(change); + openingTaskIsLeafs.add(isLeafTask ? 1 : 0); } } else if (TransitionUtil.isClosingType(change.getMode())) { if (mRecentsTask != null && mRecentsTask.equals(change.getContainer())) { foundRecentsClosing = true; - } else if (isLeafTask) { + } else if (isRootTask || isLeafTask) { if (closingTasks == null) { closingTasks = new ArrayList<>(); } @@ -622,7 +646,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } final TaskState openingTask = mOpeningTasks.remove(openingIdx); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, - " pausing opening taskId=%d", openingTask.mTaskInfo.taskId); + " pausing opening %staskId=%d", openingTask.isLeaf() ? "leaf " : "", + openingTask.mTaskInfo.taskId); mPausingTasks.add(openingTask); didMergeThings = true; } @@ -632,35 +657,55 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { // Switching to some new tasks, add to mOpening and remove from mPausing. Also, // enter NEW_TASK state since this will start the switch-to animation. final int layer = mInfo.getChanges().size() * 3; - appearedTargets = new RemoteAnimationTarget[openingTasks.size()]; + int openingLeafCount = 0; + for (int i = 0; i < openingTaskIsLeafs.size(); ++i) { + openingLeafCount += openingTaskIsLeafs.get(i); + } + if (openingLeafCount > 0) { + appearedTargets = new RemoteAnimationTarget[openingLeafCount]; + } + int nextTargetIdx = 0; for (int i = 0; i < openingTasks.size(); ++i) { final TransitionInfo.Change change = openingTasks.get(i); + final boolean isLeaf = openingTaskIsLeafs.get(i) == 1; int pausingIdx = TaskState.indexOf(mPausingTasks, change); if (pausingIdx >= 0) { // Something is showing/opening a previously-pausing app. - appearedTargets[i] = TransitionUtil.newTarget( - change, layer, mPausingTasks.get(pausingIdx).mLeash); + if (isLeaf) { + appearedTargets[nextTargetIdx++] = TransitionUtil.newTarget( + change, layer, mPausingTasks.get(pausingIdx).mLeash); + } final TaskState pausingTask = mPausingTasks.remove(pausingIdx); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, - " opening pausing taskId=%d", pausingTask.mTaskInfo.taskId); + " opening pausing %staskId=%d", isLeaf ? "leaf " : "", + pausingTask.mTaskInfo.taskId); mOpeningTasks.add(pausingTask); // Setup hides opening tasks initially, so make it visible again (since we // are already showing it). t.show(change.getLeash()); t.setAlpha(change.getLeash(), 1.f); - } else { - // We are receiving new opening tasks, so convert to onTasksAppeared. - appearedTargets[i] = TransitionUtil.newTarget( + } else if (isLeaf) { + // We are receiving new opening leaf tasks, so convert to onTasksAppeared. + final RemoteAnimationTarget target = TransitionUtil.newTarget( change, layer, info, t, mLeashMap); + appearedTargets[nextTargetIdx++] = target; // reparent into the original `mInfo` since that's where we are animating. final int rootIdx = TransitionUtil.rootIndexFor(change, mInfo); - t.reparent(appearedTargets[i].leash, mInfo.getRoot(rootIdx).getLeash()); - t.setLayer(appearedTargets[i].leash, layer); + t.reparent(target.leash, mInfo.getRoot(rootIdx).getLeash()); + t.setLayer(target.leash, layer); // Hide the animation leash, let listener show it. - t.hide(appearedTargets[i].leash); + t.hide(target.leash); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, - " opening new taskId=%d", appearedTargets[i].taskId); - mOpeningTasks.add(new TaskState(change, appearedTargets[i].leash)); + " opening new leaf taskId=%d", target.taskId); + mOpeningTasks.add(new TaskState(change, target.leash)); + } else { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + " opening new taskId=%d", change.getTaskInfo().taskId); + t.setLayer(change.getLeash(), layer); + // Setup hides opening tasks initially, so make it visible since recents + // is only animating the leafs. + t.show(change.getLeash()); + mOpeningTasks.add(new TaskState(change, null)); } } didMergeThings = true; @@ -845,7 +890,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { t.show(mOpeningTasks.get(i).mTaskSurface); } for (int i = 0; i < mPausingTasks.size(); ++i) { - if (!sendUserLeaveHint) { + if (!sendUserLeaveHint && mPausingTasks.get(i).isLeaf()) { // This means recents is not *actually* finishing, so of course we gotta // do special stuff in WMCore to accommodate. wct.setDoNotPip(mPausingTasks.get(i).mToken); @@ -924,7 +969,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { /** The surface/leash of the task provided by Core. */ SurfaceControl mTaskSurface; - /** The (local) animation-leash created for this task. */ + /** The (local) animation-leash created for this task. Only non-null for leafs. */ + @Nullable SurfaceControl mLeash; TaskState(TransitionInfo.Change change, SurfaceControl leash) { @@ -943,6 +989,10 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { return -1; } + boolean isLeaf() { + return mLeash != null; + } + public String toString() { return "" + mToken + " : " + mLeash; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java index 143b42a1ec967..c33a633f2068f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java @@ -121,15 +121,14 @@ public class TransitionUtil { @Override public boolean test(TransitionInfo.Change change) { final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); + if (taskInfo == null) return false; // Children always come before parent since changes are in top-to-bottom z-order. - if ((taskInfo == null) || mChildTaskTargets.get(taskInfo.taskId)) { - // has children, so not a leaf. Skip. - return false; - } + boolean hasChildren = mChildTaskTargets.get(taskInfo.taskId); if (taskInfo.hasParentTask()) { mChildTaskTargets.put(taskInfo.parentTaskId, true); } - return true; + // If it has children, it's not a leaf. + return !hasChildren; } }