diff options
8 files changed, 134 insertions, 0 deletions
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index ed43b8190f93..d463b62e62a3 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -376,4 +376,10 @@ oneway interface IStatusBar * @param packageName of the session for which the output switcher is shown. */ void showMediaOutputSwitcher(String packageName); + + /** Enters desktop mode. + * + * @param displayId the id of the current display. + */ + void enterDesktop(int displayId); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java index e732a0354806..8305fa6b0fbf 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java @@ -47,4 +47,8 @@ public interface DesktopMode { default void addDesktopGestureExclusionRegionListener(Consumer<Region> listener, Executor callbackExecutor) { } + + /** Called when requested to go to desktop mode from the current focused app. */ + void enterDesktop(int displayId); + } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 11304ec587e7..6de5d741f436 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -21,6 +21,7 @@ import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN +import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.app.WindowConfiguration.WindowingMode import android.content.Context @@ -240,6 +241,43 @@ class DesktopTasksController( return desktopModeTaskRepository.getVisibleTaskCount(displayId) } + /** Enter desktop by using the focused task in given `displayId` */ + fun enterDesktop(displayId: Int) { + val allFocusedTasks = + shellTaskOrganizer.getRunningTasks(displayId).filter { taskInfo -> + taskInfo.isFocused && + (taskInfo.windowingMode == WINDOWING_MODE_FULLSCREEN || + taskInfo.windowingMode == WINDOWING_MODE_MULTI_WINDOW) && + taskInfo.activityType != ACTIVITY_TYPE_HOME + } + if (allFocusedTasks.isNotEmpty()) { + when (allFocusedTasks.size) { + 2 -> { + // Split-screen case where there are two focused tasks, then we find the child + // task to move to desktop. + val splitFocusedTask = findChildFocusedTask(allFocusedTasks) + moveToDesktop(splitFocusedTask) + } + 1 -> { + // Fullscreen case where we move the current focused task. + moveToDesktop(allFocusedTasks[0].taskId) + } + else -> { + KtProtoLog.v( + WM_SHELL_DESKTOP_MODE, + "DesktopTasksController: Cannot enter desktop expected less " + + "than 3 focused tasks but found " + allFocusedTasks.size + ) + } + } + } + } + + private fun findChildFocusedTask(allFocusedTasks: List<RunningTaskInfo>): RunningTaskInfo { + if (allFocusedTasks[0].taskId == allFocusedTasks[1].parentTaskId) return allFocusedTasks[1] + return allFocusedTasks[0] + } + /** Move a task with given `taskId` to desktop */ fun moveToDesktop( taskId: Int, @@ -1012,6 +1050,12 @@ class DesktopTasksController( this@DesktopTasksController.setTaskRegionListener(listener, callbackExecutor) } } + + override fun enterDesktop(displayId: Int) { + mainExecutor.execute { + this@DesktopTasksController.enterDesktop(displayId) + } + } } /** The interface for calls from outside the host process. */ diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index 63618f4d0673..cb64c52444ac 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -734,6 +734,46 @@ class DesktopTasksControllerTest : ShellTestCase() { shellExecutor.flushAll() verify(launchAdjacentController).launchAdjacentEnabled = true } + @Test + fun enterDesktop_fullscreenTaskIsMovedToDesktop() { + val task1 = setUpFullscreenTask() + val task2 = setUpFullscreenTask() + val task3 = setUpFullscreenTask() + + task1.isFocused = true + task2.isFocused = false + task3.isFocused = false + + controller.enterDesktop(DEFAULT_DISPLAY) + + val wct = getLatestMoveToDesktopWct() + assertThat(wct.changes[task1.token.asBinder()]?.windowingMode) + .isEqualTo(WINDOWING_MODE_FREEFORM) + } + + @Test + fun enterDesktop_splitScreenTaskIsMovedToDesktop() { + val task1 = setUpSplitScreenTask() + val task2 = setUpFullscreenTask() + val task3 = setUpFullscreenTask() + val task4 = setUpSplitScreenTask() + + task1.isFocused = true + task2.isFocused = false + task3.isFocused = false + task4.isFocused = true + + task4.parentTaskId = task1.taskId + + controller.enterDesktop(DEFAULT_DISPLAY) + + val wct = getLatestMoveToDesktopWct() + assertThat(wct.changes[task4.token.asBinder()]?.windowingMode) + .isEqualTo(WINDOWING_MODE_FREEFORM) + verify(splitScreenController).prepareExitSplitScreen(any(), anyInt(), + eq(SplitScreenController.EXIT_REASON_DESKTOP_MODE) + ) + } private fun setUpFreeformTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo { val task = createFreeformTask(displayId) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index ffb11dd3cf92..ca19f71bd391 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -177,6 +177,7 @@ public class CommandQueue extends IStatusBar.Stub implements private static final int MSG_CONFIRM_IMMERSIVE_PROMPT = 77 << MSG_SHIFT; private static final int MSG_IMMERSIVE_CHANGED = 78 << MSG_SHIFT; private static final int MSG_SET_QS_TILES = 79 << MSG_SHIFT; + private static final int MSG_ENTER_DESKTOP = 80 << MSG_SHIFT; public static final int FLAG_EXCLUDE_NONE = 0; public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; public static final int FLAG_EXCLUDE_RECENTS_PANEL = 1 << 1; @@ -520,6 +521,11 @@ public class CommandQueue extends IStatusBar.Stub implements * @see IStatusBar#immersiveModeChanged */ default void immersiveModeChanged(int rootDisplayAreaId, boolean isImmersiveMode) {} + + /** + * @see IStatusBar#enterDesktop(int) + */ + default void enterDesktop(int displayId) {} } @VisibleForTesting @@ -1420,6 +1426,13 @@ public class CommandQueue extends IStatusBar.Stub implements mHandler.obtainMessage(MSG_GO_TO_FULLSCREEN_FROM_SPLIT).sendToTarget(); } + @Override + public void enterDesktop(int displayId) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = displayId; + mHandler.obtainMessage(MSG_ENTER_DESKTOP, args).sendToTarget(); + } + private final class H extends Handler { private H(Looper l) { super(l); @@ -1914,6 +1927,13 @@ public class CommandQueue extends IStatusBar.Stub implements mCallbacks.get(i).immersiveModeChanged(rootDisplayAreaId, isImmersiveMode); } break; + case MSG_ENTER_DESKTOP: + args = (SomeArgs) msg.obj; + int displayId = args.argi1; + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).enterDesktop(displayId); + } + break; } } } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java index e8325065c219..15e0965c16fe 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java @@ -356,6 +356,12 @@ public final class WMShell implements // TODO(b/278084491): update sysui state for changes on other displays } }, mSysUiMainExecutor); + mCommandQueue.addCallback(new CommandQueue.Callbacks() { + @Override + public void enterDesktop(int displayId) { + desktopMode.enterDesktop(displayId); + } + }); } @VisibleForTesting diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index a4c6959f8ad5..3c6baa873eca 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -255,4 +255,9 @@ public interface StatusBarManagerInternal { * @param tile the ComponentName of the {@link android.service.quicksettings.TileService} */ void removeQsTile(ComponentName tile); + + /** + * Called when requested to enter desktop from an app. + */ + void enterDesktop(int displayId); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index fd316eaf9b96..14c38bde6621 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -830,6 +830,15 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } @Override + public void enterDesktop(int displayId) { + IStatusBar bar = mBar; + if (bar != null) { + try { + bar.enterDesktop(displayId); + } catch (RemoteException ex) { } + } + } + @Override public void showMediaOutputSwitcher(String packageName) { IStatusBar bar = mBar; if (bar != null) { |