diff options
7 files changed, 94 insertions, 15 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java index 753dfa7396f8..a9ccdf6a156f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java @@ -293,6 +293,9 @@ public class SplitDecorManager extends WindowlessWindowManager { } if (mResizingIconView == null) { + if (mRunningAnimationCount == 0 && animFinishedCallback != null) { + animFinishedCallback.accept(false); + } return; } @@ -311,6 +314,9 @@ public class SplitDecorManager extends WindowlessWindowManager { releaseDecor(finishT); finishT.apply(); finishT.close(); + if (mRunningAnimationCount == 0 && animFinishedCallback != null) { + animFinishedCallback.accept(true); + } } }); return; 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 14ea86a8c0e9..d2b0e2800dc9 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 @@ -87,6 +87,14 @@ class SplitScreenTransitions { mStageCoordinator = stageCoordinator; } + private void initTransition(@NonNull IBinder transition, + @NonNull SurfaceControl.Transaction finishTransaction, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + mAnimatingTransition = transition; + mFinishTransaction = finishTransaction; + mFinishCallback = finishCallback; + } + /** Play animation for enter transition or dismiss transition. */ void playAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @@ -94,9 +102,7 @@ class SplitScreenTransitions { @NonNull Transitions.TransitionFinishCallback finishCallback, @NonNull WindowContainerToken mainRoot, @NonNull WindowContainerToken sideRoot, @NonNull WindowContainerToken topRoot) { - mFinishCallback = finishCallback; - mAnimatingTransition = transition; - mFinishTransaction = finishTransaction; + initTransition(transition, finishTransaction, finishCallback); final TransitSession pendingTransition = getPendingTransition(transition); if (pendingTransition != null) { @@ -220,6 +226,45 @@ class SplitScreenTransitions { onFinish(null /* wct */, null /* wctCB */); } + /** Play animation for drag divider dismiss transition. */ + void playDragDismissAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction, + @NonNull Transitions.TransitionFinishCallback finishCallback, + @NonNull WindowContainerToken toTopRoot, @NonNull SplitDecorManager toTopDecor, + @NonNull WindowContainerToken topRoot) { + initTransition(transition, finishTransaction, finishCallback); + + for (int i = info.getChanges().size() - 1; i >= 0; --i) { + final TransitionInfo.Change change = info.getChanges().get(i); + final SurfaceControl leash = change.getLeash(); + + if (toTopRoot.equals(change.getContainer())) { + startTransaction.setAlpha(leash, 1.f); + startTransaction.show(leash); + + ValueAnimator va = new ValueAnimator(); + mAnimations.add(va); + + toTopDecor.onResized(startTransaction, animated -> { + mAnimations.remove(va); + if (animated) { + mTransitions.getMainExecutor().execute(() -> { + onFinish(null /* wct */, null /* wctCB */); + }); + } + }); + } else if (topRoot.equals(change.getContainer())) { + // Ensure it on top of all changes in transition. + startTransaction.setLayer(leash, Integer.MAX_VALUE); + startTransaction.setAlpha(leash, 1.f); + startTransaction.show(leash); + } + } + startTransaction.apply(); + onFinish(null /* wct */, null /* wctCB */); + } + /** Play animation for resize transition. */ void playResizeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @@ -227,9 +272,7 @@ class SplitScreenTransitions { @NonNull Transitions.TransitionFinishCallback finishCallback, @NonNull WindowContainerToken mainRoot, @NonNull WindowContainerToken sideRoot, @NonNull SplitDecorManager mainDecor, @NonNull SplitDecorManager sideDecor) { - mFinishCallback = finishCallback; - mAnimatingTransition = transition; - mFinishTransaction = finishTransaction; + initTransition(transition, finishTransaction, finishCallback); for (int i = info.getChanges().size() - 1; i >= 0; --i) { final TransitionInfo.Change change = info.getChanges().get(i); 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 bf20567834e0..e0ffffffa727 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 @@ -1328,8 +1328,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mIsExiting = true; childrenToTop.resetBounds(wct); wct.reorder(childrenToTop.mRootTaskInfo.token, true); - wct.setSmallestScreenWidthDp(childrenToTop.mRootTaskInfo.token, - SMALLEST_SCREEN_WIDTH_DP_UNDEFINED); } wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token, false /* reparentLeafTaskIfRelaunch */); @@ -1517,6 +1515,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, void finishEnterSplitScreen(SurfaceControl.Transaction t) { mSplitLayout.update(t); + mMainStage.getSplitDecorManager().inflate(mContext, mMainStage.mRootLeash, + getMainStageBounds()); + mSideStage.getSplitDecorManager().inflate(mContext, mSideStage.mRootLeash, + getSideStageBounds()); setDividerVisibility(true, t); // Ensure divider surface are re-parented back into the hierarchy at the end of the // transition. See Transition#buildFinishTransaction for more detail. @@ -1989,13 +1991,15 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, final boolean mainStageToTop = bottomOrRight ? mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT : mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT; + final StageTaskListener toTopStage = mainStageToTop ? mMainStage : mSideStage; if (!ENABLE_SHELL_TRANSITIONS) { - exitSplitScreen(mainStageToTop ? mMainStage : mSideStage, reason); + exitSplitScreen(toTopStage, reason); return; } final int dismissTop = mainStageToTop ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE; final WindowContainerTransaction wct = new WindowContainerTransaction(); + toTopStage.resetBounds(wct); prepareExitSplitScreen(dismissTop, wct); if (mRootTaskInfo != null) { wct.setDoNotPip(mRootTaskInfo.token); @@ -2531,8 +2535,17 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, shouldAnimate = startPendingEnterAnimation( mSplitTransitions.mPendingEnter, info, startTransaction, finishTransaction); } else if (mSplitTransitions.isPendingDismiss(transition)) { + final SplitScreenTransitions.DismissSession dismiss = mSplitTransitions.mPendingDismiss; shouldAnimate = startPendingDismissAnimation( - mSplitTransitions.mPendingDismiss, info, startTransaction, finishTransaction); + dismiss, info, startTransaction, finishTransaction); + if (shouldAnimate && dismiss.mReason == EXIT_REASON_DRAG_DIVIDER) { + final StageTaskListener toTopStage = + dismiss.mDismissTop == STAGE_TYPE_MAIN ? mMainStage : mSideStage; + mSplitTransitions.playDragDismissAnimation(transition, info, startTransaction, + finishTransaction, finishCallback, toTopStage.mRootTaskInfo.token, + toTopStage.getSplitDecorManager(), mRootTaskInfo.token); + return true; + } } else if (mSplitTransitions.isPendingResize(transition)) { mSplitTransitions.playResizeAnimation(transition, info, startTransaction, finishTransaction, finishCallback, mMainStage.mRootTaskInfo.token, @@ -2787,6 +2800,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSplitTransitions.mPendingDismiss = null; return false; } + dismissTransition.setFinishedCallback((callbackWct, callbackT) -> { + mMainStage.getSplitDecorManager().release(callbackT); + mSideStage.getSplitDecorManager().release(callbackT); + }); addDividerBarToTransition(info, false /* show */); return true; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index e2e9270cd6cc..da7d18641a97 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -19,6 +19,7 @@ package com.android.wm.shell.splitscreen; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; import static android.view.RemoteAnimationTarget.MODE_OPENING; import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES; @@ -201,7 +202,7 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { if (mRootTaskInfo.taskId == taskInfo.taskId) { // Inflates split decor view only when the root task is visible. - if (mRootTaskInfo.isVisible != taskInfo.isVisible) { + if (!ENABLE_SHELL_TRANSITIONS && mRootTaskInfo.isVisible != taskInfo.isVisible) { if (taskInfo.isVisible) { mSplitDecorManager.inflate(mContext, mRootLeash, taskInfo.configuration.windowConfiguration.getBounds()); @@ -385,6 +386,7 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { void resetBounds(WindowContainerTransaction wct) { wct.setBounds(mRootTaskInfo.token, null); wct.setAppBounds(mRootTaskInfo.token, null); + wct.setSmallestScreenWidthDp(mRootTaskInfo.token, SMALLEST_SCREEN_WIDTH_DP_UNDEFINED); } void onSplitScreenListenerRegistered(SplitScreen.SplitScreenListener listener, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java index ae69b3ddd042..4e446c684d86 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java @@ -44,11 +44,15 @@ public class SplitTestUtils { static SplitLayout createMockSplitLayout() { final Rect dividerBounds = new Rect(48, 0, 52, 100); + final Rect bounds1 = new Rect(0, 0, 40, 100); + final Rect bounds2 = new Rect(60, 0, 100, 100); final SurfaceControl leash = createMockSurface(); SplitLayout out = mock(SplitLayout.class); doReturn(dividerBounds).when(out).getDividerBounds(); doReturn(dividerBounds).when(out).getRefDividerBounds(); doReturn(leash).when(out).getDividerLeash(); + doReturn(bounds1).when(out).getBounds1(); + doReturn(bounds2).when(out).getBounds2(); return out; } 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 80384531e9ae..60c0e5535568 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 @@ -42,6 +42,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import android.annotation.NonNull; import android.app.ActivityManager; @@ -72,6 +73,7 @@ import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.TransactionPool; +import com.android.wm.shell.common.split.SplitDecorManager; import com.android.wm.shell.common.split.SplitLayout; import com.android.wm.shell.transition.Transitions; @@ -117,13 +119,13 @@ public class SplitTransitionTests extends ShellTestCase { doReturn(mockExecutor).when(mTransitions).getAnimExecutor(); doReturn(mock(SurfaceControl.Transaction.class)).when(mTransactionPool).acquire(); mSplitLayout = SplitTestUtils.createMockSplitLayout(); - mMainStage = new MainStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock( + mMainStage = spy(new MainStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock( StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession, - mIconProvider); + mIconProvider)); mMainStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface()); - mSideStage = new SideStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock( + mSideStage = spy(new SideStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock( StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession, - mIconProvider); + mIconProvider)); mSideStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface()); mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue, mTaskOrganizer, mMainStage, mSideStage, mDisplayController, @@ -137,6 +139,8 @@ public class SplitTransitionTests extends ShellTestCase { .setParentTaskId(mMainStage.mRootTaskInfo.taskId).build(); mSideChild = new TestRunningTaskInfoBuilder() .setParentTaskId(mSideStage.mRootTaskInfo.taskId).build(); + doReturn(mock(SplitDecorManager.class)).when(mMainStage).getSplitDecorManager(); + doReturn(mock(SplitDecorManager.class)).when(mSideStage).getSplitDecorManager(); } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java index 6621ab8ce0d8..66b6c62f1dd6 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java @@ -68,6 +68,7 @@ import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.TransactionPool; +import com.android.wm.shell.common.split.SplitDecorManager; import com.android.wm.shell.common.split.SplitLayout; import com.android.wm.shell.splitscreen.SplitScreen.SplitScreenListener; import com.android.wm.shell.sysui.ShellController; @@ -145,6 +146,8 @@ public class StageCoordinatorTests extends ShellTestCase { mSideStage.mRootTaskInfo = new TestRunningTaskInfoBuilder().build(); mMainStage.mRootTaskInfo = new TestRunningTaskInfoBuilder().build(); + doReturn(mock(SplitDecorManager.class)).when(mMainStage).getSplitDecorManager(); + doReturn(mock(SplitDecorManager.class)).when(mSideStage).getSplitDecorManager(); } @Test |