Loading services/core/java/com/android/server/wm/AppTransitionController.java +1 −1 Original line number Diff line number Diff line Loading @@ -258,7 +258,7 @@ public class AppTransitionController { tmpCloseApps = new ArraySet<>(mDisplayContent.mClosingApps); if (mDisplayContent.mAtmService.mBackNavigationController .removeIfContainsBackAnimationTargets(tmpOpenApps, tmpCloseApps)) { mDisplayContent.mAtmService.mBackNavigationController.clearBackAnimations(null); mDisplayContent.mAtmService.mBackNavigationController.clearBackAnimations(); } } Loading services/core/java/com/android/server/wm/BackNavigationController.java +116 −101 Original line number Diff line number Diff line Loading @@ -62,13 +62,12 @@ import com.android.server.wm.utils.InsetUtils; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Objects; import java.util.function.Consumer; /** * Controller to handle actions related to the back gesture on the server side. */ class BackNavigationController { private static final String TAG = "BackNavigationController"; private static final String TAG = "CoreBackPreview"; private WindowManagerService mWindowManagerService; private boolean mBackAnimationInProgress; private @BackNavigationInfo.BackTargetType int mLastBackType; Loading @@ -76,7 +75,13 @@ class BackNavigationController { private Runnable mPendingAnimation; private final NavigationMonitor mNavigationMonitor = new NavigationMonitor(); AnimationHandler mAnimationHandler; private AnimationHandler mAnimationHandler; /** * The transition who match the back navigation targets, * release animation after this transition finish. */ private Transition mWaitTransitionFinish; private final ArrayList<WindowContainer> mTmpOpenApps = new ArrayList<>(); private final ArrayList<WindowContainer> mTmpCloseApps = new ArrayList<>(); Loading Loading @@ -140,6 +145,11 @@ class BackNavigationController { BackNavigationInfo.Builder infoBuilder = new BackNavigationInfo.Builder(); synchronized (wmService.mGlobalLock) { if (isMonitoringTransition()) { Slog.w(TAG, "Previous animation hasn't finish, status: " + mAnimationHandler); // Don't start any animation for it. return null; } WindowManagerInternal windowManagerInternal = LocalServices.getService(WindowManagerInternal.class); IBinder focusedWindowToken = windowManagerInternal.getFocusedWindowToken(); Loading Loading @@ -374,7 +384,7 @@ class BackNavigationController { } boolean isMonitoringTransition() { return isWaitBackTransition() || mNavigationMonitor.isMonitoring(); return mAnimationHandler.mComposed || mNavigationMonitor.isMonitorForRemote(); } private void scheduleAnimation(@NonNull AnimationHandler.ScheduleAnimationBuilder builder) { Loading Loading @@ -477,7 +487,7 @@ class BackNavigationController { return false; } private static class NavigationMonitor { private class NavigationMonitor { // The window which triggering the back navigation. private WindowState mNavigatingWindow; private RemoteCallback mObserver; Loading @@ -487,15 +497,23 @@ class BackNavigationController { mObserver = observer; } void stopMonitor() { mNavigatingWindow = null; void stopMonitorForRemote() { mObserver = null; } boolean isMonitoring() { void stopMonitorTransition() { mNavigatingWindow = null; } boolean isMonitorForRemote() { return mNavigatingWindow != null && mObserver != null; } boolean isMonitorAnimationOrTransition() { return mNavigatingWindow != null && (mAnimationHandler.mComposed || mAnimationHandler.mWaitTransition); } /** * Notify focus window changed during back navigation. This will cancel the gesture for * scenarios like: a system window popup, or when an activity add a new window. Loading @@ -506,7 +524,8 @@ class BackNavigationController { * a short time, but we should not cancel the navigation. */ private void onFocusWindowChanged(WindowState newFocus) { if (!isMonitoring() || !atSameDisplay(newFocus)) { if (!atSameDisplay(newFocus) || !(isMonitorForRemote() || isMonitorAnimationOrTransition())) { return; } // Keep navigating if either new focus == navigating window or null. Loading @@ -514,8 +533,14 @@ class BackNavigationController { && (newFocus.mActivityRecord == null || (newFocus.mActivityRecord == mNavigatingWindow.mActivityRecord))) { EventLogTags.writeWmBackNaviCanceled("focusWindowChanged"); if (isMonitorForRemote()) { mObserver.sendResult(null /* result */); } if (isMonitorAnimationOrTransition()) { // transition won't happen, cancel internal status clearBackAnimations(); } } } /** Loading @@ -523,7 +548,7 @@ class BackNavigationController { */ private void onTransitionReadyWhileNavigate(ArrayList<WindowContainer> opening, ArrayList<WindowContainer> closing) { if (!isMonitoring()) { if (!isMonitorForRemote() && !isMonitorAnimationOrTransition()) { return; } final ArrayList<WindowContainer> all = new ArrayList<>(opening); Loading @@ -531,7 +556,12 @@ class BackNavigationController { for (WindowContainer app : all) { if (app.hasChild(mNavigatingWindow)) { EventLogTags.writeWmBackNaviCanceled("transitionHappens"); if (isMonitorForRemote()) { mObserver.sendResult(null /* result */); } if (isMonitorAnimationOrTransition()) { clearBackAnimations(); } break; } } Loading @@ -539,6 +569,9 @@ class BackNavigationController { } private boolean atSameDisplay(WindowState newFocus) { if (mNavigatingWindow == null) { return false; } final int navigatingDisplayId = mNavigatingWindow.getDisplayId(); return newFocus == null || newFocus.getDisplayId() == navigatingDisplayId; } Loading @@ -551,12 +584,10 @@ class BackNavigationController { * close target for a transition. So the condition here is * The closing target should only exist in close list, but the opening target can be either in * open or close list. * @return {@code true} if the participants of this transition was animated by back gesture * animations, and shouldn't join next transition. */ boolean containsBackAnimationTargets(Transition transition) { void onTransactionReady(Transition transition) { if (!isMonitoringTransition()) { return false; return; } final ArraySet<WindowContainer> targets = transition.mParticipants; for (int i = targets.size() - 1; i >= 0; --i) { Loading @@ -576,33 +607,44 @@ class BackNavigationController { && mAnimationHandler.containsBackAnimationTargets(mTmpOpenApps, mTmpCloseApps); if (!matchAnimationTargets) { mNavigationMonitor.onTransitionReadyWhileNavigate(mTmpOpenApps, mTmpCloseApps); } else { if (mWaitTransitionFinish != null) { Slog.e(TAG, "Gesture animation is applied on another transition?"); } mWaitTransitionFinish = transition; } mTmpOpenApps.clear(); mTmpCloseApps.clear(); return matchAnimationTargets; } boolean isMonitorTransitionTarget(WindowContainer wc) { if (!isWaitBackTransition()) { if (!isWaitBackTransition() || mWaitTransitionFinish == null) { return false; } return mAnimationHandler.isTarget(wc, wc.isVisibleRequested() /* open */); } /** * Cleanup animation, this can either happen when transition ready or finish. * @param cleanupTransaction The transaction which the caller want to apply the internal * cleanup together. * Cleanup animation, this can either happen when legacy transition ready, or when the Shell * transition finish. */ void clearBackAnimations(SurfaceControl.Transaction cleanupTransaction) { mAnimationHandler.clearBackAnimateTarget(cleanupTransaction); void clearBackAnimations() { mAnimationHandler.clearBackAnimateTarget(); mNavigationMonitor.stopMonitorTransition(); mWaitTransitionFinish = null; } /** * Called when a transition finished. * Handle the pending animation when the running transition finished. * @param targets The final animation targets derived in transition. * @param finishedTransition The finished transition target. */ boolean handleDeferredBackAnimation(@NonNull ArrayList<Transition.ChangeInfo> targets) { boolean onTransitionFinish(ArrayList<Transition.ChangeInfo> targets, @NonNull Transition finishedTransition) { if (finishedTransition == mWaitTransitionFinish) { clearBackAnimations(); } if (!mBackAnimationInProgress || mPendingAnimationBuilder == null) { return false; } Loading Loading @@ -660,7 +702,7 @@ class BackNavigationController { private boolean mComposed; private boolean mWaitTransition; private int mSwitchType = UNKNOWN; private SurfaceControl.Transaction mFinishedTransaction; // 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. Loading @@ -669,6 +711,7 @@ class BackNavigationController { // request one during animating. private int mRequestedStartingSurfaceTaskId; private SurfaceControl mStartingSurface; private ActivityRecord mOpenActivity; AnimationHandler(WindowManagerService wms) { mWindowManagerService = wms; Loading Loading @@ -697,7 +740,8 @@ class BackNavigationController { return true; } private void initiate(WindowContainer close, WindowContainer open) { private void initiate(WindowContainer close, WindowContainer open, ActivityRecord openActivity) { WindowContainer closeTarget; if (isActivitySwitch(close, open)) { mSwitchType = ACTIVITY_SWITCH; Loading @@ -712,22 +756,26 @@ class BackNavigationController { mCloseAdaptor = createAdaptor(closeTarget, false /* isOpen */); mOpenAdaptor = createAdaptor(open, true /* isOpen */); mOpenActivity = openActivity; if (mCloseAdaptor.mAnimationTarget == null || mOpenAdaptor.mAnimationTarget == null) { Slog.w(TAG, "composeNewAnimations fail, skip"); clearBackAnimateTarget(null /* cleanupTransaction */); clearBackAnimateTarget(); } } private boolean composeAnimations(@NonNull WindowContainer close, @NonNull WindowContainer open) { clearBackAnimateTarget(null /* cleanupTransaction */); if (close == null || open == null) { boolean composeAnimations(@NonNull WindowContainer close, @NonNull WindowContainer open, ActivityRecord openActivity) { if (mComposed || mWaitTransition) { Slog.e(TAG, "Previous animation is running " + this); return false; } clearBackAnimateTarget(); if (close == null || open == null || openActivity == null) { Slog.e(TAG, "reset animation with null target close: " + close + " open: " + open); return false; } initiate(close, open); initiate(close, open, openActivity); if (mSwitchType == UNKNOWN) { return false; } Loading Loading @@ -791,24 +839,10 @@ class BackNavigationController { return false; } boolean setFinishTransaction(SurfaceControl.Transaction finishTransaction) { if (!mComposed) { return false; } mFinishedTransaction = finishTransaction; return true; } void finishPresentAnimations(SurfaceControl.Transaction t) { void finishPresentAnimations() { if (!mComposed) { return; } final SurfaceControl.Transaction pt = t != null ? t : mOpenAdaptor.mTarget.getPendingTransaction(); if (mFinishedTransaction != null) { pt.merge(mFinishedTransaction); mFinishedTransaction = null; } cleanUpWindowlessSurface(); if (mCloseAdaptor != null) { Loading @@ -819,6 +853,9 @@ class BackNavigationController { mOpenAdaptor.mTarget.cancelAnimation(); mOpenAdaptor = null; } if (mOpenActivity != null && mOpenActivity.mLaunchTaskBehind) { restoreLaunchBehind(mOpenActivity); } } private void cleanUpWindowlessSurface() { Loading @@ -845,22 +882,14 @@ class BackNavigationController { } } void clearBackAnimateTarget(SurfaceControl.Transaction cleanupTransaction) { finishPresentAnimations(cleanupTransaction); void clearBackAnimateTarget() { finishPresentAnimations(); mComposed = false; mWaitTransition = false; mOpenTransitionTargetMatch = false; mRequestedStartingSurfaceTaskId = 0; mSwitchType = UNKNOWN; if (mFinishedTransaction != null) { Slog.w(TAG, "Clear back animation, found un-processed finished transaction"); if (cleanupTransaction != null) { cleanupTransaction.merge(mFinishedTransaction); } else { mFinishedTransaction.apply(); } mFinishedTransaction = null; } mOpenActivity = null; } // The close target must in close list Loading @@ -876,9 +905,9 @@ class BackNavigationController { public String toString() { return "AnimationTargets{" + " openTarget= " + mOpenAdaptor.mTarget + (mOpenAdaptor != null ? mOpenAdaptor.mTarget : "null") + " closeTarget= " + mCloseAdaptor.mTarget + (mCloseAdaptor != null ? mCloseAdaptor.mTarget : "null") + " mSwitchType= " + mSwitchType + " mComposed= " Loading Loading @@ -1048,14 +1077,13 @@ class BackNavigationController { * @return If the preview strategy is launch behind, returns the Activity that has * launchBehind set, or null otherwise. */ private ActivityRecord applyPreviewStrategy(WindowContainer open, private void applyPreviewStrategy(WindowContainer open, ActivityRecord visibleOpenActivity) { if (isSupportWindowlessSurface() && mShowWindowlessSurface && !mIsLaunchBehind) { createStartingSurface(getSnapshot(open)); return null; return; } setLaunchBehind(visibleOpenActivity); return visibleOpenActivity; } Runnable build() { Loading @@ -1071,19 +1099,12 @@ class BackNavigationController { return null; } if (!composeAnimations(mCloseTarget, mOpenTarget)) { if (!composeAnimations(mCloseTarget, mOpenTarget, openActivity)) { return null; } final ActivityRecord launchBehindActivity = applyPreviewStrategy(mOpenTarget, openActivity); final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback( launchBehindActivity != null ? triggerBack -> { if (!triggerBack) { restoreLaunchBehind(launchBehindActivity); } } : null, mCloseTarget); final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback(); final RemoteAnimationTarget[] targets = getAnimationTargets(); return () -> { Loading @@ -1096,31 +1117,17 @@ class BackNavigationController { }; } private IBackAnimationFinishedCallback makeAnimationFinishedCallback( Consumer<Boolean> b, WindowContainer closeTarget) { private IBackAnimationFinishedCallback makeAnimationFinishedCallback() { return new IBackAnimationFinishedCallback.Stub() { @Override public void onAnimationFinished(boolean triggerBack) { final SurfaceControl.Transaction finishedTransaction = new SurfaceControl.Transaction(); synchronized (mWindowManagerService.mGlobalLock) { if (b != null) { b.accept(triggerBack); } if (triggerBack) { final SurfaceControl surfaceControl = closeTarget.getSurfaceControl(); if (surfaceControl != null && surfaceControl.isValid()) { // Hide the close target surface when transition start. finishedTransaction.hide(surfaceControl); } } if (!setFinishTransaction(finishedTransaction)) { finishedTransaction.apply(); if (!mComposed) { // animation was canceled return; } if (!triggerBack) { clearBackAnimateTarget( null /* cleanupTransaction */); clearBackAnimateTarget(); } else { mWaitTransition = true; } Loading Loading @@ -1180,6 +1187,14 @@ class BackNavigationController { } void startAnimation() { if (!mBackAnimationInProgress) { // gesture is already finished, do not start animation if (mPendingAnimation != null) { clearBackAnimations(); mPendingAnimation = null; } return; } if (mPendingAnimation != null) { mPendingAnimation.run(); mPendingAnimation = null; Loading @@ -1192,7 +1207,7 @@ class BackNavigationController { ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, " + "triggerBack=%b", backType, triggerBack); mNavigationMonitor.stopMonitor(); mNavigationMonitor.stopMonitorForRemote(); mBackAnimationInProgress = false; mShowWallpaper = false; mPendingAnimationBuilder = null; Loading services/core/java/com/android/server/wm/Transition.java +2 −6 Original line number Diff line number Diff line Loading @@ -1031,7 +1031,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { mTmpTransaction.apply(); // Handle back animation if it's already started. mController.mAtm.mBackNavigationController.handleDeferredBackAnimation(mTargets); mController.mAtm.mBackNavigationController.onTransitionFinish(mTargets, this); mController.mFinishingTransition = null; } Loading Loading @@ -1136,8 +1136,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { mFlags |= TRANSIT_FLAG_KEYGUARD_LOCKED; } // Check whether the participants were animated from back navigation. final boolean markBackAnimated = mController.mAtm.mBackNavigationController .containsBackAnimationTargets(this); mController.mAtm.mBackNavigationController.onTransactionReady(this); // Resolve the animating targets from the participants. mTargets = calculateTargets(mParticipants, mChanges); final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, transaction); Loading @@ -1150,9 +1149,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { mTargetDisplays.add(dc); } if (markBackAnimated) { mController.mAtm.mBackNavigationController.clearBackAnimations(mStartTransaction); } if (mOverrideOptions != null) { info.setAnimationOptions(mOverrideOptions); if (mOverrideOptions.getType() == ANIM_OPEN_CROSS_PROFILE_APPS) { Loading services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java +15 −3 Original line number Diff line number Diff line Loading @@ -89,11 +89,12 @@ public class BackNavigationControllerTests extends WindowTestsBase { @Before public void setUp() throws Exception { mBackNavigationController = Mockito.spy(new BackNavigationController()); final BackNavigationController original = new BackNavigationController(); original.setWindowManager(mWm); mBackNavigationController = Mockito.spy(original); LocalServices.removeServiceForTest(WindowManagerInternal.class); mWindowManagerInternal = mock(WindowManagerInternal.class); LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal); mBackNavigationController.setWindowManager(mWm); mBackAnimationAdapter = mock(BackAnimationAdapter.class); mRootHomeTask = initHomeActivity(); } Loading Loading @@ -129,7 +130,9 @@ public class BackNavigationControllerTests extends WindowTestsBase { // verify if back animation would start. assertTrue("Animation scheduled", backNavigationInfo.isPrepareRemoteAnimation()); // reset drawning status // reset drawing status backNavigationInfo.onBackNavigationFinished(false); mBackNavigationController.clearBackAnimations(); topTask.forAllWindows(w -> { makeWindowVisibleAndDrawn(w); }, true); Loading @@ -138,6 +141,8 @@ public class BackNavigationControllerTests extends WindowTestsBase { assertThat(typeToString(backNavigationInfo.getType())) .isEqualTo(typeToString(BackNavigationInfo.TYPE_CALLBACK)); backNavigationInfo.onBackNavigationFinished(false); mBackNavigationController.clearBackAnimations(); doReturn(true).when(recordA).canShowWhenLocked(); backNavigationInfo = startBackNavigation(); assertThat(typeToString(backNavigationInfo.getType())) Loading Loading @@ -194,6 +199,8 @@ public class BackNavigationControllerTests extends WindowTestsBase { assertTrue("Animation scheduled", backNavigationInfo.isPrepareRemoteAnimation()); // reset drawing status backNavigationInfo.onBackNavigationFinished(false); mBackNavigationController.clearBackAnimations(); testCase.recordFront.forAllWindows(w -> { makeWindowVisibleAndDrawn(w); }, true); Loading @@ -202,6 +209,8 @@ public class BackNavigationControllerTests extends WindowTestsBase { assertThat(typeToString(backNavigationInfo.getType())) .isEqualTo(typeToString(BackNavigationInfo.TYPE_CALLBACK)); backNavigationInfo.onBackNavigationFinished(false); mBackNavigationController.clearBackAnimations(); doReturn(true).when(testCase.recordBack).canShowWhenLocked(); backNavigationInfo = startBackNavigation(); assertThat(typeToString(backNavigationInfo.getType())) Loading Loading @@ -240,6 +249,8 @@ public class BackNavigationControllerTests extends WindowTestsBase { assertThat(typeToString(backNavigationInfo.getType())) .isEqualTo(typeToString(BackNavigationInfo.TYPE_RETURN_TO_HOME)); backNavigationInfo.onBackNavigationFinished(false); mBackNavigationController.clearBackAnimations(); setupKeyguardOccluded(); backNavigationInfo = startBackNavigation(); assertThat(typeToString(backNavigationInfo.getType())) Loading Loading @@ -553,6 +564,7 @@ public class BackNavigationControllerTests extends WindowTestsBase { assertTrue(toHomeBuilder.mIsLaunchBehind); toHomeBuilder.build(); verify(animationHandler, never()).createStartingSurface(any()); animationHandler.clearBackAnimateTarget(); // Back to ACTIVITY and TASK have the same logic, just with different target. final ActivityRecord topActivity = createActivityRecord(task); Loading Loading
services/core/java/com/android/server/wm/AppTransitionController.java +1 −1 Original line number Diff line number Diff line Loading @@ -258,7 +258,7 @@ public class AppTransitionController { tmpCloseApps = new ArraySet<>(mDisplayContent.mClosingApps); if (mDisplayContent.mAtmService.mBackNavigationController .removeIfContainsBackAnimationTargets(tmpOpenApps, tmpCloseApps)) { mDisplayContent.mAtmService.mBackNavigationController.clearBackAnimations(null); mDisplayContent.mAtmService.mBackNavigationController.clearBackAnimations(); } } Loading
services/core/java/com/android/server/wm/BackNavigationController.java +116 −101 Original line number Diff line number Diff line Loading @@ -62,13 +62,12 @@ import com.android.server.wm.utils.InsetUtils; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Objects; import java.util.function.Consumer; /** * Controller to handle actions related to the back gesture on the server side. */ class BackNavigationController { private static final String TAG = "BackNavigationController"; private static final String TAG = "CoreBackPreview"; private WindowManagerService mWindowManagerService; private boolean mBackAnimationInProgress; private @BackNavigationInfo.BackTargetType int mLastBackType; Loading @@ -76,7 +75,13 @@ class BackNavigationController { private Runnable mPendingAnimation; private final NavigationMonitor mNavigationMonitor = new NavigationMonitor(); AnimationHandler mAnimationHandler; private AnimationHandler mAnimationHandler; /** * The transition who match the back navigation targets, * release animation after this transition finish. */ private Transition mWaitTransitionFinish; private final ArrayList<WindowContainer> mTmpOpenApps = new ArrayList<>(); private final ArrayList<WindowContainer> mTmpCloseApps = new ArrayList<>(); Loading Loading @@ -140,6 +145,11 @@ class BackNavigationController { BackNavigationInfo.Builder infoBuilder = new BackNavigationInfo.Builder(); synchronized (wmService.mGlobalLock) { if (isMonitoringTransition()) { Slog.w(TAG, "Previous animation hasn't finish, status: " + mAnimationHandler); // Don't start any animation for it. return null; } WindowManagerInternal windowManagerInternal = LocalServices.getService(WindowManagerInternal.class); IBinder focusedWindowToken = windowManagerInternal.getFocusedWindowToken(); Loading Loading @@ -374,7 +384,7 @@ class BackNavigationController { } boolean isMonitoringTransition() { return isWaitBackTransition() || mNavigationMonitor.isMonitoring(); return mAnimationHandler.mComposed || mNavigationMonitor.isMonitorForRemote(); } private void scheduleAnimation(@NonNull AnimationHandler.ScheduleAnimationBuilder builder) { Loading Loading @@ -477,7 +487,7 @@ class BackNavigationController { return false; } private static class NavigationMonitor { private class NavigationMonitor { // The window which triggering the back navigation. private WindowState mNavigatingWindow; private RemoteCallback mObserver; Loading @@ -487,15 +497,23 @@ class BackNavigationController { mObserver = observer; } void stopMonitor() { mNavigatingWindow = null; void stopMonitorForRemote() { mObserver = null; } boolean isMonitoring() { void stopMonitorTransition() { mNavigatingWindow = null; } boolean isMonitorForRemote() { return mNavigatingWindow != null && mObserver != null; } boolean isMonitorAnimationOrTransition() { return mNavigatingWindow != null && (mAnimationHandler.mComposed || mAnimationHandler.mWaitTransition); } /** * Notify focus window changed during back navigation. This will cancel the gesture for * scenarios like: a system window popup, or when an activity add a new window. Loading @@ -506,7 +524,8 @@ class BackNavigationController { * a short time, but we should not cancel the navigation. */ private void onFocusWindowChanged(WindowState newFocus) { if (!isMonitoring() || !atSameDisplay(newFocus)) { if (!atSameDisplay(newFocus) || !(isMonitorForRemote() || isMonitorAnimationOrTransition())) { return; } // Keep navigating if either new focus == navigating window or null. Loading @@ -514,8 +533,14 @@ class BackNavigationController { && (newFocus.mActivityRecord == null || (newFocus.mActivityRecord == mNavigatingWindow.mActivityRecord))) { EventLogTags.writeWmBackNaviCanceled("focusWindowChanged"); if (isMonitorForRemote()) { mObserver.sendResult(null /* result */); } if (isMonitorAnimationOrTransition()) { // transition won't happen, cancel internal status clearBackAnimations(); } } } /** Loading @@ -523,7 +548,7 @@ class BackNavigationController { */ private void onTransitionReadyWhileNavigate(ArrayList<WindowContainer> opening, ArrayList<WindowContainer> closing) { if (!isMonitoring()) { if (!isMonitorForRemote() && !isMonitorAnimationOrTransition()) { return; } final ArrayList<WindowContainer> all = new ArrayList<>(opening); Loading @@ -531,7 +556,12 @@ class BackNavigationController { for (WindowContainer app : all) { if (app.hasChild(mNavigatingWindow)) { EventLogTags.writeWmBackNaviCanceled("transitionHappens"); if (isMonitorForRemote()) { mObserver.sendResult(null /* result */); } if (isMonitorAnimationOrTransition()) { clearBackAnimations(); } break; } } Loading @@ -539,6 +569,9 @@ class BackNavigationController { } private boolean atSameDisplay(WindowState newFocus) { if (mNavigatingWindow == null) { return false; } final int navigatingDisplayId = mNavigatingWindow.getDisplayId(); return newFocus == null || newFocus.getDisplayId() == navigatingDisplayId; } Loading @@ -551,12 +584,10 @@ class BackNavigationController { * close target for a transition. So the condition here is * The closing target should only exist in close list, but the opening target can be either in * open or close list. * @return {@code true} if the participants of this transition was animated by back gesture * animations, and shouldn't join next transition. */ boolean containsBackAnimationTargets(Transition transition) { void onTransactionReady(Transition transition) { if (!isMonitoringTransition()) { return false; return; } final ArraySet<WindowContainer> targets = transition.mParticipants; for (int i = targets.size() - 1; i >= 0; --i) { Loading @@ -576,33 +607,44 @@ class BackNavigationController { && mAnimationHandler.containsBackAnimationTargets(mTmpOpenApps, mTmpCloseApps); if (!matchAnimationTargets) { mNavigationMonitor.onTransitionReadyWhileNavigate(mTmpOpenApps, mTmpCloseApps); } else { if (mWaitTransitionFinish != null) { Slog.e(TAG, "Gesture animation is applied on another transition?"); } mWaitTransitionFinish = transition; } mTmpOpenApps.clear(); mTmpCloseApps.clear(); return matchAnimationTargets; } boolean isMonitorTransitionTarget(WindowContainer wc) { if (!isWaitBackTransition()) { if (!isWaitBackTransition() || mWaitTransitionFinish == null) { return false; } return mAnimationHandler.isTarget(wc, wc.isVisibleRequested() /* open */); } /** * Cleanup animation, this can either happen when transition ready or finish. * @param cleanupTransaction The transaction which the caller want to apply the internal * cleanup together. * Cleanup animation, this can either happen when legacy transition ready, or when the Shell * transition finish. */ void clearBackAnimations(SurfaceControl.Transaction cleanupTransaction) { mAnimationHandler.clearBackAnimateTarget(cleanupTransaction); void clearBackAnimations() { mAnimationHandler.clearBackAnimateTarget(); mNavigationMonitor.stopMonitorTransition(); mWaitTransitionFinish = null; } /** * Called when a transition finished. * Handle the pending animation when the running transition finished. * @param targets The final animation targets derived in transition. * @param finishedTransition The finished transition target. */ boolean handleDeferredBackAnimation(@NonNull ArrayList<Transition.ChangeInfo> targets) { boolean onTransitionFinish(ArrayList<Transition.ChangeInfo> targets, @NonNull Transition finishedTransition) { if (finishedTransition == mWaitTransitionFinish) { clearBackAnimations(); } if (!mBackAnimationInProgress || mPendingAnimationBuilder == null) { return false; } Loading Loading @@ -660,7 +702,7 @@ class BackNavigationController { private boolean mComposed; private boolean mWaitTransition; private int mSwitchType = UNKNOWN; private SurfaceControl.Transaction mFinishedTransaction; // 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. Loading @@ -669,6 +711,7 @@ class BackNavigationController { // request one during animating. private int mRequestedStartingSurfaceTaskId; private SurfaceControl mStartingSurface; private ActivityRecord mOpenActivity; AnimationHandler(WindowManagerService wms) { mWindowManagerService = wms; Loading Loading @@ -697,7 +740,8 @@ class BackNavigationController { return true; } private void initiate(WindowContainer close, WindowContainer open) { private void initiate(WindowContainer close, WindowContainer open, ActivityRecord openActivity) { WindowContainer closeTarget; if (isActivitySwitch(close, open)) { mSwitchType = ACTIVITY_SWITCH; Loading @@ -712,22 +756,26 @@ class BackNavigationController { mCloseAdaptor = createAdaptor(closeTarget, false /* isOpen */); mOpenAdaptor = createAdaptor(open, true /* isOpen */); mOpenActivity = openActivity; if (mCloseAdaptor.mAnimationTarget == null || mOpenAdaptor.mAnimationTarget == null) { Slog.w(TAG, "composeNewAnimations fail, skip"); clearBackAnimateTarget(null /* cleanupTransaction */); clearBackAnimateTarget(); } } private boolean composeAnimations(@NonNull WindowContainer close, @NonNull WindowContainer open) { clearBackAnimateTarget(null /* cleanupTransaction */); if (close == null || open == null) { boolean composeAnimations(@NonNull WindowContainer close, @NonNull WindowContainer open, ActivityRecord openActivity) { if (mComposed || mWaitTransition) { Slog.e(TAG, "Previous animation is running " + this); return false; } clearBackAnimateTarget(); if (close == null || open == null || openActivity == null) { Slog.e(TAG, "reset animation with null target close: " + close + " open: " + open); return false; } initiate(close, open); initiate(close, open, openActivity); if (mSwitchType == UNKNOWN) { return false; } Loading Loading @@ -791,24 +839,10 @@ class BackNavigationController { return false; } boolean setFinishTransaction(SurfaceControl.Transaction finishTransaction) { if (!mComposed) { return false; } mFinishedTransaction = finishTransaction; return true; } void finishPresentAnimations(SurfaceControl.Transaction t) { void finishPresentAnimations() { if (!mComposed) { return; } final SurfaceControl.Transaction pt = t != null ? t : mOpenAdaptor.mTarget.getPendingTransaction(); if (mFinishedTransaction != null) { pt.merge(mFinishedTransaction); mFinishedTransaction = null; } cleanUpWindowlessSurface(); if (mCloseAdaptor != null) { Loading @@ -819,6 +853,9 @@ class BackNavigationController { mOpenAdaptor.mTarget.cancelAnimation(); mOpenAdaptor = null; } if (mOpenActivity != null && mOpenActivity.mLaunchTaskBehind) { restoreLaunchBehind(mOpenActivity); } } private void cleanUpWindowlessSurface() { Loading @@ -845,22 +882,14 @@ class BackNavigationController { } } void clearBackAnimateTarget(SurfaceControl.Transaction cleanupTransaction) { finishPresentAnimations(cleanupTransaction); void clearBackAnimateTarget() { finishPresentAnimations(); mComposed = false; mWaitTransition = false; mOpenTransitionTargetMatch = false; mRequestedStartingSurfaceTaskId = 0; mSwitchType = UNKNOWN; if (mFinishedTransaction != null) { Slog.w(TAG, "Clear back animation, found un-processed finished transaction"); if (cleanupTransaction != null) { cleanupTransaction.merge(mFinishedTransaction); } else { mFinishedTransaction.apply(); } mFinishedTransaction = null; } mOpenActivity = null; } // The close target must in close list Loading @@ -876,9 +905,9 @@ class BackNavigationController { public String toString() { return "AnimationTargets{" + " openTarget= " + mOpenAdaptor.mTarget + (mOpenAdaptor != null ? mOpenAdaptor.mTarget : "null") + " closeTarget= " + mCloseAdaptor.mTarget + (mCloseAdaptor != null ? mCloseAdaptor.mTarget : "null") + " mSwitchType= " + mSwitchType + " mComposed= " Loading Loading @@ -1048,14 +1077,13 @@ class BackNavigationController { * @return If the preview strategy is launch behind, returns the Activity that has * launchBehind set, or null otherwise. */ private ActivityRecord applyPreviewStrategy(WindowContainer open, private void applyPreviewStrategy(WindowContainer open, ActivityRecord visibleOpenActivity) { if (isSupportWindowlessSurface() && mShowWindowlessSurface && !mIsLaunchBehind) { createStartingSurface(getSnapshot(open)); return null; return; } setLaunchBehind(visibleOpenActivity); return visibleOpenActivity; } Runnable build() { Loading @@ -1071,19 +1099,12 @@ class BackNavigationController { return null; } if (!composeAnimations(mCloseTarget, mOpenTarget)) { if (!composeAnimations(mCloseTarget, mOpenTarget, openActivity)) { return null; } final ActivityRecord launchBehindActivity = applyPreviewStrategy(mOpenTarget, openActivity); final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback( launchBehindActivity != null ? triggerBack -> { if (!triggerBack) { restoreLaunchBehind(launchBehindActivity); } } : null, mCloseTarget); final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback(); final RemoteAnimationTarget[] targets = getAnimationTargets(); return () -> { Loading @@ -1096,31 +1117,17 @@ class BackNavigationController { }; } private IBackAnimationFinishedCallback makeAnimationFinishedCallback( Consumer<Boolean> b, WindowContainer closeTarget) { private IBackAnimationFinishedCallback makeAnimationFinishedCallback() { return new IBackAnimationFinishedCallback.Stub() { @Override public void onAnimationFinished(boolean triggerBack) { final SurfaceControl.Transaction finishedTransaction = new SurfaceControl.Transaction(); synchronized (mWindowManagerService.mGlobalLock) { if (b != null) { b.accept(triggerBack); } if (triggerBack) { final SurfaceControl surfaceControl = closeTarget.getSurfaceControl(); if (surfaceControl != null && surfaceControl.isValid()) { // Hide the close target surface when transition start. finishedTransaction.hide(surfaceControl); } } if (!setFinishTransaction(finishedTransaction)) { finishedTransaction.apply(); if (!mComposed) { // animation was canceled return; } if (!triggerBack) { clearBackAnimateTarget( null /* cleanupTransaction */); clearBackAnimateTarget(); } else { mWaitTransition = true; } Loading Loading @@ -1180,6 +1187,14 @@ class BackNavigationController { } void startAnimation() { if (!mBackAnimationInProgress) { // gesture is already finished, do not start animation if (mPendingAnimation != null) { clearBackAnimations(); mPendingAnimation = null; } return; } if (mPendingAnimation != null) { mPendingAnimation.run(); mPendingAnimation = null; Loading @@ -1192,7 +1207,7 @@ class BackNavigationController { ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, " + "triggerBack=%b", backType, triggerBack); mNavigationMonitor.stopMonitor(); mNavigationMonitor.stopMonitorForRemote(); mBackAnimationInProgress = false; mShowWallpaper = false; mPendingAnimationBuilder = null; Loading
services/core/java/com/android/server/wm/Transition.java +2 −6 Original line number Diff line number Diff line Loading @@ -1031,7 +1031,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { mTmpTransaction.apply(); // Handle back animation if it's already started. mController.mAtm.mBackNavigationController.handleDeferredBackAnimation(mTargets); mController.mAtm.mBackNavigationController.onTransitionFinish(mTargets, this); mController.mFinishingTransition = null; } Loading Loading @@ -1136,8 +1136,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { mFlags |= TRANSIT_FLAG_KEYGUARD_LOCKED; } // Check whether the participants were animated from back navigation. final boolean markBackAnimated = mController.mAtm.mBackNavigationController .containsBackAnimationTargets(this); mController.mAtm.mBackNavigationController.onTransactionReady(this); // Resolve the animating targets from the participants. mTargets = calculateTargets(mParticipants, mChanges); final TransitionInfo info = calculateTransitionInfo(mType, mFlags, mTargets, transaction); Loading @@ -1150,9 +1149,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { mTargetDisplays.add(dc); } if (markBackAnimated) { mController.mAtm.mBackNavigationController.clearBackAnimations(mStartTransaction); } if (mOverrideOptions != null) { info.setAnimationOptions(mOverrideOptions); if (mOverrideOptions.getType() == ANIM_OPEN_CROSS_PROFILE_APPS) { Loading
services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java +15 −3 Original line number Diff line number Diff line Loading @@ -89,11 +89,12 @@ public class BackNavigationControllerTests extends WindowTestsBase { @Before public void setUp() throws Exception { mBackNavigationController = Mockito.spy(new BackNavigationController()); final BackNavigationController original = new BackNavigationController(); original.setWindowManager(mWm); mBackNavigationController = Mockito.spy(original); LocalServices.removeServiceForTest(WindowManagerInternal.class); mWindowManagerInternal = mock(WindowManagerInternal.class); LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal); mBackNavigationController.setWindowManager(mWm); mBackAnimationAdapter = mock(BackAnimationAdapter.class); mRootHomeTask = initHomeActivity(); } Loading Loading @@ -129,7 +130,9 @@ public class BackNavigationControllerTests extends WindowTestsBase { // verify if back animation would start. assertTrue("Animation scheduled", backNavigationInfo.isPrepareRemoteAnimation()); // reset drawning status // reset drawing status backNavigationInfo.onBackNavigationFinished(false); mBackNavigationController.clearBackAnimations(); topTask.forAllWindows(w -> { makeWindowVisibleAndDrawn(w); }, true); Loading @@ -138,6 +141,8 @@ public class BackNavigationControllerTests extends WindowTestsBase { assertThat(typeToString(backNavigationInfo.getType())) .isEqualTo(typeToString(BackNavigationInfo.TYPE_CALLBACK)); backNavigationInfo.onBackNavigationFinished(false); mBackNavigationController.clearBackAnimations(); doReturn(true).when(recordA).canShowWhenLocked(); backNavigationInfo = startBackNavigation(); assertThat(typeToString(backNavigationInfo.getType())) Loading Loading @@ -194,6 +199,8 @@ public class BackNavigationControllerTests extends WindowTestsBase { assertTrue("Animation scheduled", backNavigationInfo.isPrepareRemoteAnimation()); // reset drawing status backNavigationInfo.onBackNavigationFinished(false); mBackNavigationController.clearBackAnimations(); testCase.recordFront.forAllWindows(w -> { makeWindowVisibleAndDrawn(w); }, true); Loading @@ -202,6 +209,8 @@ public class BackNavigationControllerTests extends WindowTestsBase { assertThat(typeToString(backNavigationInfo.getType())) .isEqualTo(typeToString(BackNavigationInfo.TYPE_CALLBACK)); backNavigationInfo.onBackNavigationFinished(false); mBackNavigationController.clearBackAnimations(); doReturn(true).when(testCase.recordBack).canShowWhenLocked(); backNavigationInfo = startBackNavigation(); assertThat(typeToString(backNavigationInfo.getType())) Loading Loading @@ -240,6 +249,8 @@ public class BackNavigationControllerTests extends WindowTestsBase { assertThat(typeToString(backNavigationInfo.getType())) .isEqualTo(typeToString(BackNavigationInfo.TYPE_RETURN_TO_HOME)); backNavigationInfo.onBackNavigationFinished(false); mBackNavigationController.clearBackAnimations(); setupKeyguardOccluded(); backNavigationInfo = startBackNavigation(); assertThat(typeToString(backNavigationInfo.getType())) Loading Loading @@ -553,6 +564,7 @@ public class BackNavigationControllerTests extends WindowTestsBase { assertTrue(toHomeBuilder.mIsLaunchBehind); toHomeBuilder.build(); verify(animationHandler, never()).createStartingSurface(any()); animationHandler.clearBackAnimateTarget(); // Back to ACTIVITY and TASK have the same logic, just with different target. final ActivityRecord topActivity = createActivityRecord(task); Loading