Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +73 −43 Original line number Diff line number Diff line Loading @@ -2031,6 +2031,14 @@ class DesktopTasksController( /** Move task to the next display which can host desktop tasks. */ fun moveToNextDesktopDisplay(taskId: Int, enterReason: EnterReason) = moveToNextDisplay(taskId, enterReason) { displayId -> if ( DesktopExperienceFlags.MOVE_TO_NEXT_DISPLAY_SHORTCUT_WITH_PROJECTED_MODE.isTrue && desktopState.isProjectedMode() && displayId == DEFAULT_DISPLAY ) { logD("moveToNextDesktopDisplay: Moving to default display during projected mode.") return@moveToNextDisplay true } if (!desktopState.isDesktopModeSupportedOnDisplay(displayId)) { logD( "moveToNextDesktopDisplay: Skip displayId=$displayId as desktop mode " + Loading Loading @@ -2137,6 +2145,28 @@ class DesktopTasksController( return } val activationRunnable: RunOnTransitStart? val deactivationRunnable: RunOnTransitStart? if ( DesktopExperienceFlags.MOVE_TO_NEXT_DISPLAY_SHORTCUT_WITH_PROJECTED_MODE.isTrue && desktopState.isProjectedMode() && displayId == DEFAULT_DISPLAY ) { logV("moveToDisplay: moving task to default display during projected mode") activationRunnable = null deactivationRunnable = addMoveToFullscreenChanges( wct, task, willExitDesktop( triggerTaskId = task.taskId, displayId = task.displayId, forceExitDesktop = false, ), displayId, ) } else { val destinationDeskId = taskRepository.getDefaultDeskId(displayId) if (destinationDeskId == null) { logW("moveToDisplay: desk not found for display: $displayId") Loading @@ -2161,9 +2191,8 @@ class DesktopTasksController( wct.reparent(task.token, displayAreaInfo.token, /* onTop= */ true) } val activationRunnable = activationRunnable = addDeskActivationChanges(destinationDeskId, wct, task, enterReason = enterReason) val sourceDisplayId = task.displayId val sourceDeskId = taskRepository.getDeskIdForTask(task.taskId) val shouldExitDesktopIfNeeded = Loading @@ -2171,7 +2200,7 @@ class DesktopTasksController( DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue val isLastTask = sourceDeskId?.let { taskRepository.isOnlyTaskInDesk(task.taskId, it) } ?: false val deactivationRunnable = deactivationRunnable = if (shouldExitDesktopIfNeeded) { performDesktopExitCleanupIfNeeded( taskId = task.taskId, Loading @@ -2185,6 +2214,7 @@ class DesktopTasksController( } else { null } } if (DesktopExperienceFlags.ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS.isTrue) { // Bring the destination display to top with includingParents=true, so that the // destination display gains the display focus, which makes the top task in the display Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +36 −0 Original line number Diff line number Diff line Loading @@ -101,6 +101,7 @@ import com.android.window.flags.Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP import com.android.window.flags.Flags.FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT import com.android.window.flags.Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND import com.android.window.flags.Flags.FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY import com.android.window.flags.Flags.FLAG_MOVE_TO_NEXT_DISPLAY_SHORTCUT_WITH_PROJECTED_MODE import com.android.wm.shell.MockToken import com.android.wm.shell.R import com.android.wm.shell.RootTaskDisplayAreaOrganizer Loading Loading @@ -4165,6 +4166,41 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() verify(taskbarDesktopTaskListener).onTaskbarCornerRoundingUpdate(anyBoolean()) } @Test @EnableFlags( FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT, FLAG_MOVE_TO_NEXT_DISPLAY_SHORTCUT_WITH_PROJECTED_MODE, ) fun moveToNextDesktopDisplay_projectedMode_movesToFullscreenOnDefaultDisplay() { // Setup state where a desktop task is running on a secondary display while the device is in // projected mode desktopState.isProjected = true whenever(rootTaskDisplayAreaOrganizer.displayIds) .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY)) val defaultDisplayArea = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0) whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)) .thenReturn(defaultDisplayArea) taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) val task = setUpFreeformTask(displayId = SECOND_DISPLAY) controller.moveToNextDesktopDisplay(task.taskId, EnterReason.UNKNOWN_ENTER) val wct = getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) // Verify that the task is reparented to the default display and set to fullscreen mode val hierarchyOp = wct.hierarchyOps.find { it.container == task.token.asBinder() && it.isReparent } assertNotNull(hierarchyOp) assertThat(hierarchyOp.newParent).isEqualTo(defaultDisplayArea.token.asBinder()) val configChange = wct.changes[task.token.asBinder()] assertNotNull(configChange) assertThat(configChange.windowingMode).isEqualTo(WINDOWING_MODE_FULLSCREEN) } private fun moveToNextDesktopDisplay_moveIifDesktopModeSupportedOnDestination( isDesktopModeSupportedOnDestination: Boolean ) { Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +73 −43 Original line number Diff line number Diff line Loading @@ -2031,6 +2031,14 @@ class DesktopTasksController( /** Move task to the next display which can host desktop tasks. */ fun moveToNextDesktopDisplay(taskId: Int, enterReason: EnterReason) = moveToNextDisplay(taskId, enterReason) { displayId -> if ( DesktopExperienceFlags.MOVE_TO_NEXT_DISPLAY_SHORTCUT_WITH_PROJECTED_MODE.isTrue && desktopState.isProjectedMode() && displayId == DEFAULT_DISPLAY ) { logD("moveToNextDesktopDisplay: Moving to default display during projected mode.") return@moveToNextDisplay true } if (!desktopState.isDesktopModeSupportedOnDisplay(displayId)) { logD( "moveToNextDesktopDisplay: Skip displayId=$displayId as desktop mode " + Loading Loading @@ -2137,6 +2145,28 @@ class DesktopTasksController( return } val activationRunnable: RunOnTransitStart? val deactivationRunnable: RunOnTransitStart? if ( DesktopExperienceFlags.MOVE_TO_NEXT_DISPLAY_SHORTCUT_WITH_PROJECTED_MODE.isTrue && desktopState.isProjectedMode() && displayId == DEFAULT_DISPLAY ) { logV("moveToDisplay: moving task to default display during projected mode") activationRunnable = null deactivationRunnable = addMoveToFullscreenChanges( wct, task, willExitDesktop( triggerTaskId = task.taskId, displayId = task.displayId, forceExitDesktop = false, ), displayId, ) } else { val destinationDeskId = taskRepository.getDefaultDeskId(displayId) if (destinationDeskId == null) { logW("moveToDisplay: desk not found for display: $displayId") Loading @@ -2161,9 +2191,8 @@ class DesktopTasksController( wct.reparent(task.token, displayAreaInfo.token, /* onTop= */ true) } val activationRunnable = activationRunnable = addDeskActivationChanges(destinationDeskId, wct, task, enterReason = enterReason) val sourceDisplayId = task.displayId val sourceDeskId = taskRepository.getDeskIdForTask(task.taskId) val shouldExitDesktopIfNeeded = Loading @@ -2171,7 +2200,7 @@ class DesktopTasksController( DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue val isLastTask = sourceDeskId?.let { taskRepository.isOnlyTaskInDesk(task.taskId, it) } ?: false val deactivationRunnable = deactivationRunnable = if (shouldExitDesktopIfNeeded) { performDesktopExitCleanupIfNeeded( taskId = task.taskId, Loading @@ -2185,6 +2214,7 @@ class DesktopTasksController( } else { null } } if (DesktopExperienceFlags.ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS.isTrue) { // Bring the destination display to top with includingParents=true, so that the // destination display gains the display focus, which makes the top task in the display Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +36 −0 Original line number Diff line number Diff line Loading @@ -101,6 +101,7 @@ import com.android.window.flags.Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP import com.android.window.flags.Flags.FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT import com.android.window.flags.Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND import com.android.window.flags.Flags.FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY import com.android.window.flags.Flags.FLAG_MOVE_TO_NEXT_DISPLAY_SHORTCUT_WITH_PROJECTED_MODE import com.android.wm.shell.MockToken import com.android.wm.shell.R import com.android.wm.shell.RootTaskDisplayAreaOrganizer Loading Loading @@ -4165,6 +4166,41 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() verify(taskbarDesktopTaskListener).onTaskbarCornerRoundingUpdate(anyBoolean()) } @Test @EnableFlags( FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT, FLAG_MOVE_TO_NEXT_DISPLAY_SHORTCUT_WITH_PROJECTED_MODE, ) fun moveToNextDesktopDisplay_projectedMode_movesToFullscreenOnDefaultDisplay() { // Setup state where a desktop task is running on a secondary display while the device is in // projected mode desktopState.isProjected = true whenever(rootTaskDisplayAreaOrganizer.displayIds) .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY)) val defaultDisplayArea = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0) whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)) .thenReturn(defaultDisplayArea) taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) val task = setUpFreeformTask(displayId = SECOND_DISPLAY) controller.moveToNextDesktopDisplay(task.taskId, EnterReason.UNKNOWN_ENTER) val wct = getLatestWct( type = TRANSIT_CHANGE, handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java, ) // Verify that the task is reparented to the default display and set to fullscreen mode val hierarchyOp = wct.hierarchyOps.find { it.container == task.token.asBinder() && it.isReparent } assertNotNull(hierarchyOp) assertThat(hierarchyOp.newParent).isEqualTo(defaultDisplayArea.token.asBinder()) val configChange = wct.changes[task.token.asBinder()] assertNotNull(configChange) assertThat(configChange.windowingMode).isEqualTo(WINDOWING_MODE_FULLSCREEN) } private fun moveToNextDesktopDisplay_moveIifDesktopModeSupportedOnDestination( isDesktopModeSupportedOnDestination: Boolean ) { Loading