Merge "Add multi-display support to shell transitions" into sc-v2-dev

This commit is contained in:
Evan Rosky
2021-07-14 17:13:07 +00:00
committed by Android (Google) Code Review
10 changed files with 187 additions and 31 deletions

View File

@@ -181,6 +181,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
"-1924376693": {
"message": " Setting Ready-group to %b. group=%s from %s",
"level": "VERBOSE",
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/Transition.java"
},
"-1918702467": {
"message": "onSyncFinishedDrawing %s",
"level": "VERBOSE",
@@ -607,6 +613,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
"-1442613680": {
"message": " Creating Ready-group for Transition %d with root=%s",
"level": "VERBOSE",
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/Transition.java"
},
"-1438175584": {
"message": "Input focus has changed to %s display=%d",
"level": "VERBOSE",
@@ -2209,6 +2221,12 @@
"group": "WM_DEBUG_ADD_REMOVE",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
"352982444": {
"message": " allReady query: used=%b override=%b states=[%s]",
"level": "VERBOSE",
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/Transition.java"
},
"355720268": {
"message": "stopFreezingDisplayLocked: Unfreezing now",
"level": "DEBUG",
@@ -3277,6 +3295,12 @@
"group": "WM_DEBUG_IME",
"at": "com\/android\/server\/wm\/InsetsStateController.java"
},
"1670933628": {
"message": " Setting allReady override",
"level": "VERBOSE",
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/Transition.java"
},
"1671994402": {
"message": "Nulling last startingData",
"level": "VERBOSE",

View File

@@ -1620,7 +1620,7 @@ class ActivityStarter {
mTargetTask, remoteTransition);
} else if (started) {
// Make the collecting transition wait until this request is ready.
mService.getTransitionController().setReady(false);
mService.getTransitionController().setReady(r, false);
}
}
}

View File

