diff options
author | 2023-05-01 23:39:27 +0000 | |
---|---|---|
committer | 2023-05-01 23:39:27 +0000 | |
commit | 3ad0e9fc5f3d06a41d3647d173fe20afcbe62c00 (patch) | |
tree | fc7c04a8c615682e7eefe053a75fd3a82a760578 | |
parent | 5e5bee7e05718130f88c2f98009dfa6dcab8410c (diff) | |
parent | 44fdf07f6573d3cbefd52091352ce33f28fda26f (diff) |
Merge "Add support to move task to another display" into udc-dev
6 files changed, 141 insertions, 0 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java index 544d75739547..410ae78dba1b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java @@ -181,6 +181,17 @@ public class RootTaskDisplayAreaOrganizer extends DisplayAreaOrganizer { } /** + * Returns the list of display ids that are tracked by a {@link DisplayAreaInfo} + */ + public int[] getDisplayIds() { + int[] displayIds = new int[mDisplayAreasInfo.size()]; + for (int i = 0; i < mDisplayAreasInfo.size(); i++) { + displayIds[i] = mDisplayAreasInfo.keyAt(i); + } + return displayIds; + } + + /** * Returns the {@link DisplayAreaInfo} of the {@link DisplayAreaInfo#displayId}. */ @Nullable diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java index d1760ed75547..76ca68bbfa75 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java @@ -49,6 +49,12 @@ public class DesktopModeStatus { "persist.wm.debug.desktop_veiled_resizing", true); /** + * Flag to indicate is moving task to another display is enabled. + */ + public static final boolean IS_DISPLAY_CHANGE_ENABLED = SystemProperties.getBoolean( + "persist.wm.debug.desktop_change_display", false); + + /** * Return {@code true} if desktop mode support is enabled */ public static boolean isProto1Enabled() { 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 c814fe575e81..73a0e362a744 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 @@ -235,6 +235,69 @@ class DesktopTasksController( } /** + * Move task to the next display. + * + * Queries all current known display ids and sorts them in ascending order. Then iterates + * through the list and looks for the display id that is larger than the display id for + * the passed in task. If a display with a higher id is not found, iterates through the list and + * finds the first display id that is not the display id for the passed in task. + * + * If a display matching the above criteria is found, re-parents the task to that display. + * No-op if no such display is found. + */ + fun moveToNextDisplay(taskId: Int) { + val task = shellTaskOrganizer.getRunningTaskInfo(taskId) + if (task == null) { + ProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToNextDisplay: taskId=%d not found", taskId) + return + } + ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToNextDisplay: taskId=%d taskDisplayId=%d", + taskId, task.displayId) + + val displayIds = rootTaskDisplayAreaOrganizer.displayIds.sorted() + // Get the first display id that is higher than current task display id + var newDisplayId = displayIds.firstOrNull { displayId -> displayId > task.displayId } + if (newDisplayId == null) { + // No display with a higher id, get the first display id that is not the task display id + newDisplayId = displayIds.firstOrNull { displayId -> displayId < task.displayId } + } + if (newDisplayId == null) { + ProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToNextDisplay: next display not found") + return + } + moveToDisplay(task, newDisplayId) + } + + /** + * Move [task] to display with [displayId]. + * + * No-op if task is already on that display per [RunningTaskInfo.displayId]. + */ + private fun moveToDisplay(task: RunningTaskInfo, displayId: Int) { + ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToDisplay: taskId=%d displayId=%d", + task.taskId, displayId) + + if (task.displayId == displayId) { + ProtoLog.d(WM_SHELL_DESKTOP_MODE, "moveToDisplay: task already on display") + return + } + + val displayAreaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId) + if (displayAreaInfo == null) { + ProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveToDisplay: display not found") + return + } + + val wct = WindowContainerTransaction() + wct.reparent(task.token, displayAreaInfo.token, true /* onTop */) + if (Transitions.ENABLE_SHELL_TRANSITIONS) { + transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */) + } else { + shellTaskOrganizer.applyTransaction(wct) + } + } + + /** * Get windowing move for a given `taskId` * * @return [WindowingMode] for the task or [WINDOWING_MODE_UNDEFINED] if task is not found diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index 4cda5715ac1f..12edc3548642 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -326,6 +326,13 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { decoration.closeHandleMenu(); } else if (id == R.id.collapse_menu_button) { decoration.closeHandleMenu(); + } else if (id == R.id.select_button) { + if (DesktopModeStatus.IS_DISPLAY_CHANGE_ENABLED) { + // TODO(b/278084491): dev option to enable display switching + // remove when select is implemented + mDesktopTasksController.ifPresent(c -> c.moveToNextDisplay(mTaskId)); + decoration.closeHandleMenu(); + } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java index ed3cca078084..ac4a597c15d1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java @@ -187,6 +187,8 @@ class HandleMenu { final View moreActionsPillView = mMoreActionsPill.mWindowViewHost.getView(); final Button closeBtn = moreActionsPillView.findViewById(R.id.close_button); closeBtn.setOnClickListener(mOnClickListener); + final Button selectBtn = moreActionsPillView.findViewById(R.id.select_button); + selectBtn.setOnClickListener(mOnClickListener); } /** 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 f506969f51df..1335ebf105a6 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 @@ -31,6 +31,7 @@ import android.view.WindowManager.TRANSIT_CHANGE import android.view.WindowManager.TRANSIT_NONE import android.view.WindowManager.TRANSIT_OPEN import android.view.WindowManager.TRANSIT_TO_FRONT +import android.window.DisplayAreaInfo import android.window.TransitionRequestInfo import android.window.WindowContainerTransaction import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER @@ -344,6 +345,57 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test + fun moveToNextDisplay_noOtherDisplays() { + whenever(rootTaskDisplayAreaOrganizer.displayIds).thenReturn(intArrayOf(DEFAULT_DISPLAY)) + val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY) + controller.moveToNextDisplay(task.taskId) + verifyWCTNotExecuted() + } + + @Test + fun moveToNextDisplay_moveFromFirstToSecondDisplay() { + // Set up two display ids + whenever(rootTaskDisplayAreaOrganizer.displayIds) + .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY)) + // Create a mock for the target display area: second display + val secondDisplayArea = DisplayAreaInfo(MockToken().token(), SECOND_DISPLAY, 0) + whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(SECOND_DISPLAY)) + .thenReturn(secondDisplayArea) + + val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY) + controller.moveToNextDisplay(task.taskId) + with(getLatestWct(expectTransition = TRANSIT_CHANGE)) { + assertThat(hierarchyOps).hasSize(1) + assertThat(hierarchyOps[0].container).isEqualTo(task.token.asBinder()) + assertThat(hierarchyOps[0].isReparent).isTrue() + assertThat(hierarchyOps[0].newParent).isEqualTo(secondDisplayArea.token.asBinder()) + assertThat(hierarchyOps[0].toTop).isTrue() + } + } + + @Test + fun moveToNextDisplay_moveFromSecondToFirstDisplay() { + // Set up two display ids + whenever(rootTaskDisplayAreaOrganizer.displayIds) + .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY)) + // Create a mock for the target display area: default display + val defaultDisplayArea = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0) + whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)) + .thenReturn(defaultDisplayArea) + + val task = setUpFreeformTask(displayId = SECOND_DISPLAY) + controller.moveToNextDisplay(task.taskId) + + with(getLatestWct(expectTransition = TRANSIT_CHANGE)) { + assertThat(hierarchyOps).hasSize(1) + assertThat(hierarchyOps[0].container).isEqualTo(task.token.asBinder()) + assertThat(hierarchyOps[0].isReparent).isTrue() + assertThat(hierarchyOps[0].newParent).isEqualTo(defaultDisplayArea.token.asBinder()) + assertThat(hierarchyOps[0].toTop).isTrue() + } + } + + @Test fun getTaskWindowingMode() { val fullscreenTask = setUpFullscreenTask() val freeformTask = setUpFreeformTask() |