diff options
| author | 2023-02-23 22:16:26 +0000 | |
|---|---|---|
| committer | 2023-02-23 22:16:26 +0000 | |
| commit | 294c7e8446e3fd405a56fdb4927d6cd5773fa252 (patch) | |
| tree | 9283f2e699f49bd240c11f1fc39d3451d89531bf | |
| parent | 02b3713d0ba743328f859384682ddb4c24e6a5b3 (diff) | |
| parent | 89e82322d2c46961221e9a25940ad151e2223b1d (diff) | |
Merge "Stabilize overview/quick-switch transitions" into udc-dev
| -rw-r--r-- | packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java | 183 | ||||
| -rw-r--r-- | services/core/java/com/android/server/wm/ActivityTaskManagerService.java | 20 |
2 files changed, 143 insertions, 60 deletions
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 2a37bd370b7c..80b97588279f 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 @@ -36,7 +36,6 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Log; -import android.util.SparseArray; import android.view.IRecentsAnimationController; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; @@ -106,12 +105,24 @@ public class RemoteTransitionCompat { private RecentsAnimationListener mListener = null; private RecentsAnimationControllerCompat mWrapped = null; private IRemoteTransitionFinishedCallback mFinishCB = null; + + /** + * List of tasks that we are switching away from via this transition. Upon finish, these + * pausing tasks will become invisible. + * These need to be ordered since the order must be restored if there is no task-switch. + */ private ArrayList<TaskState> mPausingTasks = null; + + /** + * List of tasks that we are switching to. Upon finish, these will remain visible and + * on top. + */ + private ArrayList<TaskState> mOpeningTasks = null; + private WindowContainerToken mPipTask = null; private WindowContainerToken mRecentsTask = null; private int mRecentsTaskId = 0; private TransitionInfo mInfo = null; - private ArrayList<SurfaceControl> mOpeningLeashes = null; private boolean mOpeningSeparateHome = false; private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null; private PictureInPictureSurfaceTransaction mPipTransaction = null; @@ -120,6 +131,15 @@ public class RemoteTransitionCompat { private RemoteAnimationTarget[] mAppearedTargets; private boolean mWillFinishToHome = false; + /** The animation is idle, waiting for the user to choose a task to switch to. */ + private static final int STATE_NORMAL = 0; + + /** The user chose a new task to switch to and the animation is animating to it. */ + private static final int STATE_NEW_TASK = 1; + + /** The latest state that the recents animation is operating in. */ + private int mState = STATE_NORMAL; + void start(RecentsAnimationControllerCompat wrapped, RecentsAnimationListener listener, IBinder transition, TransitionInfo info, SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishedCallback) { @@ -132,12 +152,14 @@ public class RemoteTransitionCompat { mInfo = info; mFinishCB = finishedCallback; mPausingTasks = new ArrayList<>(); + mOpeningTasks = new ArrayList<>(); mPipTask = null; mRecentsTask = null; mRecentsTaskId = -1; mLeashMap = new ArrayMap<>(); mTransition = transition; mKeyguardLocked = (info.getFlags() & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0; + mState = STATE_NORMAL; final ArrayList<RemoteAnimationTarget> apps = new ArrayList<>(); final ArrayList<RemoteAnimationTarget> wallpapers = new ArrayList<>(); @@ -178,6 +200,9 @@ public class RemoteTransitionCompat { } else if (taskInfo != null && taskInfo.topActivityType == ACTIVITY_TYPE_HOME) { mRecentsTask = taskInfo.token; mRecentsTaskId = taskInfo.taskId; + } else if (change.getMode() == TRANSIT_OPEN + || change.getMode() == TRANSIT_TO_FRONT) { + mOpeningTasks.add(new TaskState(change, target.leash)); } } } @@ -189,34 +214,41 @@ public class RemoteTransitionCompat { @SuppressLint("NewApi") boolean merge(TransitionInfo info, SurfaceControl.Transaction t) { - SparseArray<TransitionInfo.Change> openingTasks = null; + ArrayList<TransitionInfo.Change> openingTasks = null; + ArrayList<TransitionInfo.Change> closingTasks = null; mAppearedTargets = null; - boolean foundHomeOpening = false; + mOpeningSeparateHome = false; + TransitionInfo.Change recentsOpening = null; boolean foundRecentsClosing = false; boolean hasChangingApp = false; - for (int i = info.getChanges().size() - 1; i >= 0; --i) { + final RemoteAnimationTargetCompat.LeafTaskFilter leafTaskFilter = + new RemoteAnimationTargetCompat.LeafTaskFilter(); + for (int i = 0; i < info.getChanges().size(); ++i) { final TransitionInfo.Change change = info.getChanges().get(i); + final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); + final boolean isLeafTask = leafTaskFilter.test(change); if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) { - final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); - if (taskInfo != null) { + if (mRecentsTask.equals(change.getContainer())) { + recentsOpening = change; + } else if (isLeafTask) { if (taskInfo.topActivityType == ACTIVITY_TYPE_HOME) { // This is usually a 3p launcher - foundHomeOpening = true; + mOpeningSeparateHome = true; } if (openingTasks == null) { - openingTasks = new SparseArray<>(); - } - if (taskInfo.hasParentTask()) { - // Collects opening leaf tasks only since Launcher monitors leaf task - // ids to perform recents animation. - openingTasks.remove(taskInfo.parentTaskId); + openingTasks = new ArrayList<>(); } - openingTasks.put(taskInfo.taskId, change); + openingTasks.add(change); } } else if (change.getMode() == TRANSIT_CLOSE || change.getMode() == TRANSIT_TO_BACK) { if (mRecentsTask.equals(change.getContainer())) { foundRecentsClosing = true; + } else if (isLeafTask) { + if (closingTasks == null) { + closingTasks = new ArrayList<>(); + } + closingTasks.add(change); } } else if (change.getMode() == TRANSIT_CHANGE) { hasChangingApp = true; @@ -234,45 +266,72 @@ public class RemoteTransitionCompat { } return false; } - if (openingTasks == null) return false; - int pauseMatches = 0; - if (!foundHomeOpening) { - for (int i = 0; i < openingTasks.size(); ++i) { - if (TaskState.indexOf(mPausingTasks, openingTasks.valueAt(i)) >= 0) { - ++pauseMatches; + if (recentsOpening != null) { + // the recents task re-appeared. This happens if the user gestures before the + // task-switch (NEW_TASK) animation finishes. + if (mState == STATE_NORMAL) { + Log.e(TAG, "Returning to recents while recents is already idle."); + } + if (closingTasks == null || closingTasks.size() == 0) { + Log.e(TAG, "Returning to recents without closing any opening tasks."); + } + // Setup may hide it initially since it doesn't know that overview was still active. + t.show(recentsOpening.getLeash()); + t.setAlpha(recentsOpening.getLeash(), 1.f); + mState = STATE_NORMAL; + } + boolean didMergeThings = false; + if (closingTasks != null) { + // Cancelling a task-switch. Move the tasks back to mPausing from mOpening + for (int i = 0; i < closingTasks.size(); ++i) { + final TransitionInfo.Change change = closingTasks.get(i); + int openingIdx = TaskState.indexOf(mOpeningTasks, change); + if (openingIdx < 0) { + Log.e(TAG, "Back to existing recents animation from an unrecognized " + + "task: " + change.getTaskInfo().taskId); + continue; } + mPausingTasks.add(mOpeningTasks.remove(openingIdx)); + didMergeThings = true; } } - 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."); + if (openingTasks != null && openingTasks.size() > 0) { + // 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; + final RemoteAnimationTarget[] targets = + new RemoteAnimationTarget[openingTasks.size()]; + for (int i = 0; i < openingTasks.size(); ++i) { + final TransitionInfo.Change change = openingTasks.get(i); + int pausingIdx = TaskState.indexOf(mPausingTasks, change); + if (pausingIdx >= 0) { + // Something is showing/opening a previously-pausing app. + targets[i] = newTarget(change, layer, mPausingTasks.get(pausingIdx).mLeash); + mOpeningTasks.add(mPausingTasks.remove(pausingIdx)); + // 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. + targets[i] = newTarget(change, layer, info, t, mLeashMap); + t.reparent(targets[i].leash, mInfo.getRootLeash()); + t.setLayer(targets[i].leash, layer); + mOpeningTasks.add(new TaskState(change, targets[i].leash)); + } } - // In this case, we are "returning" to an already running app, so just consume - // the merge and do nothing. - info.releaseAllSurfaces(); - t.close(); - return true; + didMergeThings = true; + mState = STATE_NEW_TASK; + mAppearedTargets = targets; } - final int layer = mInfo.getChanges().size() * 3; - mOpeningLeashes = new ArrayList<>(); - mOpeningSeparateHome = foundHomeOpening; - final RemoteAnimationTarget[] targets = - new RemoteAnimationTarget[openingTasks.size()]; - for (int i = 0; i < openingTasks.size(); ++i) { - final TransitionInfo.Change change = openingTasks.valueAt(i); - mOpeningLeashes.add(change.getLeash()); - // We are receiving new opening tasks, so convert to onTasksAppeared. - targets[i] = newTarget(change, layer, info, t, mLeashMap); - t.reparent(targets[i].leash, mInfo.getRootLeash()); - t.setLayer(targets[i].leash, layer); + if (!didMergeThings) { + // Didn't recognize anything in incoming transition so don't merge it. + Log.w(TAG, "Don't know how to merge this transition."); + return false; } t.apply(); // not using the incoming anim-only surfaces info.releaseAnimSurfaces(); - mAppearedTargets = targets; return true; } @@ -300,6 +359,8 @@ public class RemoteTransitionCompat { if (enabled) { // transient launches don't receive focus automatically. Since we are taking over // the gesture now, take focus explicitly. + // This also moves recents back to top if the user gestured before a switch + // animation finished. try { ActivityTaskManager.getService().setFocusedTask(mRecentsTaskId); } catch (RemoteException e) { @@ -336,8 +397,8 @@ public class RemoteTransitionCompat { if (toHome) wct.reorder(mRecentsTask, true /* toTop */); else wct.restoreTransientOrder(mRecentsTask); } - if (!toHome && !mWillFinishToHome && mPausingTasks != null && mOpeningLeashes == null) { - // The gesture went back to opening the app rather than continuing with + if (!toHome && !mWillFinishToHome && mPausingTasks != null && mState == STATE_NORMAL) { + // The gesture is returning to the pausing-task(s) rather than continuing with // recents, so end the transition by moving the app back to the top (and also // re-showing it's task). for (int i = mPausingTasks.size() - 1; i >= 0; --i) { @@ -349,25 +410,28 @@ public class RemoteTransitionCompat { wct.restoreTransientOrder(mRecentsTask); } } else if (toHome && mOpeningSeparateHome && mPausingTasks != null) { - // Special situaition where 3p launcher was changed during recents (this happens + // Special situation where 3p launcher was changed during recents (this happens // during tapltests...). Here we get both "return to home" AND "home opening". - // This is basically going home, but we have to restore recents order and also - // treat the home "pausing" task properly. - for (int i = mPausingTasks.size() - 1; i >= 0; --i) { - final TaskState state = mPausingTasks.get(i); + // This is basically going home, but we have to restore the recents and home order. + for (int i = 0; i < mOpeningTasks.size(); ++i) { + final TaskState state = mOpeningTasks.get(i); if (state.mTaskInfo.topActivityType == ACTIVITY_TYPE_HOME) { - // Treat as opening (see above) + // Make sure it is on top. wct.reorder(state.mToken, true /* onTop */); - t.show(state.mTaskSurface); - } else { - // Treat as hiding (see below) - t.hide(state.mTaskSurface); } + t.show(state.mTaskSurface); + } + for (int i = mPausingTasks.size() - 1; i >= 0; --i) { + t.hide(mPausingTasks.get(i).mTaskSurface); } if (!mKeyguardLocked && mRecentsTask != null) { wct.restoreTransientOrder(mRecentsTask); } } else { + // The general case: committing to recents, going home, or switching tasks. + for (int i = 0; i < mOpeningTasks.size(); ++i) { + t.show(mOpeningTasks.get(i).mTaskSurface); + } for (int i = 0; i < mPausingTasks.size(); ++i) { if (!sendUserLeaveHint) { // This means recents is not *actually* finishing, so of course we gotta @@ -391,7 +455,7 @@ public class RemoteTransitionCompat { try { mFinishCB.onTransitionFinished(wct.isEmpty() ? null : wct, t); } catch (RemoteException e) { - Log.e("RemoteTransitionCompat", "Failed to call animation finish callback", e); + Log.e(TAG, "Failed to call animation finish callback", e); t.apply(); } // Only release the non-local created surface references. The animator is responsible @@ -402,12 +466,13 @@ public class RemoteTransitionCompat { mListener = null; mFinishCB = null; mPausingTasks = null; + mOpeningTasks = null; mAppearedTargets = null; mInfo = null; - mOpeningLeashes = null; mOpeningSeparateHome = false; mLeashMap = null; mTransition = null; + mState = STATE_NORMAL; } @Override public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) { diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index c41acd04070c..f6cdec47401d 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -65,6 +65,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_PIP; +import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; @@ -2034,7 +2035,20 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return; } - if (r.moveFocusableActivityToTop("setFocusedTask")) { + final Transition transition = (getTransitionController().isCollecting() + || !getTransitionController().isShellTransitionsEnabled()) ? null + : getTransitionController().createTransition(TRANSIT_TO_FRONT); + if (transition != null) { + // Set ready before doing anything. If order does change, then that will set it unready + // so that we wait for the new lifecycles to complete. + transition.setReady(task, true /* ready */); + } + final boolean movedToTop = r.moveFocusableActivityToTop("setFocusedTask"); + if (movedToTop) { + if (transition != null) { + getTransitionController().requestStartTransition( + transition, null /* startTask */, null /* remote */, null /* display */); + } mRootWindowContainer.resumeFocusedTasksTopActivities(); } else if (touchedActivity != null && touchedActivity.isFocusable()) { final TaskFragment parent = touchedActivity.getTaskFragment(); @@ -2046,6 +2060,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { true /* updateInputWindows */); } } + if (transition != null && !movedToTop) { + // No order changes and focus-changes, alone, aren't captured in transitions. + transition.abort(); + } } @Override |