@@ -1359,7 +1359,8 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
}
mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_TO_FRONT,
0 /* flags */, task, options != null ? options.getRemoteTransition() : null);
0 /* flags */, task, task /* readyGroupRef */,
options != null ? options.getRemoteTransition() : null);
reason = reason + " findTaskToMoveToFront";
boolean reparented = false;
if (task.isResizeable() && canUseActivityOptionsLaunchBounds(options)) {

View File

@@ -2987,7 +2987,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
@Override
void removeIfPossible() {
if (isAnimating(TRANSITION | PARENTS)) {
if (isAnimating(TRANSITION | PARENTS)
// isAnimating is a legacy transition query and will be removed, so also add a
// check for whether this is in a shell-transition when not using legacy.
|| mAtmService.getTransitionController().inTransition()) {
mDeferredRemoval = true;
return;
}
@@ -4989,7 +4992,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
@WindowManager.TransitionFlags int flags) {
prepareAppTransition(transit, flags);
mAtmService.getTransitionController().requestTransitionIfNeeded(transit, flags,
null /* trigger */);
null /* trigger */, this);
}
/** @see #requestTransitionAndLegacyPrepare(int, int) */
@@ -4997,11 +5000,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
@Nullable WindowContainer trigger) {
prepareAppTransition(transit);
mAtmService.getTransitionController().requestTransitionIfNeeded(transit, 0 /* flags */,
trigger);
trigger, this);
}
void executeAppTransition() {
mAtmService.getTransitionController().setReady();
mAtmService.getTransitionController().setReady(this);
if (mAppTransition.isTransitionSet()) {
ProtoLog.w(WM_DEBUG_APP_TRANSITIONS,
"Execute app transition: %s, displayId: %d Callers=%s",

View File

@@ -508,6 +508,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mTaskSupervisor.updateTopResumedActivityIfNeeded();
}
@Override
boolean isAttached() {
return true;
}
/**
* Called when DisplayWindowSettings values may change.
*/

View File

@@ -132,7 +132,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
private TransitionInfo.AnimationOptions mOverrideOptions;
private @TransitionState int mState = STATE_COLLECTING;
private boolean mReadyCalled = false;
private final ReadyTracker mReadyTracker = new ReadyTracker();
// TODO(b/188595497): remove when not needed.
/** @see RecentsAnimationController#mNavigationBarAttachedToApp */
@@ -169,9 +169,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
mState = STATE_STARTED;
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Starting Transition %d",
mSyncId);
if (mReadyCalled) {
setReady();
}
applyReady();
}
/**
@@ -186,6 +184,11 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
for (WindowContainer curr = wc.getParent(); curr != null && !mChanges.containsKey(curr);
curr = curr.getParent()) {
mChanges.put(curr, new ChangeInfo(curr));
if (isReadyGroup(curr)) {
mReadyTracker.addGroup(curr);
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " Creating Ready-group for"
+ " Transition %d with root=%s", mSyncId, curr);
}
}
if (mParticipants.contains(wc)) return;
mSyncEngine.addToSyncSet(mSyncId, wc);
@@ -236,21 +239,33 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
* all participants have finished drawing, the transition can still collect participants.
*
* If this is called before the transition is started, it will be deferred until start.
*
* @param wc A reference point to determine which ready-group to update. For now, each display
* has its own ready-group, so this is used to look-up which display to mark ready.
* The transition will wait for all groups to be ready.
*/
void setReady(boolean ready) {
void setReady(WindowContainer wc, boolean ready) {
if (mSyncId < 0) return;
if (mState < STATE_STARTED) {
mReadyCalled = ready;
return;
}
mReadyTracker.setReadyFrom(wc, ready);
applyReady();
}
private void applyReady() {
if (mState < STATE_STARTED) return;
final boolean ready = mReadyTracker.allReady();
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
"Set transition ready=%b %d", ready, mSyncId);
mSyncEngine.setReady(mSyncId, ready);
}
/** @see #setReady . This calls with parameter true. */
void setReady() {
setReady(true);
/**
* Sets all possible ready groups to ready.
* @see ReadyTracker#setAllReady.
*/
void setAllReady() {
if (mSyncId < 0) return;
mReadyTracker.setAllReady();
applyReady();
}
/**
@@ -890,6 +905,15 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
return wc.getParent().getSurfaceControl();
}
/**
* A ready group is defined by a root window-container where all transitioning windows under
* it are expected to animate together as a group. At the moment, this treats each display as
* a ready-group to match the existing legacy transition behavior.
*/
private static boolean isReadyGroup(WindowContainer wc) {
return wc instanceof DisplayContent;
}
/**
* Construct a TransitionInfo object from a set of targets and changes. Also populates the
* root surface.
@@ -1092,4 +1116,95 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
mChildren.addAll(wcs);
}
}
/**
* The transition sync mechanism has 2 parts:
* 1. Whether all WM operations for a particular transition are "ready" (eg. did the app
* launch or stop or get a new configuration?).
* 2. Whether all the windows involved have finished drawing their final-state content.
*
* A transition animation can play once both parts are complete. This ready-tracker keeps track
* of part (1). Currently, WM code assumes that "readiness" (part 1) is grouped. This means that
* even if the WM operations in one group are ready, the whole transition itself may not be
* ready if there are WM operations still pending in another group. This class helps keep track
* of readiness across the multiple groups. Currently, we assume that each display is a group
* since that is how it has been until now.
*/
private static class ReadyTracker {
private final ArrayMap<WindowContainer, Boolean> mReadyGroups = new ArrayMap<>();
/**
* Ensures that this doesn't report as allReady before it has been used. This is needed
* in very niche cases where a transition is a no-op (nothing has been collected) but we
* still want to be marked ready (via. setAllReady).
*/
private boolean mUsed = false;
/**
* If true, this overrides all ready groups and reports ready. Used by shell-initiated
* transitions via {@link #setAllReady()}.
*/
private boolean mReadyOverride = false;
/**
* Adds a ready-group. Any setReady calls in this subtree will be tracked together. For
* now these are only DisplayContents.
*/
void addGroup(WindowContainer wc) {
if (mReadyGroups.containsKey(wc)) {
Slog.e(TAG, "Trying to add a ready-group twice: " + wc);
return;
}
mReadyGroups.put(wc, false);
}
/**
* Sets a group's ready state.
* @param wc Any container within a group's subtree. Used to identify the ready-group.
*/
void setReadyFrom(WindowContainer wc, boolean ready) {
mUsed = true;
WindowContainer current = wc;
while (current != null) {
if (isReadyGroup(current)) {
mReadyGroups.put(current, ready);
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " Setting Ready-group to"
+ " %b. group=%s from %s", ready, current, wc);
break;
}
current = current.getParent();
}
}
/** Marks this as ready regardless of individual groups. */
void setAllReady() {
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " Setting allReady override");
mUsed = true;
mReadyOverride = true;
}
/** @return true if all tracked subtrees are ready. */
boolean allReady() {
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " allReady query: used=%b "
+ "override=%b states=[%s]", mUsed, mReadyOverride, groupsToString());
if (!mUsed) return false;
if (mReadyOverride) return true;
for (int i = mReadyGroups.size() - 1; i >= 0; --i) {
final WindowContainer wc = mReadyGroups.keyAt(i);
if (!wc.isAttached() || !wc.isVisibleRequested()) continue;
if (!mReadyGroups.valueAt(i)) return false;
}
return true;
}
private String groupsToString() {
StringBuilder b = new StringBuilder();
for (int i = 0; i < mReadyGroups.size(); ++i) {
if (i != 0) b.append(',');
b.append(mReadyGroups.keyAt(i)).append(':')
.append(mReadyGroups.valueAt(i));
}
return b.toString();
}
}
}

