Loading libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java +33 −16 Original line number Diff line number Diff line Loading @@ -203,9 +203,6 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, // only care about latest one. mAnimApp = appThread; for (int i = 0; i < mStateListeners.size(); i++) { mStateListeners.get(i).onTransitionStateChanged(TRANSITION_STATE_REQUESTED); } // TODO(b/366021931): Formalize this later final boolean isSyntheticRequest = options.getBoolean( "is_synthetic_recents_transition", /* defaultValue= */ false); Loading @@ -215,6 +212,25 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, if (displayId == INVALID_DISPLAY) { displayId = DEFAULT_DISPLAY; } // If there is an existing recents transition for the given display then we're not handling // the gesture correctly from the calling end. Canceling and starting a new transition is // possible but the legacy recents animation runner interface is not suited to handle events // from overlapping controllers. We just opt to log the error and preferably prevent this on // the calling end. final RecentsController lastController = findControllerForDisplay(displayId); if (lastController != null) { lastController.cancel(lastController.isSyntheticTransition() ? "existing_running_synthetic_transition" : "existing_running_transition"); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "startRecentsTransition: Skipping due to existing transition"); return null; } for (int i = 0; i < mStateListeners.size(); i++) { mStateListeners.get(i).onTransitionStateChanged(TRANSITION_STATE_REQUESTED); } if (isSyntheticRequest) { transition = startSyntheticRecentsTransition(listener, displayId); } else { Loading @@ -231,16 +247,9 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, int displayId) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsTransitionHandler.startRecentsTransition(synthetic)"); final RecentsController lastController = getLastController(); if (lastController != null) { lastController.cancel(lastController.isSyntheticTransition() ? "existing_running_synthetic_transition" : "existing_running_transition"); return null; } // Create a new synthetic transition and start it immediately final RecentsController controller = new RecentsController(listener); final RecentsController controller = new RecentsController(listener, displayId); controller.startSyntheticTransition(displayId); mControllers.add(controller); return SYNTHETIC_TRANSITION; Loading Loading @@ -280,7 +289,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, setTransitionForMixer.accept(transition); } final RecentsController controller = new RecentsController(listener); final RecentsController controller = new RecentsController(listener, displayId); if (transition != null) { controller.setTransition(transition); mControllers.add(controller); Loading @@ -303,11 +312,17 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, } /** * Returns if there is currently a pending or active recents transition. * Finds an existing controller for the provided {@param displayId}. */ @Nullable private RecentsController getLastController() { return !mControllers.isEmpty() ? mControllers.getLast() : null; private RecentsController findControllerForDisplay(int displayId) { for (int i = 0; i < mControllers.size(); i++) { final RecentsController controller = mControllers.get(i); if (controller.mDisplayId == displayId) { return controller; } } return null; } /** Loading Loading @@ -392,6 +407,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, class RecentsController extends IRecentsAnimationController.Stub { private final int mInstanceId; private final int mDisplayId; private IRecentsAnimationRunner mListener; private IBinder.DeathRecipient mDeathHandler; Loading Loading @@ -461,8 +477,9 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, // This stores the pending finish transaction to merge with the actual finish transaction private SurfaceControl.Transaction mPendingFinishTransaction; RecentsController(IRecentsAnimationRunner listener) { RecentsController(IRecentsAnimationRunner listener, int displayId) { mInstanceId = System.identityHashCode(this); mDisplayId = displayId; mListener = listener; mDeathHandler = () -> { mExecutor.execute(() -> { Loading libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java +6 −6 Original line number Diff line number Diff line Loading @@ -525,22 +525,22 @@ public class DefaultMixedHandler implements MixedTransitionHandler, } private void setRecentsTransitionDuringSplit(IBinder transition, int displayId) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while " + "Split-Screen is foreground, so treat it as Mixed."); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while Split-Screen is foreground, so treat it as Mixed."); mActiveTransitions.add(createRecentsMixedTransition( MixedTransition.TYPE_RECENTS_DURING_SPLIT, transition, displayId)); } private void setRecentsTransitionDuringKeyguard(IBinder transition, int displayId) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while " + "keyguard is visible, so treat it as Mixed."); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while keyguard is visible, so treat it as Mixed."); mActiveTransitions.add(createRecentsMixedTransition( MixedTransition.TYPE_RECENTS_DURING_KEYGUARD, transition, displayId)); } private void setRecentsTransitionDuringDesktop(IBinder transition, int displayId) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while " + "desktop mode is active, so treat it as Mixed."); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while desktop mode is active, so treat it as Mixed."); mActiveTransitions.add(createRecentsMixedTransition( MixedTransition.TYPE_RECENTS_DURING_DESKTOP, transition, displayId)); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java +9 −8 Original line number Diff line number Diff line Loading @@ -89,8 +89,8 @@ class RecentsMixedTransition extends DefaultMixedHandler.MixedTransition { @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition for Recents during" + " Desktop #%d", info.getDebugId()); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition for Recents during Desktop #%d", info.getDebugId()); if (mInfo == null) { mInfo = info; Loading Loading @@ -124,12 +124,13 @@ class RecentsMixedTransition extends DefaultMixedHandler.MixedTransition { @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Mixed transition for Recents during" + " Keyguard #%d", info.getDebugId()); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Mixed transition for Recents during Keyguard #%d", info.getDebugId()); if (!mKeyguardHandler.isKeyguardShowing() || mKeyguardHandler.isKeyguardAnimating()) { ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Cancel mixed transition because " + "keyguard state was changed #%d", info.getDebugId()); ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Cancel mixed transition because keyguard state was changed #%d", info.getDebugId()); return false; } if (mInfo == null) { Loading @@ -145,8 +146,8 @@ class RecentsMixedTransition extends DefaultMixedHandler.MixedTransition { @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Mixed transition for Recents during" + " split screen #%d", info.getDebugId()); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Mixed transition for Recents during split screen #%d", info.getDebugId()); for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java +19 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; Loading Loading @@ -215,6 +216,24 @@ public class RecentsTransitionHandlerTest extends ShellTestCase { } } @Test public void testStartRecentsTransitionTwiceCancelsFirst() throws Exception { final IRecentsAnimationRunner runner1 = mock(IRecentsAnimationRunner.class); final IRecentsAnimationRunner runner2 = mock(IRecentsAnimationRunner.class); final IBinder transition1 = startRecentsTransition(/* synthetic= */ true, runner1); verify(runner1).onAnimationStart(any(), any(), any(), any(), any(), any()); // Start a new recents transition and verify the original runner is canceled and we don't // start the new transition either final IBinder transition2 = startRecentsTransition(/* synthetic= */ true, runner2); assertNull(transition2); verify(runner1).onAnimationCanceled(any(), any()); verify(runner2, never()).onAnimationStart(any(), any(), any(), any(), any(), any()); assertNull(mRecentsTransitionHandler.findController(transition1)); } @Test public void testStartSyntheticRecentsTransition_callsOnAnimationStartAndFinishCallback() throws Exception { final IRecentsAnimationRunner runner = mock(IRecentsAnimationRunner.class); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java +33 −16 Original line number Diff line number Diff line Loading @@ -203,9 +203,6 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, // only care about latest one. mAnimApp = appThread; for (int i = 0; i < mStateListeners.size(); i++) { mStateListeners.get(i).onTransitionStateChanged(TRANSITION_STATE_REQUESTED); } // TODO(b/366021931): Formalize this later final boolean isSyntheticRequest = options.getBoolean( "is_synthetic_recents_transition", /* defaultValue= */ false); Loading @@ -215,6 +212,25 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, if (displayId == INVALID_DISPLAY) { displayId = DEFAULT_DISPLAY; } // If there is an existing recents transition for the given display then we're not handling // the gesture correctly from the calling end. Canceling and starting a new transition is // possible but the legacy recents animation runner interface is not suited to handle events // from overlapping controllers. We just opt to log the error and preferably prevent this on // the calling end. final RecentsController lastController = findControllerForDisplay(displayId); if (lastController != null) { lastController.cancel(lastController.isSyntheticTransition() ? "existing_running_synthetic_transition" : "existing_running_transition"); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "startRecentsTransition: Skipping due to existing transition"); return null; } for (int i = 0; i < mStateListeners.size(); i++) { mStateListeners.get(i).onTransitionStateChanged(TRANSITION_STATE_REQUESTED); } if (isSyntheticRequest) { transition = startSyntheticRecentsTransition(listener, displayId); } else { Loading @@ -231,16 +247,9 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, int displayId) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsTransitionHandler.startRecentsTransition(synthetic)"); final RecentsController lastController = getLastController(); if (lastController != null) { lastController.cancel(lastController.isSyntheticTransition() ? "existing_running_synthetic_transition" : "existing_running_transition"); return null; } // Create a new synthetic transition and start it immediately final RecentsController controller = new RecentsController(listener); final RecentsController controller = new RecentsController(listener, displayId); controller.startSyntheticTransition(displayId); mControllers.add(controller); return SYNTHETIC_TRANSITION; Loading Loading @@ -280,7 +289,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, setTransitionForMixer.accept(transition); } final RecentsController controller = new RecentsController(listener); final RecentsController controller = new RecentsController(listener, displayId); if (transition != null) { controller.setTransition(transition); mControllers.add(controller); Loading @@ -303,11 +312,17 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, } /** * Returns if there is currently a pending or active recents transition. * Finds an existing controller for the provided {@param displayId}. */ @Nullable private RecentsController getLastController() { return !mControllers.isEmpty() ? mControllers.getLast() : null; private RecentsController findControllerForDisplay(int displayId) { for (int i = 0; i < mControllers.size(); i++) { final RecentsController controller = mControllers.get(i); if (controller.mDisplayId == displayId) { return controller; } } return null; } /** Loading Loading @@ -392,6 +407,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, class RecentsController extends IRecentsAnimationController.Stub { private final int mInstanceId; private final int mDisplayId; private IRecentsAnimationRunner mListener; private IBinder.DeathRecipient mDeathHandler; Loading Loading @@ -461,8 +477,9 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, // This stores the pending finish transaction to merge with the actual finish transaction private SurfaceControl.Transaction mPendingFinishTransaction; RecentsController(IRecentsAnimationRunner listener) { RecentsController(IRecentsAnimationRunner listener, int displayId) { mInstanceId = System.identityHashCode(this); mDisplayId = displayId; mListener = listener; mDeathHandler = () -> { mExecutor.execute(() -> { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java +6 −6 Original line number Diff line number Diff line Loading @@ -525,22 +525,22 @@ public class DefaultMixedHandler implements MixedTransitionHandler, } private void setRecentsTransitionDuringSplit(IBinder transition, int displayId) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while " + "Split-Screen is foreground, so treat it as Mixed."); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while Split-Screen is foreground, so treat it as Mixed."); mActiveTransitions.add(createRecentsMixedTransition( MixedTransition.TYPE_RECENTS_DURING_SPLIT, transition, displayId)); } private void setRecentsTransitionDuringKeyguard(IBinder transition, int displayId) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while " + "keyguard is visible, so treat it as Mixed."); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while keyguard is visible, so treat it as Mixed."); mActiveTransitions.add(createRecentsMixedTransition( MixedTransition.TYPE_RECENTS_DURING_KEYGUARD, transition, displayId)); } private void setRecentsTransitionDuringDesktop(IBinder transition, int displayId) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while " + "desktop mode is active, so treat it as Mixed."); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while desktop mode is active, so treat it as Mixed."); mActiveTransitions.add(createRecentsMixedTransition( MixedTransition.TYPE_RECENTS_DURING_DESKTOP, transition, displayId)); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java +9 −8 Original line number Diff line number Diff line Loading @@ -89,8 +89,8 @@ class RecentsMixedTransition extends DefaultMixedHandler.MixedTransition { @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition for Recents during" + " Desktop #%d", info.getDebugId()); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition for Recents during Desktop #%d", info.getDebugId()); if (mInfo == null) { mInfo = info; Loading Loading @@ -124,12 +124,13 @@ class RecentsMixedTransition extends DefaultMixedHandler.MixedTransition { @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Mixed transition for Recents during" + " Keyguard #%d", info.getDebugId()); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Mixed transition for Recents during Keyguard #%d", info.getDebugId()); if (!mKeyguardHandler.isKeyguardShowing() || mKeyguardHandler.isKeyguardAnimating()) { ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Cancel mixed transition because " + "keyguard state was changed #%d", info.getDebugId()); ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Cancel mixed transition because keyguard state was changed #%d", info.getDebugId()); return false; } if (mInfo == null) { Loading @@ -145,8 +146,8 @@ class RecentsMixedTransition extends DefaultMixedHandler.MixedTransition { @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Mixed transition for Recents during" + " split screen #%d", info.getDebugId()); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Mixed transition for Recents during split screen #%d", info.getDebugId()); for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java +19 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; Loading Loading @@ -215,6 +216,24 @@ public class RecentsTransitionHandlerTest extends ShellTestCase { } } @Test public void testStartRecentsTransitionTwiceCancelsFirst() throws Exception { final IRecentsAnimationRunner runner1 = mock(IRecentsAnimationRunner.class); final IRecentsAnimationRunner runner2 = mock(IRecentsAnimationRunner.class); final IBinder transition1 = startRecentsTransition(/* synthetic= */ true, runner1); verify(runner1).onAnimationStart(any(), any(), any(), any(), any(), any()); // Start a new recents transition and verify the original runner is canceled and we don't // start the new transition either final IBinder transition2 = startRecentsTransition(/* synthetic= */ true, runner2); assertNull(transition2); verify(runner1).onAnimationCanceled(any(), any()); verify(runner2, never()).onAnimationStart(any(), any(), any(), any(), any(), any()); assertNull(mRecentsTransitionHandler.findController(transition1)); } @Test public void testStartSyntheticRecentsTransition_callsOnAnimationStartAndFinishCallback() throws Exception { final IRecentsAnimationRunner runner = mock(IRecentsAnimationRunner.class); Loading