Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java +37 −1 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ class SplitScreenTransitions { DismissTransition mPendingDismiss = null; TransitSession mPendingEnter = null; TransitSession mPendingRecent = null; TransitSession mPendingResize = null; private IBinder mAnimatingTransition = null; Loading Loading @@ -259,6 +260,10 @@ class SplitScreenTransitions { return mPendingEnter != null && mPendingEnter.mTransition == transition; } boolean isPendingRecent(IBinder transition) { return mPendingRecent != null && mPendingRecent.mTransition == transition; } boolean isPendingDismiss(IBinder transition) { return mPendingDismiss != null && mPendingDismiss.mTransition == transition; } Loading @@ -271,6 +276,8 @@ class SplitScreenTransitions { private TransitSession getPendingTransition(IBinder transition) { if (isPendingEnter(transition)) { return mPendingEnter; } else if (isPendingRecent(transition)) { return mPendingRecent; } else if (isPendingDismiss(transition)) { return mPendingDismiss; } else if (isPendingResize(transition)) { Loading Loading @@ -354,10 +361,32 @@ class SplitScreenTransitions { + " deduced Resize split screen"); } void setRecentTransition(@NonNull IBinder transition, @Nullable RemoteTransition remoteTransition, @Nullable TransitionFinishedCallback finishCallback) { mPendingRecent = new TransitSession(transition, null /* consumedCb */, finishCallback); if (remoteTransition != null) { // Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff) mPendingRemoteHandler = new OneShotRemoteHandler( mTransitions.getMainExecutor(), remoteTransition); mPendingRemoteHandler.setTransition(transition); } ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition " + " deduced Enter recent panel"); } void mergeAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t, IBinder mergeTarget, Transitions.TransitionFinishCallback finishCallback) { if (mergeTarget != mAnimatingTransition) return; if (isPendingEnter(transition) && isPendingRecent(mergeTarget)) { // Since there's an entering transition merged, recent transition no longer // need to handle entering split screen after the transition finished. mPendingRecent.setFinishedCallback(null); } if (mActiveRemoteHandler != null) { mActiveRemoteHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback); } else { Loading Loading @@ -394,6 +423,10 @@ class SplitScreenTransitions { } else if (isPendingDismiss(transition)) { mPendingDismiss.onConsumed(aborted); mPendingDismiss = null; } else if (isPendingRecent(transition)) { mPendingRecent.onConsumed(aborted); mPendingRecent = null; mPendingRemoteHandler = null; } else if (isPendingResize(transition)) { mPendingResize.onConsumed(aborted); mPendingResize = null; Loading @@ -407,6 +440,9 @@ class SplitScreenTransitions { if (isPendingEnter(mAnimatingTransition)) { mPendingEnter.onFinished(wct, mFinishTransaction); mPendingEnter = null; } else if (isPendingRecent(mAnimatingTransition)) { mPendingRecent.onFinished(wct, mFinishTransaction); mPendingRecent = null; } else if (isPendingDismiss(mAnimatingTransition)) { mPendingDismiss.onFinished(wct, mFinishTransaction); mPendingDismiss = null; Loading Loading @@ -516,7 +552,7 @@ class SplitScreenTransitions { } /** Calls when the transition finished. */ public interface TransitionFinishedCallback { interface TransitionFinishedCallback { void onFinished(WindowContainerTransaction wct, SurfaceControl.Transaction t); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +39 −35 Original line number Diff line number Diff line Loading @@ -259,6 +259,37 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } }; private final SplitScreenTransitions.TransitionFinishedCallback mRecentTransitionFinishedCallback = new SplitScreenTransitions.TransitionFinishedCallback() { @Override public void onFinished(WindowContainerTransaction finishWct, SurfaceControl.Transaction finishT) { // Check if the recent transition is finished by returning to the current // split, so we // can restore the divider bar. for (int i = 0; i < finishWct.getHierarchyOps().size(); ++i) { final WindowContainerTransaction.HierarchyOp op = finishWct.getHierarchyOps().get(i); final IBinder container = op.getContainer(); if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop() && (mMainStage.containsContainer(container) || mSideStage.containsContainer(container))) { updateSurfaceBounds(mSplitLayout, finishT, false /* applyResizingOffset */); setDividerVisibility(true, finishT); return; } } // Dismiss the split screen if it's not returning to split. prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, finishWct); setSplitsVisible(false); setDividerVisibility(false, finishT); logExit(EXIT_REASON_UNKNOWN); } }; protected StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue, ShellTaskOrganizer taskOrganizer, DisplayController displayController, DisplayImeController displayImeController, Loading Loading @@ -357,11 +388,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, return mMainStage.isActive(); } /** Checks if `transition` is a pending enter-split transition. */ public boolean isPendingEnter(IBinder transition) { return mSplitTransitions.isPendingEnter(transition); } @StageType int getStageOfTask(int taskId) { if (mMainStage.containsTask(taskId)) { Loading Loading @@ -2240,8 +2266,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, final int activityType = triggerTask.getActivityType(); if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) { // starting recents, so don't handle this. return null; // Enter overview panel, so start recent transition. mSplitTransitions.setRecentTransition(transition, request.getRemoteTransition(), mRecentTransitionFinishedCallback); } } } else { Loading Loading @@ -2370,6 +2397,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (mSplitTransitions.isPendingEnter(transition)) { shouldAnimate = startPendingEnterAnimation( transition, info, startTransaction, finishTransaction); } else if (mSplitTransitions.isPendingRecent(transition)) { shouldAnimate = startPendingRecentAnimation(transition, info, startTransaction); } else if (mSplitTransitions.isPendingDismiss(transition)) { shouldAnimate = startPendingDismissAnimation( mSplitTransitions.mPendingDismiss, info, startTransaction, finishTransaction); Loading Loading @@ -2624,35 +2653,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, return true; } /** Call this when starting the open-recents animation while split-screen is active. */ public void onRecentsInSplitAnimationStart(@NonNull SurfaceControl.Transaction t) { private boolean startPendingRecentAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) { setDividerVisibility(false, t); } /** Call this when the recents animation during split-screen finishes. */ public void onRecentsInSplitAnimationFinish(WindowContainerTransaction finishWct, SurfaceControl.Transaction finishT) { // Check if the recent transition is finished by returning to the current // split, so we can restore the divider bar. for (int i = 0; i < finishWct.getHierarchyOps().size(); ++i) { final WindowContainerTransaction.HierarchyOp op = finishWct.getHierarchyOps().get(i); final IBinder container = op.getContainer(); if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop() && (mMainStage.containsContainer(container) || mSideStage.containsContainer(container))) { updateSurfaceBounds(mSplitLayout, finishT, false /* applyResizingOffset */); setDividerVisibility(true, finishT); return; } } // Dismiss the split screen if it's not returning to split. prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, finishWct); setSplitsVisible(false); setDividerVisibility(false, finishT); logExit(EXIT_REASON_UNKNOWN); return true; } private void addDividerBarToTransition(@NonNull TransitionInfo info, Loading libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java +2 −70 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.wm.shell.transition; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; Loading @@ -26,7 +25,6 @@ import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR; import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED; import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP; import static com.android.wm.shell.util.TransitionUtil.isOpeningType; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -70,20 +68,14 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { /** Pip was entered while handling an intent with its own remoteTransition. */ static final int TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE = 3; /** Recents transition while split-screen active. */ static final int TYPE_RECENTS_DURING_SPLIT = 4; /** The default animation for this mixed transition. */ static final int ANIM_TYPE_DEFAULT = 0; /** For ENTER_PIP_FROM_SPLIT, indicates that this is a to-home animation. */ static final int ANIM_TYPE_GOING_HOME = 1; /** For RECENTS_DURING_SPLIT, is set when this turns into a pair->pair task switch. */ static final int ANIM_TYPE_PAIR_TO_PAIR = 1; final int mType; int mAnimType = ANIM_TYPE_DEFAULT; int mAnimType = 0; final IBinder mTransition; Transitions.TransitionHandler mLeftoversHandler = null; Loading Loading @@ -175,25 +167,6 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { mixed.mLeftoversHandler = handler.first; mActiveTransitions.add(mixed); return handler.second; } else if (mSplitHandler.isSplitActive() && isOpeningType(request.getType()) && request.getTriggerTask() != null && request.getTriggerTask().getWindowingMode() == WINDOWING_MODE_FULLSCREEN && (request.getTriggerTask().getActivityType() == ACTIVITY_TYPE_HOME || request.getTriggerTask().getActivityType() == ACTIVITY_TYPE_RECENTS)) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while " + "Split-Screen is active, so treat it as Mixed."); Pair<Transitions.TransitionHandler, WindowContainerTransaction> handler = mPlayer.dispatchRequest(transition, request, this); if (handler == null) { // fall through -- it will probably be picked-up by normal split handler. return null; } final MixedTransition mixed = new MixedTransition( MixedTransition.TYPE_RECENTS_DURING_SPLIT, transition); mixed.mLeftoversHandler = handler.first; mActiveTransitions.add(mixed); return handler.second; } return null; } Loading Loading @@ -243,9 +216,6 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { } else if (mixed.mType == MixedTransition.TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE) { return animateOpenIntentWithRemoteAndPip(mixed, info, startTransaction, finishTransaction, finishCallback); } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_SPLIT) { return animateRecentsDuringSplit(mixed, info, startTransaction, finishTransaction, finishCallback); } else { mActiveTransitions.remove(mixed); throw new IllegalStateException("Starting mixed animation without a known mixed type? " Loading Loading @@ -471,40 +441,12 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { return true; } private boolean animateRecentsDuringSplit(@NonNull final MixedTransition mixed, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { // Split-screen is only interested in the recents transition finishing (and merging), so // just wrap finish and start recents animation directly. Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> { mixed.mInFlightSubAnimations = 0; mActiveTransitions.remove(mixed); // If pair-to-pair switching, the post-recents clean-up isn't needed. if (mixed.mAnimType != MixedTransition.ANIM_TYPE_PAIR_TO_PAIR) { wct = wct != null ? wct : new WindowContainerTransaction(); mSplitHandler.onRecentsInSplitAnimationFinish(wct, finishTransaction); } mSplitHandler.onTransitionAnimationComplete(); finishCallback.onTransitionFinished(wct, wctCB); }; mixed.mInFlightSubAnimations = 1; mSplitHandler.onRecentsInSplitAnimationStart(startTransaction); final boolean handled = mixed.mLeftoversHandler.startAnimation(mixed.mTransition, info, startTransaction, finishTransaction, finishCB); if (!handled) { mActiveTransitions.remove(mixed); } return handled; } @Override public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget, @NonNull Transitions.TransitionFinishCallback finishCallback) { for (int i = 0; i < mActiveTransitions.size(); ++i) { if (mActiveTransitions.get(i).mTransition != mergeTarget) continue; if (mActiveTransitions.get(i) != mergeTarget) continue; MixedTransition mixed = mActiveTransitions.get(i); if (mixed.mInFlightSubAnimations <= 0) { // Already done, so no need to end it. Loading Loading @@ -532,14 +474,6 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback); } } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_SPLIT) { if (mSplitHandler.isPendingEnter(transition)) { // Recents -> enter-split means that we are switching from one pair to // another pair. mixed.mAnimType = MixedTransition.ANIM_TYPE_PAIR_TO_PAIR; } mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback); } else { throw new IllegalStateException("Playing a mixed transition with unknown type? " + mixed.mType); Loading @@ -559,8 +493,6 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { if (mixed == null) return; if (mixed.mType == MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT) { mPipHandler.onTransitionConsumed(transition, aborted, finishT); } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_SPLIT) { mixed.mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT); } } } libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java +12 −49 Original line number Diff line number Diff line Loading @@ -35,7 +35,6 @@ import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_P import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; Loading Loading @@ -250,7 +249,7 @@ public class SplitTransitionTests extends ShellTestCase { @Test @UiThreadTest public void testEnterRecentsAndCommit() { public void testEnterRecents() { enterSplit(); ActivityManager.RunningTaskInfo homeTask = new TestRunningTaskInfoBuilder() Loading @@ -262,60 +261,24 @@ public class SplitTransitionTests extends ShellTestCase { TransitionRequestInfo request = new TransitionRequestInfo(TRANSIT_TO_FRONT, homeTask, null); IBinder transition = mock(IBinder.class); WindowContainerTransaction result = mStageCoordinator.handleRequest(transition, request); // Don't handle recents opening assertNull(result); // make sure we haven't made any local changes yet (need to wait until transition is ready) assertTrue(mStageCoordinator.isSplitScreenVisible()); // simulate the start of recents transition mMainStage.onTaskVanished(mMainChild); mSideStage.onTaskVanished(mSideChild); mStageCoordinator.onRecentsInSplitAnimationStart(mock(SurfaceControl.Transaction.class)); assertTrue(mStageCoordinator.isSplitScreenVisible()); // Make sure it cleans-up if recents doesn't restore WindowContainerTransaction commitWCT = new WindowContainerTransaction(); mStageCoordinator.onRecentsInSplitAnimationFinish(commitWCT, mock(SurfaceControl.Transaction.class)); assertFalse(mStageCoordinator.isSplitScreenVisible()); } @Test @UiThreadTest public void testEnterRecentsAndRestore() { enterSplit(); ActivityManager.RunningTaskInfo homeTask = new TestRunningTaskInfoBuilder() .setWindowingMode(WINDOWING_MODE_FULLSCREEN) .setActivityType(ACTIVITY_TYPE_HOME) .build(); // Create a request to bring home forward TransitionRequestInfo request = new TransitionRequestInfo(TRANSIT_TO_FRONT, homeTask, null); IBinder transition = mock(IBinder.class); WindowContainerTransaction result = mStageCoordinator.handleRequest(transition, request); // Don't handle recents opening assertNull(result); assertTrue(result.isEmpty()); // make sure we haven't made any local changes yet (need to wait until transition is ready) assertTrue(mStageCoordinator.isSplitScreenVisible()); // simulate the start of recents transition // simulate the transition TransitionInfo info = new TransitionInfoBuilder(TRANSIT_TO_FRONT, 0) .addChange(TRANSIT_TO_FRONT, homeTask) .addChange(TRANSIT_TO_BACK, mMainChild) .addChange(TRANSIT_TO_BACK, mSideChild) .build(); mMainStage.onTaskVanished(mMainChild); mSideStage.onTaskVanished(mSideChild); mStageCoordinator.onRecentsInSplitAnimationStart(mock(SurfaceControl.Transaction.class)); assertTrue(mStageCoordinator.isSplitScreenVisible()); // Make sure we remain in split after recents restores. WindowContainerTransaction restoreWCT = new WindowContainerTransaction(); restoreWCT.reorder(mMainChild.token, true /* toTop */); restoreWCT.reorder(mSideChild.token, true /* toTop */); // simulate the restoreWCT being applied: mMainStage.onTaskAppeared(mMainChild, mock(SurfaceControl.class)); mSideStage.onTaskAppeared(mSideChild, mock(SurfaceControl.class)); mStageCoordinator.onRecentsInSplitAnimationFinish(restoreWCT, mock(SurfaceControl.Transaction.class)); mStageCoordinator.startAnimation(transition, info, mock(SurfaceControl.Transaction.class), mock(SurfaceControl.Transaction.class), mock(Transitions.TransitionFinishCallback.class)); assertTrue(mStageCoordinator.isSplitScreenVisible()); } Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java +37 −1 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ class SplitScreenTransitions { DismissTransition mPendingDismiss = null; TransitSession mPendingEnter = null; TransitSession mPendingRecent = null; TransitSession mPendingResize = null; private IBinder mAnimatingTransition = null; Loading Loading @@ -259,6 +260,10 @@ class SplitScreenTransitions { return mPendingEnter != null && mPendingEnter.mTransition == transition; } boolean isPendingRecent(IBinder transition) { return mPendingRecent != null && mPendingRecent.mTransition == transition; } boolean isPendingDismiss(IBinder transition) { return mPendingDismiss != null && mPendingDismiss.mTransition == transition; } Loading @@ -271,6 +276,8 @@ class SplitScreenTransitions { private TransitSession getPendingTransition(IBinder transition) { if (isPendingEnter(transition)) { return mPendingEnter; } else if (isPendingRecent(transition)) { return mPendingRecent; } else if (isPendingDismiss(transition)) { return mPendingDismiss; } else if (isPendingResize(transition)) { Loading Loading @@ -354,10 +361,32 @@ class SplitScreenTransitions { + " deduced Resize split screen"); } void setRecentTransition(@NonNull IBinder transition, @Nullable RemoteTransition remoteTransition, @Nullable TransitionFinishedCallback finishCallback) { mPendingRecent = new TransitSession(transition, null /* consumedCb */, finishCallback); if (remoteTransition != null) { // Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff) mPendingRemoteHandler = new OneShotRemoteHandler( mTransitions.getMainExecutor(), remoteTransition); mPendingRemoteHandler.setTransition(transition); } ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition " + " deduced Enter recent panel"); } void mergeAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t, IBinder mergeTarget, Transitions.TransitionFinishCallback finishCallback) { if (mergeTarget != mAnimatingTransition) return; if (isPendingEnter(transition) && isPendingRecent(mergeTarget)) { // Since there's an entering transition merged, recent transition no longer // need to handle entering split screen after the transition finished. mPendingRecent.setFinishedCallback(null); } if (mActiveRemoteHandler != null) { mActiveRemoteHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback); } else { Loading Loading @@ -394,6 +423,10 @@ class SplitScreenTransitions { } else if (isPendingDismiss(transition)) { mPendingDismiss.onConsumed(aborted); mPendingDismiss = null; } else if (isPendingRecent(transition)) { mPendingRecent.onConsumed(aborted); mPendingRecent = null; mPendingRemoteHandler = null; } else if (isPendingResize(transition)) { mPendingResize.onConsumed(aborted); mPendingResize = null; Loading @@ -407,6 +440,9 @@ class SplitScreenTransitions { if (isPendingEnter(mAnimatingTransition)) { mPendingEnter.onFinished(wct, mFinishTransaction); mPendingEnter = null; } else if (isPendingRecent(mAnimatingTransition)) { mPendingRecent.onFinished(wct, mFinishTransaction); mPendingRecent = null; } else if (isPendingDismiss(mAnimatingTransition)) { mPendingDismiss.onFinished(wct, mFinishTransaction); mPendingDismiss = null; Loading Loading @@ -516,7 +552,7 @@ class SplitScreenTransitions { } /** Calls when the transition finished. */ public interface TransitionFinishedCallback { interface TransitionFinishedCallback { void onFinished(WindowContainerTransaction wct, SurfaceControl.Transaction t); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +39 −35 Original line number Diff line number Diff line Loading @@ -259,6 +259,37 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } }; private final SplitScreenTransitions.TransitionFinishedCallback mRecentTransitionFinishedCallback = new SplitScreenTransitions.TransitionFinishedCallback() { @Override public void onFinished(WindowContainerTransaction finishWct, SurfaceControl.Transaction finishT) { // Check if the recent transition is finished by returning to the current // split, so we // can restore the divider bar. for (int i = 0; i < finishWct.getHierarchyOps().size(); ++i) { final WindowContainerTransaction.HierarchyOp op = finishWct.getHierarchyOps().get(i); final IBinder container = op.getContainer(); if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop() && (mMainStage.containsContainer(container) || mSideStage.containsContainer(container))) { updateSurfaceBounds(mSplitLayout, finishT, false /* applyResizingOffset */); setDividerVisibility(true, finishT); return; } } // Dismiss the split screen if it's not returning to split. prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, finishWct); setSplitsVisible(false); setDividerVisibility(false, finishT); logExit(EXIT_REASON_UNKNOWN); } }; protected StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue, ShellTaskOrganizer taskOrganizer, DisplayController displayController, DisplayImeController displayImeController, Loading Loading @@ -357,11 +388,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, return mMainStage.isActive(); } /** Checks if `transition` is a pending enter-split transition. */ public boolean isPendingEnter(IBinder transition) { return mSplitTransitions.isPendingEnter(transition); } @StageType int getStageOfTask(int taskId) { if (mMainStage.containsTask(taskId)) { Loading Loading @@ -2240,8 +2266,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, final int activityType = triggerTask.getActivityType(); if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) { // starting recents, so don't handle this. return null; // Enter overview panel, so start recent transition. mSplitTransitions.setRecentTransition(transition, request.getRemoteTransition(), mRecentTransitionFinishedCallback); } } } else { Loading Loading @@ -2370,6 +2397,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (mSplitTransitions.isPendingEnter(transition)) { shouldAnimate = startPendingEnterAnimation( transition, info, startTransaction, finishTransaction); } else if (mSplitTransitions.isPendingRecent(transition)) { shouldAnimate = startPendingRecentAnimation(transition, info, startTransaction); } else if (mSplitTransitions.isPendingDismiss(transition)) { shouldAnimate = startPendingDismissAnimation( mSplitTransitions.mPendingDismiss, info, startTransaction, finishTransaction); Loading Loading @@ -2624,35 +2653,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, return true; } /** Call this when starting the open-recents animation while split-screen is active. */ public void onRecentsInSplitAnimationStart(@NonNull SurfaceControl.Transaction t) { private boolean startPendingRecentAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) { setDividerVisibility(false, t); } /** Call this when the recents animation during split-screen finishes. */ public void onRecentsInSplitAnimationFinish(WindowContainerTransaction finishWct, SurfaceControl.Transaction finishT) { // Check if the recent transition is finished by returning to the current // split, so we can restore the divider bar. for (int i = 0; i < finishWct.getHierarchyOps().size(); ++i) { final WindowContainerTransaction.HierarchyOp op = finishWct.getHierarchyOps().get(i); final IBinder container = op.getContainer(); if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop() && (mMainStage.containsContainer(container) || mSideStage.containsContainer(container))) { updateSurfaceBounds(mSplitLayout, finishT, false /* applyResizingOffset */); setDividerVisibility(true, finishT); return; } } // Dismiss the split screen if it's not returning to split. prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, finishWct); setSplitsVisible(false); setDividerVisibility(false, finishT); logExit(EXIT_REASON_UNKNOWN); return true; } private void addDividerBarToTransition(@NonNull TransitionInfo info, Loading
libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java +2 −70 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.wm.shell.transition; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; Loading @@ -26,7 +25,6 @@ import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR; import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED; import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP; import static com.android.wm.shell.util.TransitionUtil.isOpeningType; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -70,20 +68,14 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { /** Pip was entered while handling an intent with its own remoteTransition. */ static final int TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE = 3; /** Recents transition while split-screen active. */ static final int TYPE_RECENTS_DURING_SPLIT = 4; /** The default animation for this mixed transition. */ static final int ANIM_TYPE_DEFAULT = 0; /** For ENTER_PIP_FROM_SPLIT, indicates that this is a to-home animation. */ static final int ANIM_TYPE_GOING_HOME = 1; /** For RECENTS_DURING_SPLIT, is set when this turns into a pair->pair task switch. */ static final int ANIM_TYPE_PAIR_TO_PAIR = 1; final int mType; int mAnimType = ANIM_TYPE_DEFAULT; int mAnimType = 0; final IBinder mTransition; Transitions.TransitionHandler mLeftoversHandler = null; Loading Loading @@ -175,25 +167,6 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { mixed.mLeftoversHandler = handler.first; mActiveTransitions.add(mixed); return handler.second; } else if (mSplitHandler.isSplitActive() && isOpeningType(request.getType()) && request.getTriggerTask() != null && request.getTriggerTask().getWindowingMode() == WINDOWING_MODE_FULLSCREEN && (request.getTriggerTask().getActivityType() == ACTIVITY_TYPE_HOME || request.getTriggerTask().getActivityType() == ACTIVITY_TYPE_RECENTS)) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while " + "Split-Screen is active, so treat it as Mixed."); Pair<Transitions.TransitionHandler, WindowContainerTransaction> handler = mPlayer.dispatchRequest(transition, request, this); if (handler == null) { // fall through -- it will probably be picked-up by normal split handler. return null; } final MixedTransition mixed = new MixedTransition( MixedTransition.TYPE_RECENTS_DURING_SPLIT, transition); mixed.mLeftoversHandler = handler.first; mActiveTransitions.add(mixed); return handler.second; } return null; } Loading Loading @@ -243,9 +216,6 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { } else if (mixed.mType == MixedTransition.TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE) { return animateOpenIntentWithRemoteAndPip(mixed, info, startTransaction, finishTransaction, finishCallback); } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_SPLIT) { return animateRecentsDuringSplit(mixed, info, startTransaction, finishTransaction, finishCallback); } else { mActiveTransitions.remove(mixed); throw new IllegalStateException("Starting mixed animation without a known mixed type? " Loading Loading @@ -471,40 +441,12 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { return true; } private boolean animateRecentsDuringSplit(@NonNull final MixedTransition mixed, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, @NonNull Transitions.TransitionFinishCallback finishCallback) { // Split-screen is only interested in the recents transition finishing (and merging), so // just wrap finish and start recents animation directly. Transitions.TransitionFinishCallback finishCB = (wct, wctCB) -> { mixed.mInFlightSubAnimations = 0; mActiveTransitions.remove(mixed); // If pair-to-pair switching, the post-recents clean-up isn't needed. if (mixed.mAnimType != MixedTransition.ANIM_TYPE_PAIR_TO_PAIR) { wct = wct != null ? wct : new WindowContainerTransaction(); mSplitHandler.onRecentsInSplitAnimationFinish(wct, finishTransaction); } mSplitHandler.onTransitionAnimationComplete(); finishCallback.onTransitionFinished(wct, wctCB); }; mixed.mInFlightSubAnimations = 1; mSplitHandler.onRecentsInSplitAnimationStart(startTransaction); final boolean handled = mixed.mLeftoversHandler.startAnimation(mixed.mTransition, info, startTransaction, finishTransaction, finishCB); if (!handled) { mActiveTransitions.remove(mixed); } return handled; } @Override public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget, @NonNull Transitions.TransitionFinishCallback finishCallback) { for (int i = 0; i < mActiveTransitions.size(); ++i) { if (mActiveTransitions.get(i).mTransition != mergeTarget) continue; if (mActiveTransitions.get(i) != mergeTarget) continue; MixedTransition mixed = mActiveTransitions.get(i); if (mixed.mInFlightSubAnimations <= 0) { // Already done, so no need to end it. Loading Loading @@ -532,14 +474,6 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback); } } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_SPLIT) { if (mSplitHandler.isPendingEnter(transition)) { // Recents -> enter-split means that we are switching from one pair to // another pair. mixed.mAnimType = MixedTransition.ANIM_TYPE_PAIR_TO_PAIR; } mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback); } else { throw new IllegalStateException("Playing a mixed transition with unknown type? " + mixed.mType); Loading @@ -559,8 +493,6 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { if (mixed == null) return; if (mixed.mType == MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT) { mPipHandler.onTransitionConsumed(transition, aborted, finishT); } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_SPLIT) { mixed.mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT); } } }
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java +12 −49 Original line number Diff line number Diff line Loading @@ -35,7 +35,6 @@ import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_P import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; Loading Loading @@ -250,7 +249,7 @@ public class SplitTransitionTests extends ShellTestCase { @Test @UiThreadTest public void testEnterRecentsAndCommit() { public void testEnterRecents() { enterSplit(); ActivityManager.RunningTaskInfo homeTask = new TestRunningTaskInfoBuilder() Loading @@ -262,60 +261,24 @@ public class SplitTransitionTests extends ShellTestCase { TransitionRequestInfo request = new TransitionRequestInfo(TRANSIT_TO_FRONT, homeTask, null); IBinder transition = mock(IBinder.class); WindowContainerTransaction result = mStageCoordinator.handleRequest(transition, request); // Don't handle recents opening assertNull(result); // make sure we haven't made any local changes yet (need to wait until transition is ready) assertTrue(mStageCoordinator.isSplitScreenVisible()); // simulate the start of recents transition mMainStage.onTaskVanished(mMainChild); mSideStage.onTaskVanished(mSideChild); mStageCoordinator.onRecentsInSplitAnimationStart(mock(SurfaceControl.Transaction.class)); assertTrue(mStageCoordinator.isSplitScreenVisible()); // Make sure it cleans-up if recents doesn't restore WindowContainerTransaction commitWCT = new WindowContainerTransaction(); mStageCoordinator.onRecentsInSplitAnimationFinish(commitWCT, mock(SurfaceControl.Transaction.class)); assertFalse(mStageCoordinator.isSplitScreenVisible()); } @Test @UiThreadTest public void testEnterRecentsAndRestore() { enterSplit(); ActivityManager.RunningTaskInfo homeTask = new TestRunningTaskInfoBuilder() .setWindowingMode(WINDOWING_MODE_FULLSCREEN) .setActivityType(ACTIVITY_TYPE_HOME) .build(); // Create a request to bring home forward TransitionRequestInfo request = new TransitionRequestInfo(TRANSIT_TO_FRONT, homeTask, null); IBinder transition = mock(IBinder.class); WindowContainerTransaction result = mStageCoordinator.handleRequest(transition, request); // Don't handle recents opening assertNull(result); assertTrue(result.isEmpty()); // make sure we haven't made any local changes yet (need to wait until transition is ready) assertTrue(mStageCoordinator.isSplitScreenVisible()); // simulate the start of recents transition // simulate the transition TransitionInfo info = new TransitionInfoBuilder(TRANSIT_TO_FRONT, 0) .addChange(TRANSIT_TO_FRONT, homeTask) .addChange(TRANSIT_TO_BACK, mMainChild) .addChange(TRANSIT_TO_BACK, mSideChild) .build(); mMainStage.onTaskVanished(mMainChild); mSideStage.onTaskVanished(mSideChild); mStageCoordinator.onRecentsInSplitAnimationStart(mock(SurfaceControl.Transaction.class)); assertTrue(mStageCoordinator.isSplitScreenVisible()); // Make sure we remain in split after recents restores. WindowContainerTransaction restoreWCT = new WindowContainerTransaction(); restoreWCT.reorder(mMainChild.token, true /* toTop */); restoreWCT.reorder(mSideChild.token, true /* toTop */); // simulate the restoreWCT being applied: mMainStage.onTaskAppeared(mMainChild, mock(SurfaceControl.class)); mSideStage.onTaskAppeared(mSideChild, mock(SurfaceControl.class)); mStageCoordinator.onRecentsInSplitAnimationFinish(restoreWCT, mock(SurfaceControl.Transaction.class)); mStageCoordinator.startAnimation(transition, info, mock(SurfaceControl.Transaction.class), mock(SurfaceControl.Transaction.class), mock(Transitions.TransitionFinishCallback.class)); assertTrue(mStageCoordinator.isSplitScreenVisible()); } Loading