View File

@@ -192,8 +192,8 @@ class TransitionController {
*/
@Nullable
Transition requestTransitionIfNeeded(@WindowManager.TransitionType int type,
@Nullable WindowContainer trigger) {
return requestTransitionIfNeeded(type, 0 /* flags */, trigger);
@NonNull WindowContainer trigger) {
return requestTransitionIfNeeded(type, 0 /* flags */, trigger, trigger /* readyGroupRef */);
}
/**
@@ -201,8 +201,10 @@ class TransitionController {
*/
@Nullable
Transition requestTransitionIfNeeded(@WindowManager.TransitionType int type,
@WindowManager.TransitionFlags int flags, @Nullable WindowContainer trigger) {
return requestTransitionIfNeeded(type, flags, trigger, null /* remote */);
@WindowManager.TransitionFlags int flags, @Nullable WindowContainer trigger,
@NonNull WindowContainer readyGroupRef) {
return requestTransitionIfNeeded(type, flags, trigger, readyGroupRef,
null /* remoteTransition */);
}
private static boolean isExistenceType(@WindowManager.TransitionType int type) {
@@ -213,19 +215,20 @@ class TransitionController {
* If a transition isn't requested yet, creates one and asks the TransitionPlayer (Shell) to
* start it. Collection can start immediately.
* @param trigger if non-null, this is the first container that will be collected
* @param readyGroupRef Used to identify which ready-group this request is for.
* @return the created transition if created or null otherwise.
*/
@Nullable
Transition requestTransitionIfNeeded(@WindowManager.TransitionType int type,
@WindowManager.TransitionFlags int flags, @Nullable WindowContainer trigger,
@Nullable IRemoteTransition remoteTransition) {
@NonNull WindowContainer readyGroupRef, @Nullable IRemoteTransition remoteTransition) {
if (mTransitionPlayer == null) {
return null;
}
Transition newTransition = null;
if (isCollecting()) {
// Make the collecting transition wait until this request is ready.
mCollectingTransition.setReady(false);
mCollectingTransition.setReady(readyGroupRef, false);
} else {
newTransition = requestStartTransition(createTransition(type, flags),
trigger != null ? trigger.asTask() : null, remoteTransition);
@@ -280,14 +283,14 @@ class TransitionController {
}
/** @see Transition#setReady */
void setReady(boolean ready) {
void setReady(WindowContainer wc, boolean ready) {
if (mCollectingTransition == null) return;
mCollectingTransition.setReady(ready);
mCollectingTransition.setReady(wc, ready);
}
/** @see Transition#setReady */
void setReady() {
setReady(true);
void setReady(WindowContainer wc) {
setReady(wc, true);
}
/** @see Transition#finishTransition */

View File

@@ -851,7 +851,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
boolean isAttached() {
return getDisplayArea() != null;
WindowContainer parent = getParent();
return parent != null && parent.isAttached();
}
void setWaitingForDrawnIfResizingChanged() {

View File

@@ -8123,7 +8123,11 @@ public class WindowManagerService extends IWindowManager.Stub
boolean isAnimating = mAnimator.isAnimationScheduled()
|| mRoot.isAnimating(TRANSITION | CHILDREN, ANIMATION_TYPE_ALL);
if (!isAnimating) {
break;
// isAnimating is a legacy transition query and will be removed, so also add
// a check for whether this is in a shell-transition when not using legacy.
if (!mAtmService.getTransitionController().inTransition()) {
break;
}
}
long startTime = System.currentTimeMillis();
try {

View File

@@ -227,7 +227,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
applyTransaction(t, -1 /*syncId*/, transition, caller);
if (needsSetReady) {
transition.setReady();
transition.setAllReady();
}
return transition;
}