diff options
4 files changed, 90 insertions, 155 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java index 5f1d30f09066..e1c089550c2d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java @@ -67,6 +67,7 @@ class SplitScreenTransitions { DismissTransition mPendingDismiss = null; TransitSession mPendingEnter = null; + TransitSession mPendingRecent = null; TransitSession mPendingResize = null; private IBinder mAnimatingTransition = null; @@ -256,6 +257,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; } @@ -268,6 +273,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)) { @@ -351,10 +358,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 { @@ -391,6 +420,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; @@ -404,6 +437,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; @@ -513,7 +549,7 @@ class SplitScreenTransitions { } /** Calls when the transition finished. */ - public interface TransitionFinishedCallback { + interface TransitionFinishedCallback { void onFinished(WindowContainerTransaction wct, SurfaceControl.Transaction t); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 9d1a7ea14900..a5546e554422 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -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, @@ -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)) { @@ -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 { @@ -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); @@ -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, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java index 095b8da7cfa7..75112b62c1c6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java @@ -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; @@ -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; @@ -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; @@ -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; } @@ -241,9 +214,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? " @@ -469,40 +439,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. @@ -530,14 +472,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); @@ -557,8 +491,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); } } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java index 2edec7db828f..3901dabcaec8 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java @@ -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; @@ -250,7 +249,7 @@ public class SplitTransitionTests extends ShellTestCase { @Test @UiThreadTest - public void testEnterRecentsAndCommit() { + public void testEnterRecents() { enterSplit(); ActivityManager.RunningTaskInfo homeTask = new TestRunningTaskInfoBuilder() @@ -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()); } |