summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Evan Rosky <erosky@google.com> 2023-02-23 22:16:26 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-02-23 22:16:26 +0000
commit294c7e8446e3fd405a56fdb4927d6cd5773fa252 (patch)
tree9283f2e699f49bd240c11f1fc39d3451d89531bf
parent02b3713d0ba743328f859384682ddb4c24e6a5b3 (diff)
parent89e82322d2c46961221e9a25940ad151e2223b1d (diff)
Merge "Stabilize overview/quick-switch transitions" into udc-dev
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java183
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java20
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