From 738ba5601f979c291fe7e32d02981387c6a86aeb Mon Sep 17 00:00:00 2001 From: Evan Rosky Date: Thu, 29 Oct 2020 17:12:49 -0700 Subject: Relocate transition collection around lifecycle events (1/N) Previously was just using whatever the legacy transition system used. However, that system would wait too late (until after round-trips to the client) in order to prepare some transitions. Since the new transitions utilize "snapshots", they need to collect earlier in the lifecycle to work properly. This first CL deals mostly with activity start/finish and task to-front/to-back. It also adds some utilities like the ability to abort a transition (needed because activitystarter works this way) and the ability to un-ready a transition/ sync transaction to enable trampolines. This also switches the transit types to the new constants. Bug: 169035022 Test: Existing tests (TransitionTests) pass Change-Id: I05f3a2e8e27ccaed7077d648daf033aeabc333f9 --- core/java/android/window/TransitionInfo.java | 14 +-- data/etc/services.core.protolog.json | 12 +-- .../src/com/android/wm/shell/Transitions.java | 11 +- .../java/com/android/server/wm/ActivityRecord.java | 1 + .../android/server/wm/ActivityStackSupervisor.java | 4 + .../com/android/server/wm/ActivityStarter.java | 23 ++++ .../java/com/android/server/wm/AppTransition.java | 6 +- .../com/android/server/wm/BLASTSyncEngine.java | 22 +++- .../java/com/android/server/wm/DisplayContent.java | 22 ++++ .../com/android/server/wm/KeyguardController.java | 2 +- .../com/android/server/wm/RootWindowContainer.java | 3 +- services/core/java/com/android/server/wm/Task.java | 17 +-- .../java/com/android/server/wm/Transition.java | 87 +++++++++++---- .../android/server/wm/TransitionController.java | 117 ++++++++++----------- 14 files changed, 222 insertions(+), 119 deletions(-) diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java index 50174dfd8899..0eef84765890 100644 --- a/core/java/android/window/TransitionInfo.java +++ b/core/java/android/window/TransitionInfo.java @@ -170,14 +170,14 @@ public final class TransitionInfo implements Parcelable { private final Rect mStartBounds = new Rect(); private final Rect mEndBounds = new Rect(); - public Change(@NonNull WindowContainerToken container, @NonNull SurfaceControl leash) { + public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) { mContainer = container; mLeash = leash; } private Change(Parcel in) { - mContainer = WindowContainerToken.CREATOR.createFromParcel(in); - mParent = in.readParcelable(WindowContainerToken.class.getClassLoader()); + mContainer = in.readTypedObject(WindowContainerToken.CREATOR); + mParent = in.readTypedObject(WindowContainerToken.CREATOR); mLeash = new SurfaceControl(); mLeash.readFromParcel(in); mMode = in.readInt(); @@ -205,8 +205,8 @@ public final class TransitionInfo implements Parcelable { mEndBounds.set(rect); } - /** @return the container that is changing */ - @NonNull + /** @return the container that is changing. May be null if non-remotable (eg. activity) */ + @Nullable public WindowContainerToken getContainer() { return mContainer; } @@ -252,8 +252,8 @@ public final class TransitionInfo implements Parcelable { @Override /** @hide */ public void writeToParcel(@NonNull Parcel dest, int flags) { - mContainer.writeToParcel(dest, flags); - dest.writeParcelable(mParent, 0); + dest.writeTypedObject(mContainer, flags); + dest.writeTypedObject(mParent, flags); mLeash.writeToParcel(dest, flags); dest.writeInt(mMode); mStartBounds.writeToParcel(dest, flags); diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index e51bf5e4e1f6..f4ccecc7e62f 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -1027,6 +1027,12 @@ "group": "WM_DEBUG_TASKS", "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java" }, + "-874888131": { + "message": "Set transition ready=%b %d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" + }, "-874446906": { "message": "showBootMessage: msg=%s always=%b mAllowBootMessages=%b mShowingBootMessages=%b mSystemBooted=%b. %s", "level": "INFO", @@ -2509,12 +2515,6 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowToken.java" }, - "849147756": { - "message": "Finish collecting in transition %d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, "853091290": { "message": "Moved stack=%s behind stack=%s", "level": "DEBUG", diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java index 04be3b70fc65..388eb28223dc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java @@ -109,13 +109,10 @@ public class Transitions extends ITransitionPlayer.Stub { mAnimExecutor.execute(va::start); } - private static boolean isOpeningType(@WindowManager.TransitionOldType int legacyType) { - // TODO(shell-transitions): consider providing and using z-order vs the global type for - // this determination. - return legacyType == WindowManager.TRANSIT_OLD_TASK_OPEN - || legacyType == WindowManager.TRANSIT_OLD_TASK_TO_FRONT - || legacyType == WindowManager.TRANSIT_OLD_TASK_OPEN_BEHIND - || legacyType == WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY; + private static boolean isOpeningType(@WindowManager.TransitionType int type) { + return type == WindowManager.TRANSIT_OPEN + || type == WindowManager.TRANSIT_TO_FRONT + || type == WindowManager.TRANSIT_KEYGUARD_GOING_AWAY; } @Override diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 107690614f82..80d1f1148cb6 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2983,6 +2983,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (stopped) { clearOptionsLocked(); } + mAtmService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, this); } /** diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index e2a7afb64fca..019f650c5f1c 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -43,6 +43,8 @@ import static android.os.PowerManager.PARTIAL_WAKE_LOCK; import static android.os.Process.INVALID_UID; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.WindowManager.TRANSIT_CLOSE; +import static android.view.WindowManager.TRANSIT_TO_FRONT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS; @@ -1349,6 +1351,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { mUserLeaving = true; } + mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_TO_FRONT, task); reason = reason + " findTaskToMoveToFront"; boolean reparented = false; if (task.isResizeable() && canUseActivityOptionsLaunchBounds(options)) { @@ -1516,6 +1519,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { // Prevent recursion. return; } + mService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, task); task.mInRemoveTask = true; try { task.performClearTask(reason); diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 6f979363e3bd..6a320f7b1e6d 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -55,6 +55,7 @@ import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Process.INVALID_UID; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.WindowManager.TRANSIT_OPEN; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS; @@ -1566,6 +1567,15 @@ class ActivityStarter { boolean restrictedBgActivity, NeededUriGrants intentGrants) { int result = START_CANCELED; final Task startedActivityStack; + + // Create a transition now to record the original intent of actions taken within + // startActivityInner. Otherwise, logic in startActivityInner could start a different + // transition based on a sub-action. + // Only do the create here (and defer requestStart) since startActivityInner might abort. + final Transition newTransition = (!mService.getTransitionController().isCollecting() + && mService.getTransitionController().getTransitionPlayer() != null) + ? mService.getTransitionController().createTransition(TRANSIT_OPEN) : null; + mService.getTransitionController().collect(r); try { mService.deferWindowLayout(); Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner"); @@ -1575,6 +1585,18 @@ class ActivityStarter { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); startedActivityStack = handleStartResult(r, result); mService.continueWindowLayout(); + + // Transition housekeeping + if (!ActivityManager.isStartResultSuccessful(result)) { + if (newTransition != null) { + newTransition.abort(); + } + } else if (newTransition != null) { + mService.getTransitionController().requestStartTransition(newTransition); + } else { + // Make the collecting transition wait until this request is ready. + mService.getTransitionController().setReady(false); + } } postStartActivityProcessing(r, result, startedActivityStack); @@ -2607,6 +2629,7 @@ class ActivityStarter { mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info, mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession, mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions); + mService.getTransitionController().collect(task); addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask"); ProtoLog.v(WM_DEBUG_TASKS, "Starting new activity %s in new task %s", diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 12c2c0e54ce7..e146adadffe7 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -2297,8 +2297,7 @@ public class AppTransition implements Dump { */ boolean prepareAppTransitionOld(@TransitionOldType int transit, boolean alwaysKeepCurrent, @TransitionFlags int flags, boolean forceOverride) { - if (mService.mAtmService.getTransitionController().adaptLegacyPrepare( - transit, flags, forceOverride)) { + if (mService.mAtmService.getTransitionController().getTransitionPlayer() != null) { return false; } ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, @@ -2334,6 +2333,9 @@ public class AppTransition implements Dump { } boolean prepareAppTransition(@TransitionType int transit, @TransitionFlags int flags) { + if (mService.mAtmService.getTransitionController().getTransitionPlayer() != null) { + return false; + } mNextAppTransitionRequests.add(transit); mNextAppTransitionFlags |= flags; updateBooster(); diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java index 301783c155e1..faeb4ba36748 100644 --- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java +++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java @@ -100,6 +100,10 @@ class BLASTSyncEngine { return; } } + finishNow(); + } + + private void finishNow() { ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Finished!", mSyncId); SurfaceControl.Transaction merged = mWm.mTransactionFactory.get(); if (mOrphanTransaction != null) { @@ -112,9 +116,10 @@ class BLASTSyncEngine { mActiveSyncs.remove(mSyncId); } - private void setReady() { + private void setReady(boolean ready) { ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Set ready", mSyncId); - mReady = true; + mReady = ready; + if (!ready) return; mWm.mWindowPlacerLocked.requestTraversal(); } @@ -153,8 +158,19 @@ class BLASTSyncEngine { mActiveSyncs.get(id).addToSync(wc); } + void setReady(int id, boolean ready) { + mActiveSyncs.get(id).setReady(ready); + } + void setReady(int id) { - mActiveSyncs.get(id).setReady(); + setReady(id, true); + } + + /** + * Aborts the sync (ie. it doesn't wait for ready or anything to finish) + */ + void abort(int id) { + mActiveSyncs.get(id).finishNow(); } void onSurfacePlacement() { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 07c61d3dcea5..d7df5cc99e69 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -4539,6 +4539,28 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } } + /** + * Helper that both requests a transition (using the new transition system) and prepares + * the legacy transition system. Use this when both systems have the same start-point. + * + * @see TransitionController#requestTransitionIfNeeded(int, int, WindowContainer) + * @see AppTransition#prepareAppTransition + */ + void requestTransitionAndLegacyPrepare(@WindowManager.TransitionType int transit, + @WindowManager.TransitionFlags int flags) { + prepareAppTransition(transit, flags); + mAtmService.getTransitionController().requestTransitionIfNeeded(transit, flags, + null /* trigger */); + } + + /** @see #requestTransitionAndLegacyPrepare(int, int) */ + void requestTransitionAndLegacyPrepare(@WindowManager.TransitionType int transit, + @Nullable WindowContainer trigger) { + prepareAppTransition(transit); + mAtmService.getTransitionController().requestTransitionIfNeeded(transit, 0 /* flags */, + trigger); + } + void executeAppTransition() { mAtmService.getTransitionController().setReady(); if (mAppTransition.isTransitionSet()) { diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index 9068bb75f405..903e92263fb8 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -215,7 +215,7 @@ class KeyguardController { false /* alwaysKeepCurrent */, convertTransitFlags(flags), false /* forceOverride */); mRootWindowContainer.getDefaultDisplay() - .prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, + .requestTransitionAndLegacyPrepare(TRANSIT_KEYGUARD_GOING_AWAY, convertTransitFlags(flags)); updateKeyguardSleepToken(); diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 3200bbc90de1..075dc7dd6836 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2802,7 +2802,8 @@ class RootWindowContainer extends WindowContainer r.detachFromProcess(); r.mDisplayContent.prepareAppTransitionOld(TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */); - r.mDisplayContent.prepareAppTransition(TRANSIT_CLOSE, TRANSIT_FLAG_APP_CRASHED); + r.mDisplayContent.requestTransitionAndLegacyPrepare(TRANSIT_CLOSE, + TRANSIT_FLAG_APP_CRASHED); r.destroyIfPossible("handleAppCrashed"); } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index ac9c28935211..c490273f9180 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -6417,6 +6417,7 @@ class Task extends WindowContainer { final DisplayContent dc = mDisplayContent; if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: starting " + r); + // TODO(shell-transitions): record NO_ANIMATION flag somewhere. if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) { dc.prepareAppTransitionOld(TRANSIT_OLD_NONE, keepCurTransition); dc.prepareAppTransition(TRANSIT_NONE); @@ -6438,16 +6439,8 @@ class Task extends WindowContainer { transit = TRANSIT_OLD_TASK_OPEN; } } - if (mAtmService.getTransitionController().isShellTransitionsEnabled() - // TODO(shell-transitions): eventually all transitions. - && transit == TRANSIT_OLD_TASK_OPEN) { - Transition transition = - mAtmService.getTransitionController().requestTransition(transit); - transition.collect(task); - } else { - dc.prepareAppTransitionOld(transit, keepCurTransition); - dc.prepareAppTransition(TRANSIT_OPEN); - } + dc.prepareAppTransitionOld(transit, keepCurTransition); + dc.prepareAppTransition(TRANSIT_OPEN); mStackSupervisor.mNoAnimActivities.remove(r); } boolean doShow = true; @@ -6587,7 +6580,7 @@ class Task extends WindowContainer { Task finishedTask = r.getTask(); mDisplayContent.prepareAppTransitionOld( TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */); - mDisplayContent.prepareAppTransition(TRANSIT_CLOSE, TRANSIT_FLAG_APP_CRASHED); + mDisplayContent.requestTransitionAndLegacyPrepare(TRANSIT_CLOSE, TRANSIT_FLAG_APP_CRASHED); r.finishIfPossible(reason, false /* oomAdj */); // Also terminate any activities below it that aren't yet stopped, to avoid a situation @@ -6965,7 +6958,7 @@ class Task extends WindowContainer { mDisplayContent.prepareAppTransitionOld(TRANSIT_OLD_TASK_TO_BACK, false /* alwaysKeepCurrent */); - mDisplayContent.prepareAppTransition(TRANSIT_TO_BACK); + mDisplayContent.requestTransitionAndLegacyPrepare(TRANSIT_TO_BACK, tr); moveToBack("moveTaskToBackLocked", tr); if (inPinnedWindowingMode()) { diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index d5322eac3886..ecf2cdfb6b6b 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -22,13 +22,14 @@ import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANI import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER; -import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY; -import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER; +import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY; +import android.annotation.IntDef; import android.annotation.NonNull; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; +import android.os.SystemClock; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; @@ -41,6 +42,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.ProtoLogGroup; import com.android.internal.protolog.common.ProtoLog; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Map; @@ -65,17 +68,32 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe */ private static final int STATE_PLAYING = 2; - final @WindowManager.TransitionOldType int mType; + /** + * This transition is aborting or has aborted. No animation will play nor will anything get + * sent to the player. + */ + private static final int STATE_ABORT = 3; + + @IntDef(prefix = { "STATE_" }, value = { + STATE_COLLECTING, + STATE_STARTED, + STATE_PLAYING, + STATE_ABORT + }) + @Retention(RetentionPolicy.SOURCE) + @interface TransitionState {} + + final @WindowManager.TransitionType int mType; private int mSyncId; private @WindowManager.TransitionFlags int mFlags; private final TransitionController mController; private final BLASTSyncEngine mSyncEngine; final ArrayMap mParticipants = new ArrayMap<>(); - private int mState = STATE_COLLECTING; + private @TransitionState int mState = STATE_COLLECTING; private boolean mReadyCalled = false; - Transition(@WindowManager.TransitionOldType int type, - @WindowManager.TransitionFlags int flags, TransitionController controller) { + Transition(@WindowManager.TransitionType int type, @WindowManager.TransitionFlags int flags, + TransitionController controller) { mType = type; mFlags = flags; mController = controller; @@ -116,15 +134,20 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe * * If this is called before the transition is started, it will be deferred until start. */ - void setReady() { + void setReady(boolean ready) { if (mSyncId < 0) return; if (mState < STATE_STARTED) { - mReadyCalled = true; + mReadyCalled = ready; return; } ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, - "Finish collecting in transition %d", mSyncId); - mSyncEngine.setReady(mSyncId); + "Set transition ready=%b %d", ready, mSyncId); + mSyncEngine.setReady(mSyncId, ready); + } + + /** @see #setReady . This calls with parameter true. */ + void setReady() { + setReady(true); } /** The transition has finished animating and is ready to finalize WM state */ @@ -143,21 +166,41 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe } } + void abort() { + // This calls back into itself via controller.abort, so just early return here. + if (mState == STATE_ABORT) return; + if (mState != STATE_COLLECTING) { + throw new IllegalStateException("Too late to abort."); + } + mState = STATE_ABORT; + // Syncengine abort will call through to onTransactionReady() + mSyncEngine.abort(mSyncId); + } + @Override public void onTransactionReady(int syncId, SurfaceControl.Transaction transaction) { if (syncId != mSyncId) { Slog.e(TAG, "Unexpected Sync ID " + syncId + ". Expected " + mSyncId); return; } - mState = STATE_PLAYING; - mController.moveToPlaying(this); - final TransitionInfo info = calculateTransitionInfo(mType, mParticipants); - int displayId = DEFAULT_DISPLAY; for (WindowContainer container : mParticipants.keySet()) { + if (container.mDisplayContent == null) continue; displayId = container.mDisplayContent.getDisplayId(); } + if (mState == STATE_ABORT) { + mController.abort(this); + mController.mAtm.mRootWindowContainer.getDisplayContent(displayId) + .getPendingTransaction().merge(transaction); + mSyncId = -1; + return; + } + + mState = STATE_PLAYING; + mController.moveToPlaying(this); + final TransitionInfo info = calculateTransitionInfo(mType, mParticipants); + handleNonAppWindowsInTransition(displayId, mType, mFlags); if (mController.getTransitionPlayer() != null) { @@ -176,13 +219,14 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe mSyncId = -1; } - private void handleNonAppWindowsInTransition(int displayId, int transit, int flags) { + private void handleNonAppWindowsInTransition(int displayId, + @WindowManager.TransitionType int transit, int flags) { final DisplayContent dc = mController.mAtm.mRootWindowContainer.getDisplayContent(displayId); if (dc == null) { return; } - if (transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY) { + if (transit == TRANSIT_KEYGUARD_GOING_AWAY) { if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0 && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0 && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) == 0) { @@ -196,13 +240,13 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe } } } - if (transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY - || transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER) { + if (transit == TRANSIT_KEYGUARD_GOING_AWAY) { dc.startKeyguardExitOnNonAppWindows( - transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER, + (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0, (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0, (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) != 0); - mController.mAtm.mWindowManager.mPolicy.startKeyguardExitAnimation(transit, 0); + mController.mAtm.mWindowManager.mPolicy.startKeyguardExitAnimation( + SystemClock.uptimeMillis(), 0 /* duration */); } } @@ -447,7 +491,8 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe final WindowContainer target = targets.keyAt(i); final ChangeInfo info = targets.valueAt(i); final TransitionInfo.Change change = new TransitionInfo.Change( - target.mRemoteToken.toWindowContainerToken(), target.getSurfaceControl()); + target.mRemoteToken != null ? target.mRemoteToken.toWindowContainerToken() + : null, target.getSurfaceControl()); if (info.mParent != null) { change.setParent(info.mParent.mRemoteToken.toWindowContainerToken()); } diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index c2fb4cd9f6b3..773bcaf14f15 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -16,14 +16,6 @@ package com.android.server.wm; -import static android.view.WindowManager.TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY; -import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN; -import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN_BEHIND; -import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_BACK; -import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_FRONT; - import android.annotation.NonNull; import android.annotation.Nullable; import android.os.IBinder; @@ -36,7 +28,6 @@ import com.android.internal.protolog.ProtoLogGroup; import com.android.internal.protolog.common.ProtoLog; import java.util.ArrayList; -import java.util.Arrays; /** * Handles all the aspects of recording and synchronizing transitions. @@ -44,13 +35,6 @@ import java.util.Arrays; class TransitionController { private static final String TAG = "TransitionController"; - private static final int[] SUPPORTED_LEGACY_TRANSIT_TYPES = {TRANSIT_OLD_TASK_OPEN, - TRANSIT_OLD_TASK_CLOSE, TRANSIT_OLD_TASK_TO_FRONT, TRANSIT_OLD_TASK_TO_BACK, - TRANSIT_OLD_TASK_OPEN_BEHIND, TRANSIT_OLD_KEYGUARD_GOING_AWAY}; - static { - Arrays.sort(SUPPORTED_LEGACY_TRANSIT_TYPES); - } - private ITransitionPlayer mTransitionPlayer; private final IBinder.DeathRecipient mTransitionPlayerDeath = () -> mTransitionPlayer = null; final ActivityTaskManagerService mAtm; @@ -81,6 +65,9 @@ class TransitionController { @NonNull Transition createTransition(@WindowManager.TransitionOldType int type, @WindowManager.TransitionFlags int flags) { + if (mTransitionPlayer == null) { + throw new IllegalStateException("Shell Transitions not enabled"); + } if (mCollectingTransition != null) { throw new IllegalStateException("Simultaneous transitions not supported yet."); } @@ -111,6 +98,14 @@ class TransitionController { return mTransitionPlayer != null; } + /** + * @return {@code true} if transition is actively collecting changes. This is {@code false} + * once a transition is playing + */ + boolean isCollecting() { + return mCollectingTransition != null; + } + /** @return {@code true} if a transition is running */ boolean inTransition() { // TODO(shell-transitions): eventually properly support multiple @@ -133,26 +128,46 @@ class TransitionController { } /** - * Creates a transition and asks the TransitionPlayer (Shell) to start it. - * @return the created transition. Collection can start immediately. + * @see #requestTransitionIfNeeded(int, int) */ - @NonNull - Transition requestTransition(@WindowManager.TransitionOldType int type) { - return requestTransition(type, 0 /* flags */); + @Nullable + Transition requestTransitionIfNeeded(@WindowManager.TransitionType int type, + @Nullable WindowContainer trigger) { + return requestTransitionIfNeeded(type, 0 /* flags */, trigger); } - /** @see #requestTransition */ - @NonNull - Transition requestTransition(@WindowManager.TransitionOldType int type, - @WindowManager.TransitionFlags int flags) { + /** + * 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 + * @return the created transition if created or null otherwise. + */ + @Nullable + Transition requestTransitionIfNeeded(@WindowManager.TransitionType int type, + @WindowManager.TransitionFlags int flags, @Nullable WindowContainer trigger) { if (mTransitionPlayer == null) { - throw new IllegalStateException("Shell Transitions not enabled"); + return null; + } + Transition newTransition = null; + if (isCollecting()) { + // Make the collecting transition wait until this request is ready. + mCollectingTransition.setReady(false); + } else { + newTransition = requestStartTransition(createTransition(type, flags)); } - final Transition transition = createTransition(type, flags); + if (trigger != null) { + collect(trigger); + } + return newTransition; + } + + /** Asks the transition player (shell) to start a created but not yet started transition. */ + @NonNull + Transition requestStartTransition(@NonNull Transition transition) { try { ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Requesting StartTransition: %s", transition); - mTransitionPlayer.requestStartTransition(type, transition); + mTransitionPlayer.requestStartTransition(transition.mType, transition); } catch (RemoteException e) { Slog.e(TAG, "Error requesting transition", e); transition.start(); @@ -160,35 +175,6 @@ class TransitionController { return transition; } - /** - * Temporary adapter that converts the legacy AppTransition's prepareAppTransition call into - * a Shell transition request. If shell transitions are enabled, this will take priority in - * handling transition types that it supports. All other transitions will be ignored and thus - * be handled by the legacy apptransition system. This allows both worlds to live in tandem - * during migration. - * - * @return {@code true} if the transition is handled. - */ - boolean adaptLegacyPrepare(@WindowManager.TransitionOldType int transit, - @WindowManager.TransitionFlags int flags, boolean forceOverride) { - if (!isShellTransitionsEnabled() - || Arrays.binarySearch(SUPPORTED_LEGACY_TRANSIT_TYPES, transit) < 0) { - return false; - } - if (inTransition()) { - if (AppTransition.isKeyguardTransit(transit)) { - // TODO(shell-transitions): add to flags - } else if (forceOverride) { - // TODO(shell-transitions): sort out these flags - } else if (transit == TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE) { - // TODO(shell-transitions): record crashing - } - } else { - requestTransition(transit, flags); - } - return true; - } - /** @see Transition#collect */ void collect(@NonNull WindowContainer wc) { if (mCollectingTransition == null) return; @@ -196,9 +182,14 @@ class TransitionController { } /** @see Transition#setReady */ - void setReady() { + void setReady(boolean ready) { if (mCollectingTransition == null) return; - mCollectingTransition.setReady(); + mCollectingTransition.setReady(ready); + } + + /** @see Transition#setReady */ + void setReady() { + setReady(true); } /** @see Transition#finishTransition */ @@ -221,4 +212,12 @@ class TransitionController { mPlayingTransitions.add(transition); } + void abort(Transition transition) { + if (transition != mCollectingTransition) { + throw new IllegalStateException("Too late to abort."); + } + transition.abort(); + mCollectingTransition = null; + } + } -- cgit v1.2.3-59-g8ed1b