diff options
| author | 2023-03-14 04:03:06 +0000 | |
|---|---|---|
| committer | 2023-03-14 04:03:06 +0000 | |
| commit | 7241e58c175e097553dc369c6a1ab2fb8546887b (patch) | |
| tree | 93a35998e2f6d1b0546e289ad23b4e7fb24d2990 | |
| parent | 5279472cdab121345af9d237fb1ad9d90149daa7 (diff) | |
| parent | 6358dddd6ad57ae4cdd4d87d4cfdd2d027395e08 (diff) | |
Merge "Move recents-during-split handling to MixedHandler" into udc-dev
4 files changed, 155 insertions, 90 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 e09c3c9e4d3f..4b5ad1d05c4a 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 @@ -68,7 +68,6 @@ class SplitScreenTransitions { DismissTransition mPendingDismiss = null; TransitSession mPendingEnter = null; - TransitSession mPendingRecent = null; TransitSession mPendingResize = null; private IBinder mAnimatingTransition = null; @@ -260,10 +259,6 @@ 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; } @@ -276,8 +271,6 @@ 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)) { @@ -361,32 +354,10 @@ 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 { @@ -423,10 +394,6 @@ 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; @@ -440,9 +407,6 @@ 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; @@ -552,7 +516,7 @@ class SplitScreenTransitions { } /** Calls when the transition finished. */ - interface TransitionFinishedCallback { + public 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 a5546e554422..9d1a7ea14900 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,37 +259,6 @@ 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, @@ -388,6 +357,11 @@ 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)) { @@ -2266,9 +2240,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, final int activityType = triggerTask.getActivityType(); if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) { - // Enter overview panel, so start recent transition. - mSplitTransitions.setRecentTransition(transition, request.getRemoteTransition(), - mRecentTransitionFinishedCallback); + // starting recents, so don't handle this. + return null; } } } else { @@ -2397,8 +2370,6 @@ 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); @@ -2653,10 +2624,35 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, return true; } - private boolean startPendingRecentAnimation(@NonNull IBinder transition, - @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) { + /** Call this when starting the open-recents animation while split-screen is active. */ + public void onRecentsInSplitAnimationStart(@NonNull SurfaceControl.Transaction t) { setDividerVisibility(false, t); - return true; + } + + /** 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); } 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 2e864483bf1d..b9f6a012efaf 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,6 +18,7 @@ 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; @@ -25,6 +26,7 @@ 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; @@ -68,14 +70,20 @@ 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 = 0; + int mAnimType = ANIM_TYPE_DEFAULT; final IBinder mTransition; Transitions.TransitionHandler mLeftoversHandler = null; @@ -167,6 +175,25 @@ 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; } @@ -216,6 +243,9 @@ 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? " @@ -441,12 +471,40 @@ 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) != mergeTarget) continue; + if (mActiveTransitions.get(i).mTransition != mergeTarget) continue; MixedTransition mixed = mActiveTransitions.get(i); if (mixed.mInFlightSubAnimations <= 0) { // Already done, so no need to end it. @@ -474,6 +532,14 @@ 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); @@ -493,6 +559,8 @@ 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 3901dabcaec8..2edec7db828f 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,6 +35,7 @@ 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; @@ -249,7 +250,7 @@ public class SplitTransitionTests extends ShellTestCase { @Test @UiThreadTest - public void testEnterRecents() { + public void testEnterRecentsAndCommit() { enterSplit(); ActivityManager.RunningTaskInfo homeTask = new TestRunningTaskInfoBuilder() @@ -261,24 +262,60 @@ 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); - - assertTrue(result.isEmpty()); + // 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 transition - TransitionInfo info = new TransitionInfoBuilder(TRANSIT_TO_FRONT, 0) - .addChange(TRANSIT_TO_FRONT, homeTask) - .addChange(TRANSIT_TO_BACK, mMainChild) - .addChange(TRANSIT_TO_BACK, mSideChild) + // 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); + + // 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.startAnimation(transition, info, - mock(SurfaceControl.Transaction.class), - mock(SurfaceControl.Transaction.class), - mock(Transitions.TransitionFinishCallback.class)); + 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)); assertTrue(mStageCoordinator.isSplitScreenVisible()); } |