From c8a54dab1d2eec0dc404822cfe654b49db23f423 Mon Sep 17 00:00:00 2001 From: Jerry Chang Date: Fri, 3 Sep 2021 16:47:51 +0800 Subject: [PATCH] Update split screen interface to indicate dismissing to top task Bug: 198310766 Test: atest WMShellUnitTests Change-Id: I78824605575825a41eb2e507123705bfca6482a2 --- .../shell/draganddrop/DragAndDropPolicy.java | 4 +- .../wm/shell/splitscreen/ISplitScreen.aidl | 5 ++- .../splitscreen/SplitScreenController.java | 10 ++--- .../shell/splitscreen/StageCoordinator.java | 29 ++++++++++++--- .../shell/splitscreen/StageTaskListener.java | 7 ++++ .../splitscreen/StageCoordinatorTests.java | 37 +++++++++++++++++++ 6 files changed, 77 insertions(+), 15 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java index 102b90ff5d3db..fbf04d6f3fff0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java @@ -304,7 +304,7 @@ public class DragAndDropPolicy { * Exits splitscreen, with an associated exit trigger from the SplitscreenUIChanged proto * for logging. */ - void exitSplitScreen(int exitTrigger); + void exitSplitScreen(int toTopTaskId, int exitTrigger); } /** @@ -357,7 +357,7 @@ public class DragAndDropPolicy { } @Override - public void exitSplitScreen(int exitTrigger) { + public void exitSplitScreen(int toTopTaskId, int exitTrigger) { throw new UnsupportedOperationException("exitSplitScreen not implemented by starter"); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl index 6ec514bd83313..ce707c5a1a364 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl @@ -52,9 +52,10 @@ interface ISplitScreen { oneway void removeFromSideStage(int taskId) = 4; /** - * Removes the split-screen stages. + * Removes the split-screen stages and leaving indicated task to top. Passing INVALID_TASK_ID + * to indicate leaving no top task after leaving split-screen. */ - oneway void exitSplitScreen() = 5; + oneway void exitSplitScreen(int toTopTaskId) = 5; /** * @param exitSplitScreenOnHide if to exit split-screen if both stages are not visible. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index e74e116a2157a..66428d543efa7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -173,8 +173,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT); } - public void exitSplitScreen(int exitReason) { - mStageCoordinator.exitSplitScreen(exitReason); + public void exitSplitScreen(int toTopTaskId, int exitReason) { + mStageCoordinator.exitSplitScreen(toTopTaskId, exitReason); } public void onKeyguardOccludedChanged(boolean occluded) { @@ -499,11 +499,11 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, } @Override - public void exitSplitScreen() { + public void exitSplitScreen(int toTopTaskId) { executeRemoteCallWithTaskPermission(mController, "exitSplitScreen", (controller) -> { - controller.exitSplitScreen( - FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME); + controller.exitSplitScreen(toTopTaskId, + FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__UNKNOWN_EXIT); }); } 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 9e6edd2a53817..1d0840691f554 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 @@ -472,16 +472,32 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } - void exitSplitScreen(int exitReason) { - exitSplitScreen(null /* childrenToTop */, exitReason); - } - void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) { mExitSplitScreenOnHide = exitSplitScreenOnHide; } + void exitSplitScreen(int toTopTaskId, int exitReason) { + StageTaskListener childrenToTop = null; + if (mMainStage.containsTask(toTopTaskId)) { + childrenToTop = mMainStage; + } else if (mSideStage.containsTask(toTopTaskId)) { + childrenToTop = mSideStage; + } + + final WindowContainerTransaction wct = new WindowContainerTransaction(); + if (childrenToTop != null) { + childrenToTop.reorderChild(toTopTaskId, true /* onTop */, wct); + } + applyExitSplitScreen(childrenToTop, wct, exitReason); + } + private void exitSplitScreen(StageTaskListener childrenToTop, int exitReason) { final WindowContainerTransaction wct = new WindowContainerTransaction(); + applyExitSplitScreen(childrenToTop, wct, exitReason); + } + + private void applyExitSplitScreen(StageTaskListener childrenToTop, + WindowContainerTransaction wct, int exitReason) { mSideStage.removeAllTasks(wct, childrenToTop == mSideStage); mMainStage.deactivate(wct, childrenToTop == mMainStage); mTaskOrganizer.applyTransaction(wct); @@ -627,7 +643,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, // Don't dismiss staged split when both stages are not visible due to sleeping display, // like the cases keyguard showing or screen off. || (!mMainStage.mRootTaskInfo.isSleeping && !mSideStage.mRootTaskInfo.isSleeping)) { - exitSplitScreen(SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME); + exitSplitScreen(null /* childrenToTop */, + SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME); } } else if (mKeyguardOccluded) { // At least one of the stages is visible while keyguard occluded. Dismiss split because @@ -1249,7 +1266,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, @Override public void onNoLongerSupportMultiWindow() { if (mMainStage.isActive()) { - StageCoordinator.this.exitSplitScreen( + StageCoordinator.this.exitSplitScreen(null /* childrenToTop */, SPLITSCREEN_UICHANGED__EXIT_REASON__APP_DOES_NOT_SUPPORT_MULTIWINDOW); } } 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 3512a0c3727bf..1fc7e6352f6b3 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 @@ -214,6 +214,13 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { wct.setBounds(mRootTaskInfo.token, bounds); } + void reorderChild(int taskId, boolean onTop, WindowContainerTransaction wct) { + if (!containsTask(taskId)) { + return; + } + wct.reorder(mChildrenTaskInfo.get(taskId).token, onTop /* onTop */); + } + void setVisibility(boolean visible, WindowContainerTransaction wct) { wct.reorder(mRootTaskInfo.token, visible /* onTop */); } 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 6cce0ab26df75..d930d4ca5dd48 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 @@ -16,14 +16,17 @@ package com.android.wm.shell.splitscreen; +import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.view.Display.DEFAULT_DISPLAY; +import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME; import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.graphics.Rect; @@ -94,4 +97,38 @@ public class StageCoordinatorTests extends ShellTestCase { verify(mSideStage).removeTask( eq(task.taskId), any(), any(WindowContainerTransaction.class)); } + + @Test + public void testExitSplitScreen() { + mStageCoordinator.exitSplitScreen(INVALID_TASK_ID, + SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME); + verify(mSideStage).removeAllTasks(any(WindowContainerTransaction.class), eq(false)); + verify(mMainStage).deactivate(any(WindowContainerTransaction.class), eq(false)); + } + + @Test + public void testExitSplitScreenToMainStage() { + final int testTaskId = 12345; + when(mMainStage.containsTask(eq(testTaskId))).thenReturn(true); + when(mSideStage.containsTask(eq(testTaskId))).thenReturn(false); + mStageCoordinator.exitSplitScreen(testTaskId, + SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME); + verify(mMainStage).reorderChild(eq(testTaskId), eq(true), + any(WindowContainerTransaction.class)); + verify(mSideStage).removeAllTasks(any(WindowContainerTransaction.class), eq(false)); + verify(mMainStage).deactivate(any(WindowContainerTransaction.class), eq(true)); + } + + @Test + public void testExitSplitScreenToSideStage() { + final int testTaskId = 12345; + when(mMainStage.containsTask(eq(testTaskId))).thenReturn(false); + when(mSideStage.containsTask(eq(testTaskId))).thenReturn(true); + mStageCoordinator.exitSplitScreen(testTaskId, + SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME); + verify(mSideStage).reorderChild(eq(testTaskId), eq(true), + any(WindowContainerTransaction.class)); + verify(mSideStage).removeAllTasks(any(WindowContainerTransaction.class), eq(true)); + verify(mMainStage).deactivate(any(WindowContainerTransaction.class), eq(false)); + } }