Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt +1 −1 Original line number Diff line number Diff line Loading @@ -69,7 +69,7 @@ class DesktopModeKeyGestureHandler( logV("Key gesture MOVE_TO_NEXT_DISPLAY is handled") getGloballyFocusedFreeformTask()?.let { mainExecutor.execute { desktopTasksController.get().moveToNextDisplay(it.taskId) desktopTasksController.get().moveToNextDesktopDisplay(it.taskId) } } } Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +19 −15 Original line number Diff line number Diff line Loading @@ -1236,36 +1236,40 @@ 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. * Queries all currently known display IDs and checks if they match the predicate. The check is * performed in an order such that display IDs greater than the passed task's displayId are * considered before display IDs less than or equal to the passed task's displayID. Within each * of these two groups, the check is performed in ascending order. * * If a display matching the above criteria is found, re-parents the task to that display. No-op * if no such display is found. * If a display ID matches predicate is found, re-parents the task to that display. No-op if no * such display is found. */ fun moveToNextDisplay(taskId: Int) { fun moveToNextDisplay(taskId: Int, predicate: (Int) -> Boolean = { true }) { val task = shellTaskOrganizer.getRunningTaskInfo(taskId) if (task == null) { logW("moveToNextDisplay: taskId=%d not found", taskId) return } logV("moveToNextDisplay: taskId=%d displayId=%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 } } val newDisplayId = rootTaskDisplayAreaOrganizer.displayIds .sortedBy { (it - task.displayId - 1).mod(Int.MAX_VALUE) } .find(predicate) if (newDisplayId == null) { logW("moveToNextDisplay: next display not found") return } // moveToDisplay is no-op if newDisplayId is same with task.displayId. moveToDisplay(task, newDisplayId) } /** Move task to the next display which can host desktop tasks. */ fun moveToNextDesktopDisplay(taskId: Int) = moveToNextDisplay(taskId) { val display = displayController.getDisplay(it) ?: return@moveToNextDisplay false DesktopModeStatus.isDesktopModeSupportedOnDisplay(context, display) } /** * Start an intent through a launch transition for starting tasks whose transition does not get * handled by [handleRequest] Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt +1 −1 Original line number Diff line number Diff line Loading @@ -178,7 +178,7 @@ class DesktopModeKeyGestureHandlerTest : ShellTestCase() { keyGestureEventHandler.handleKeyGestureEvent(event, null) testExecutor.flushAll() verify(desktopTasksController).moveToNextDisplay(task.taskId) verify(desktopTasksController).moveToNextDesktopDisplay(task.taskId) } @Test Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +55 −0 Original line number Diff line number Diff line Loading @@ -371,6 +371,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() whenever(displayLayout.densityDpi()).thenReturn(160) whenever(runBlocking { persistentRepository.readDesktop(any(), any()) }) .thenReturn(Desktop.getDefaultInstance()) whenever(display.type).thenReturn(Display.TYPE_INTERNAL) doReturn(mockToast).`when` { Toast.makeText(any(), anyInt(), anyInt()) } val tda = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0) Loading Loading @@ -3353,6 +3354,60 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() verify(taskbarDesktopTaskListener).onTaskbarCornerRoundingUpdate(anyBoolean()) } private fun moveToNextDesktopDisplay_moveIifDesktopModeSupportedOnDestination( isDesktopModeSupportedOnDestination: Boolean ) { // Set up two display ids whenever(rootTaskDisplayAreaOrganizer.displayIds) .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY)) // Add desk if destination support desktop if (isDesktopModeSupportedOnDestination) { taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = 2) } // 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) // Set up external display content val secondaryDisplay = mock(Display::class.java) whenever(displayController.getDisplay(SECOND_DISPLAY)).thenReturn(secondaryDisplay) doReturn(isDesktopModeSupportedOnDestination).`when` { DesktopModeStatus.isDesktopModeSupportedOnDisplay(any<Context>(), eq(secondaryDisplay)) } // Set up a task on the default display val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY) controller.moveToNextDesktopDisplay(task.taskId) val verificationMode = if (isDesktopModeSupportedOnDestination) { times(1) } else { never() } verify(transitions, verificationMode) .startTransition( eq(TRANSIT_CHANGE), any<WindowContainerTransaction>(), isA(DesktopModeMoveToDisplayTransitionHandler::class.java), ) } @Test fun moveToNextDesktopDisplay_moveIfDesktopModeSupportedOnDestination() { moveToNextDesktopDisplay_moveIifDesktopModeSupportedOnDestination(true) } @Test fun moveToNextDesktopDisplay_dontMoveIfDesktopModeNotSupportedOnDestination() { moveToNextDesktopDisplay_moveIifDesktopModeSupportedOnDestination(false) } @Test fun getTaskWindowingMode() { val fullscreenTask = setUpFullscreenTask() Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt +1 −1 Original line number Diff line number Diff line Loading @@ -69,7 +69,7 @@ class DesktopModeKeyGestureHandler( logV("Key gesture MOVE_TO_NEXT_DISPLAY is handled") getGloballyFocusedFreeformTask()?.let { mainExecutor.execute { desktopTasksController.get().moveToNextDisplay(it.taskId) desktopTasksController.get().moveToNextDesktopDisplay(it.taskId) } } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +19 −15 Original line number Diff line number Diff line Loading @@ -1236,36 +1236,40 @@ 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. * Queries all currently known display IDs and checks if they match the predicate. The check is * performed in an order such that display IDs greater than the passed task's displayId are * considered before display IDs less than or equal to the passed task's displayID. Within each * of these two groups, the check is performed in ascending order. * * If a display matching the above criteria is found, re-parents the task to that display. No-op * if no such display is found. * If a display ID matches predicate is found, re-parents the task to that display. No-op if no * such display is found. */ fun moveToNextDisplay(taskId: Int) { fun moveToNextDisplay(taskId: Int, predicate: (Int) -> Boolean = { true }) { val task = shellTaskOrganizer.getRunningTaskInfo(taskId) if (task == null) { logW("moveToNextDisplay: taskId=%d not found", taskId) return } logV("moveToNextDisplay: taskId=%d displayId=%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 } } val newDisplayId = rootTaskDisplayAreaOrganizer.displayIds .sortedBy { (it - task.displayId - 1).mod(Int.MAX_VALUE) } .find(predicate) if (newDisplayId == null) { logW("moveToNextDisplay: next display not found") return } // moveToDisplay is no-op if newDisplayId is same with task.displayId. moveToDisplay(task, newDisplayId) } /** Move task to the next display which can host desktop tasks. */ fun moveToNextDesktopDisplay(taskId: Int) = moveToNextDisplay(taskId) { val display = displayController.getDisplay(it) ?: return@moveToNextDisplay false DesktopModeStatus.isDesktopModeSupportedOnDisplay(context, display) } /** * Start an intent through a launch transition for starting tasks whose transition does not get * handled by [handleRequest] Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt +1 −1 Original line number Diff line number Diff line Loading @@ -178,7 +178,7 @@ class DesktopModeKeyGestureHandlerTest : ShellTestCase() { keyGestureEventHandler.handleKeyGestureEvent(event, null) testExecutor.flushAll() verify(desktopTasksController).moveToNextDisplay(task.taskId) verify(desktopTasksController).moveToNextDesktopDisplay(task.taskId) } @Test Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +55 −0 Original line number Diff line number Diff line Loading @@ -371,6 +371,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() whenever(displayLayout.densityDpi()).thenReturn(160) whenever(runBlocking { persistentRepository.readDesktop(any(), any()) }) .thenReturn(Desktop.getDefaultInstance()) whenever(display.type).thenReturn(Display.TYPE_INTERNAL) doReturn(mockToast).`when` { Toast.makeText(any(), anyInt(), anyInt()) } val tda = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0) Loading Loading @@ -3353,6 +3354,60 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() verify(taskbarDesktopTaskListener).onTaskbarCornerRoundingUpdate(anyBoolean()) } private fun moveToNextDesktopDisplay_moveIifDesktopModeSupportedOnDestination( isDesktopModeSupportedOnDestination: Boolean ) { // Set up two display ids whenever(rootTaskDisplayAreaOrganizer.displayIds) .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY)) // Add desk if destination support desktop if (isDesktopModeSupportedOnDestination) { taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = 2) } // 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) // Set up external display content val secondaryDisplay = mock(Display::class.java) whenever(displayController.getDisplay(SECOND_DISPLAY)).thenReturn(secondaryDisplay) doReturn(isDesktopModeSupportedOnDestination).`when` { DesktopModeStatus.isDesktopModeSupportedOnDisplay(any<Context>(), eq(secondaryDisplay)) } // Set up a task on the default display val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY) controller.moveToNextDesktopDisplay(task.taskId) val verificationMode = if (isDesktopModeSupportedOnDestination) { times(1) } else { never() } verify(transitions, verificationMode) .startTransition( eq(TRANSIT_CHANGE), any<WindowContainerTransaction>(), isA(DesktopModeMoveToDisplayTransitionHandler::class.java), ) } @Test fun moveToNextDesktopDisplay_moveIfDesktopModeSupportedOnDestination() { moveToNextDesktopDisplay_moveIifDesktopModeSupportedOnDestination(true) } @Test fun moveToNextDesktopDisplay_dontMoveIfDesktopModeNotSupportedOnDestination() { moveToNextDesktopDisplay_moveIifDesktopModeSupportedOnDestination(false) } @Test fun getTaskWindowingMode() { val fullscreenTask = setUpFullscreenTask() Loading