diff options
6 files changed, 154 insertions, 87 deletions
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 325ebbe885b4..8e619a8bda48 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -609,4 +609,6 @@ message BackNavigationProto { optional bool animation_in_progress = 1; optional int32 last_back_type = 2; optional bool show_wallpaper = 3; + optional string main_open_activity = 4; + optional bool animation_running = 5; }
\ No newline at end of file diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index e93f35802953..0c6bad886ebd 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -226,6 +226,7 @@ import static com.android.server.wm.IdentifierProto.USER_ID; import static com.android.server.wm.LetterboxConfiguration.DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW; import static com.android.server.wm.LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_PREDICT_BACK; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE; @@ -7632,7 +7633,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @Override void prepareSurfaces() { final boolean show = isVisible() || isAnimating(PARENTS, - ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS); + ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS + | ANIMATION_TYPE_PREDICT_BACK); if (mSurfaceControl != null) { if (show && !mLastSurfaceShowing) { diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index 0c196d7e99e9..976641b52a16 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -26,7 +26,9 @@ import static android.view.WindowManager.TRANSIT_TO_BACK; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW; import static com.android.server.wm.BackNavigationProto.ANIMATION_IN_PROGRESS; +import static com.android.server.wm.BackNavigationProto.ANIMATION_RUNNING; import static com.android.server.wm.BackNavigationProto.LAST_BACK_TYPE; +import static com.android.server.wm.BackNavigationProto.MAIN_OPEN_ACTIVITY; import static com.android.server.wm.BackNavigationProto.SHOW_WALLPAPER; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_PREDICT_BACK; @@ -50,6 +52,7 @@ import android.view.WindowInsets; import android.window.BackAnimationAdapter; import android.window.BackNavigationInfo; import android.window.IBackAnimationFinishedCallback; +import android.window.IWindowlessStartingSurfaceCallback; import android.window.OnBackInvokedCallbackInfo; import android.window.TaskSnapshot; @@ -73,6 +76,8 @@ class BackNavigationController { private @BackNavigationInfo.BackTargetType int mLastBackType; private boolean mShowWallpaper; private Runnable mPendingAnimation; + + private boolean mBackAnimationRunning; private final NavigationMonitor mNavigationMonitor = new NavigationMonitor(); private AnimationHandler mAnimationHandler; @@ -474,7 +479,7 @@ class BackNavigationController { final ActivityRecord ar = openApps.valueAt(i); if (mAnimationHandler.isTarget(ar, true /* open */)) { openApps.removeAt(i); - mAnimationHandler.mOpenTransitionTargetMatch = true; + mAnimationHandler.markStartingSurfaceMatch(); } } for (int i = closeApps.size() - 1; i >= 0; --i) { @@ -583,8 +588,9 @@ class BackNavigationController { * The closing target should only exist in close list, but the opening target can be either in * open or close list. */ - void onTransactionReady(Transition transition, ArrayList<Transition.ChangeInfo> targets) { - if (!isMonitoringTransition()) { + void onTransactionReady(Transition transition, ArrayList<Transition.ChangeInfo> targets, + SurfaceControl.Transaction startTransaction) { + if (!isMonitoringTransition() || targets.isEmpty()) { return; } for (int i = targets.size() - 1; i >= 0; --i) { @@ -613,6 +619,17 @@ class BackNavigationController { Slog.e(TAG, "Gesture animation is applied on another transition?"); } mWaitTransitionFinish = transition; + // Flag target matches to defer remove the splash screen. + for (int i = mTmpOpenApps.size() - 1; i >= 0; --i) { + final WindowContainer wc = mTmpOpenApps.get(i); + if (mAnimationHandler.isTarget(wc, true /* open */)) { + mAnimationHandler.markStartingSurfaceMatch(); + break; + } + } + // Because the target will reparent to transition root, so it cannot be controlled by + // animation leash. Hide the close target when transition starts. + startTransaction.hide(mAnimationHandler.mCloseAdaptor.mTarget.getSurfaceControl()); } mTmpOpenApps.clear(); mTmpCloseApps.clear(); @@ -633,6 +650,7 @@ class BackNavigationController { mAnimationHandler.clearBackAnimateTarget(); mNavigationMonitor.stopMonitorTransition(); mWaitTransitionFinish = null; + mBackAnimationRunning = false; } /** @@ -717,11 +735,7 @@ class BackNavigationController { // This will be set before transition happen, to know whether the real opening target // exactly match animating target. When target match, reparent the starting surface to // the opening target like starting window do. - private boolean mOpenTransitionTargetMatch; - // The starting surface task Id. Used to clear the starting surface if the animation has - // request one during animating. - private int mRequestedStartingSurfaceTaskId; - private SurfaceControl mStartingSurface; + private boolean mStartingSurfaceTargetMatch; private ActivityRecord mOpenActivity; AnimationHandler(WindowManagerService wms) { @@ -765,8 +779,8 @@ class BackNavigationController { return; } - mCloseAdaptor = createAdaptor(closeTarget, false /* isOpen */); - mOpenAdaptor = createAdaptor(open, true /* isOpen */); + mCloseAdaptor = createAdaptor(closeTarget, false, mSwitchType); + mOpenAdaptor = createAdaptor(open, true, mSwitchType); mOpenActivity = openActivity; if (mCloseAdaptor.mAnimationTarget == null || mOpenAdaptor.mAnimationTarget == null) { Slog.w(TAG, "composeNewAnimations fail, skip"); @@ -774,8 +788,8 @@ class BackNavigationController { } } - boolean composeAnimations(@NonNull WindowContainer close, @NonNull WindowContainer open, - ActivityRecord openActivity) { + private boolean composeAnimations(@NonNull WindowContainer close, + @NonNull WindowContainer open, ActivityRecord openActivity) { if (mComposed || mWaitTransition) { Slog.e(TAG, "Previous animation is running " + this); return false; @@ -805,28 +819,6 @@ class BackNavigationController { .isSupportWindowlessStartingSurface(); } - void createStartingSurface(TaskSnapshot snapshot) { - if (!mComposed) { - return; - } - - final ActivityRecord topActivity = getTopOpenActivity(); - if (topActivity == null) { - Slog.e(TAG, "createStartingSurface fail, no open activity: " + this); - return; - } - // TODO (b/257857570) draw snapshot by starting surface. - } - - private ActivityRecord getTopOpenActivity() { - if (mSwitchType == ACTIVITY_SWITCH) { - return mOpenAdaptor.mTarget.asActivityRecord(); - } else if (mSwitchType == TASK_SWITCH) { - return mOpenAdaptor.mTarget.asTask().getTopNonFinishingActivity(); - } - return null; - } - boolean containTarget(ArrayList<WindowContainer> wcs, boolean open) { for (int i = wcs.size() - 1; i >= 0; --i) { if (isTarget(wcs.get(i), open)) { @@ -860,13 +852,13 @@ class BackNavigationController { if (!mComposed) { return; } - cleanUpWindowlessSurface(); if (mCloseAdaptor != null) { mCloseAdaptor.mTarget.cancelAnimation(); mCloseAdaptor = null; } if (mOpenAdaptor != null) { + mOpenAdaptor.cleanUpWindowlessSurface(mStartingSurfaceTargetMatch); mOpenAdaptor.mTarget.cancelAnimation(); mOpenAdaptor = null; } @@ -875,36 +867,16 @@ class BackNavigationController { } } - private void cleanUpWindowlessSurface() { - final ActivityRecord ar = getTopOpenActivity(); - if (ar == null) { - Slog.w(TAG, "finishPresentAnimations without top activity: " + this); - } - final SurfaceControl.Transaction pendingT = ar != null ? ar.getPendingTransaction() - : mOpenAdaptor.mTarget.getPendingTransaction(); - // ensure open target is visible before cancel animation. - mOpenTransitionTargetMatch &= ar != null; - if (mOpenTransitionTargetMatch) { - pendingT.show(ar.getSurfaceControl()); - } - if (mRequestedStartingSurfaceTaskId != 0) { - // If open target match, reparent to open activity - if (mStartingSurface != null && mOpenTransitionTargetMatch) { - pendingT.reparent(mStartingSurface, ar.getSurfaceControl()); - } - // remove starting surface. - mStartingSurface = null; - // TODO (b/257857570) draw snapshot by starting surface. - mRequestedStartingSurfaceTaskId = 0; - } + void markStartingSurfaceMatch() { + mStartingSurfaceTargetMatch = true; + mOpenAdaptor.reparentWindowlessSurfaceToTarget(); } void clearBackAnimateTarget() { finishPresentAnimations(); mComposed = false; mWaitTransition = false; - mOpenTransitionTargetMatch = false; - mRequestedStartingSurfaceTaskId = 0; + mStartingSurfaceTargetMatch = false; mSwitchType = UNKNOWN; mOpenActivity = null; } @@ -935,9 +907,9 @@ class BackNavigationController { } private static BackWindowAnimationAdaptor createAdaptor( - WindowContainer target, boolean isOpen) { + WindowContainer target, boolean isOpen, int switchType) { final BackWindowAnimationAdaptor adaptor = - new BackWindowAnimationAdaptor(target, isOpen); + new BackWindowAnimationAdaptor(target, isOpen, switchType); final SurfaceControl.Transaction pt = target.getPendingTransaction(); target.startAnimation(pt, adaptor, false /* hidden */, ANIMATION_TYPE_PREDICT_BACK); // Workaround to show TaskFragment which can be hide in Transitions and won't show @@ -957,11 +929,19 @@ class BackNavigationController { private final WindowContainer mTarget; private final boolean mIsOpen; private RemoteAnimationTarget mAnimationTarget; + private final int mSwitchType; - BackWindowAnimationAdaptor(WindowContainer closeTarget, boolean isOpen) { - mBounds.set(closeTarget.getBounds()); - mTarget = closeTarget; + // The starting surface task Id. Used to clear the starting surface if the animation has + // requested one during animating. + private int mRequestedStartingSurfaceId = INVALID_TASK_ID; + private SurfaceControl mStartingSurface; + + BackWindowAnimationAdaptor(WindowContainer target, boolean isOpen, + int switchType) { + mBounds.set(target.getBounds()); + mTarget = target; mIsOpen = isOpen; + mSwitchType = switchType; } @Override public boolean getShowWallpaper() { @@ -979,6 +959,8 @@ class BackNavigationController { public void onAnimationCancelled(SurfaceControl animationLeash) { if (mCapturedLeash == animationLeash) { mCapturedLeash = null; + mRequestedStartingSurfaceId = INVALID_TASK_ID; + mStartingSurface = null; } } @@ -1009,8 +991,15 @@ class BackNavigationController { return mAnimationTarget; } Task t = mTarget.asTask(); - final ActivityRecord r = t != null ? t.getTopNonFinishingActivity() - : mTarget.asActivityRecord(); + ActivityRecord r = null; + if (t == null && mTarget.asTaskFragment() != null) { + t = mTarget.asTaskFragment().getTask(); + r = mTarget.asTaskFragment().getTopNonFinishingActivity(); + } + if (r == null) { + r = t != null ? t.getTopNonFinishingActivity() + : mTarget.asActivityRecord(); + } if (t == null && r != null) { t = r.getTask(); } @@ -1037,6 +1026,77 @@ class BackNavigationController { r.checkEnterPictureInPictureAppOpsState()); return mAnimationTarget; } + + void createStartingSurface() { + if (!mIsOpen) { + return; + } + final Task openTask = mSwitchType == TASK_SWITCH + ? mTarget.asTask() : mSwitchType == ACTIVITY_SWITCH + ? mTarget.asActivityRecord().getTask() : null; + if (openTask == null) { + return; + } + final ActivityRecord mainActivity = mSwitchType == ACTIVITY_SWITCH + ? mTarget.asActivityRecord() + : openTask.getTopNonFinishingActivity(); + if (mainActivity == null) { + return; + } + final TaskSnapshot snapshot = getSnapshot(mTarget); + mRequestedStartingSurfaceId = openTask.mAtmService.mTaskOrganizerController + .addWindowlessStartingSurface(openTask, mainActivity, + mAnimationTarget.leash, snapshot, + new IWindowlessStartingSurfaceCallback.Stub() { + // Once the starting surface has been created in shell, it will call + // onSurfaceAdded to pass the created surface to core, so if a + // transition is triggered by the back gesture, there doesn't need to + // create another starting surface for the opening target, just reparent + // the starting surface to the opening target. + // Note if cleanUpWindowlessSurface happen prior than onSurfaceAdded + // called, there won't be able to reparent the starting surface on + // opening target. But if that happens and transition target is matched, + // the app window should already draw. + @Override + public void onSurfaceAdded(SurfaceControl sc) { + synchronized (mTarget.mWmService.mGlobalLock) { + if (mRequestedStartingSurfaceId != INVALID_TASK_ID) { + mStartingSurface = sc; + } + } + } + }); + } + + // When back gesture has triggered and transition target matches navigation target, + // reparent the starting surface to the opening target as it's starting window. + void reparentWindowlessSurfaceToTarget() { + if (mRequestedStartingSurfaceId == INVALID_TASK_ID) { + return; + } + // If open target matches, reparent to open activity or task + if (mStartingSurface != null && mStartingSurface.isValid()) { + mTarget.getPendingTransaction() + .reparent(mStartingSurface, mTarget.getSurfaceControl()); + // remove starting surface. + mStartingSurface = null; + } + } + + /** + * Ask shell to clear the starting surface. + * @param openTransitionMatch if true, shell will play the remove starting window + * animation, otherwise remove it directly. + */ + void cleanUpWindowlessSurface(boolean openTransitionMatch) { + if (mRequestedStartingSurfaceId == INVALID_TASK_ID) { + return; + } + mTarget.mWmService.mAtmService.mTaskOrganizerController + .removeWindowlessStartingSurface(mRequestedStartingSurfaceId, + !openTransitionMatch); + mRequestedStartingSurfaceId = INVALID_TASK_ID; + } } ScheduleAnimationBuilder prepareAnimation(int backType, BackAnimationAdapter adapter, @@ -1089,15 +1149,13 @@ class BackNavigationController { /** * Apply preview strategy on the opening target - * @param open The opening target. + * @param openAnimationAdaptor The animator who can create starting surface. * @param visibleOpenActivity The visible activity in opening target. - * @return If the preview strategy is launch behind, returns the Activity that has - * launchBehind set, or null otherwise. */ - private void applyPreviewStrategy(WindowContainer open, + private void applyPreviewStrategy(BackWindowAnimationAdaptor openAnimationAdaptor, ActivityRecord visibleOpenActivity) { if (isSupportWindowlessSurface() && mShowWindowlessSurface && !mIsLaunchBehind) { - createStartingSurface(getSnapshot(open)); + openAnimationAdaptor.createStartingSurface(); return; } setLaunchBehind(visibleOpenActivity); @@ -1119,7 +1177,7 @@ class BackNavigationController { if (!composeAnimations(mCloseTarget, mOpenTarget, openActivity)) { return null; } - applyPreviewStrategy(mOpenTarget, openActivity); + applyPreviewStrategy(mOpenAdaptor, openActivity); final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback(); final RemoteAnimationTarget[] targets = getAnimationTargets(); @@ -1220,6 +1278,7 @@ class BackNavigationController { if (mPendingAnimation != null) { mPendingAnimation.run(); mPendingAnimation = null; + mBackAnimationRunning = true; } } @@ -1236,9 +1295,6 @@ class BackNavigationController { } static TaskSnapshot getSnapshot(@NonNull WindowContainer w) { - if (!isScreenshotEnabled()) { - return null; - } if (w.asTask() != null) { final Task task = w.asTask(); return task.mRootWindowContainer.mWindowManager.mTaskSnapshotController.getSnapshot( @@ -1247,8 +1303,8 @@ class BackNavigationController { } if (w.asActivityRecord() != null) { - // TODO (b/259497289) return TaskSnapshot when feature complete. - return null; + final ActivityRecord ar = w.asActivityRecord(); + return ar.mWmService.mSnapshotController.mActivitySnapshotController.getSnapshot(ar); } return null; } @@ -1270,6 +1326,12 @@ class BackNavigationController { proto.write(ANIMATION_IN_PROGRESS, mBackAnimationInProgress); proto.write(LAST_BACK_TYPE, mLastBackType); proto.write(SHOW_WALLPAPER, mShowWallpaper); + if (mAnimationHandler.mOpenActivity != null) { + mAnimationHandler.mOpenActivity.writeNameToProto(proto, MAIN_OPEN_ACTIVITY); + } else { + proto.write(MAIN_OPEN_ACTIVITY, ""); + } + proto.write(ANIMATION_RUNNING, mBackAnimationRunning); proto.end(token); } } diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index cdb4ad645dc3..b72d02789114 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -790,12 +790,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } boolean isSupportWindowlessStartingSurface() { - // Enable after ag/20426257 final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast(); - if (lastOrganizer == null) { - return false; - } - return false; + return lastOrganizer != null; } /** * Notify the shell ({@link com.android.wm.shell.ShellTaskOrganizer} that the client has diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index b7c8092e3774..f33af5efb691 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -1499,7 +1499,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { mTargets = calculateTargets(mParticipants, mChanges); // Check whether the participants were animated from back navigation. - mController.mAtm.mBackNavigationController.onTransactionReady(this, mTargets); + mController.mAtm.mBackNavigationController.onTransactionReady(this, mTargets, + transaction); final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, transaction); info.setDebugId(mSyncId); mController.assignTrack(this, info); diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java index 6d7f2c13197c..1c86758f28ff 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java @@ -570,6 +570,7 @@ public class BackNavigationControllerTests extends WindowTestsBase { final ContextWrapper contextSpy = Mockito.spy(new ContextWrapper(mWm.mContext)); final Resources resourcesSpy = Mockito.spy(contextSpy.getResources()); + spyOn(mAtm.mTaskOrganizerController); when(contextSpy.getResources()).thenReturn(resourcesSpy); MockitoSession mockitoSession = mockitoSession().mockStatic(BackNavigationController.class) @@ -597,7 +598,8 @@ public class BackNavigationControllerTests extends WindowTestsBase { mBackAnimationAdapter, task, mRootHomeTask, bottomActivity, homeActivity); assertTrue(toHomeBuilder.mIsLaunchBehind); toHomeBuilder.build(); - verify(animationHandler, never()).createStartingSurface(any()); + verify(mAtm.mTaskOrganizerController, never()) + .addWindowlessStartingSurface(any(), any(), any(), any(), any()); animationHandler.clearBackAnimateTarget(); // Back to ACTIVITY and TASK have the same logic, just with different target. @@ -609,9 +611,11 @@ public class BackNavigationControllerTests extends WindowTestsBase { assertFalse(toActivityBuilder.mIsLaunchBehind); toActivityBuilder.build(); if (preferWindowlessSurface) { - verify(animationHandler).createStartingSurface(any()); + verify(mAtm.mTaskOrganizerController) + .addWindowlessStartingSurface(any(), any(), any(), any(), any()); } else { - verify(animationHandler, never()).createStartingSurface(any()); + verify(mAtm.mTaskOrganizerController, never()) + .addWindowlessStartingSurface(any(), any(), any(), any(), any()); } } |