Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +24 −5 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.UiEventLogger; import com.android.internal.statusbar.IStatusBarService; import com.android.launcher3.icons.IconProvider; import com.android.window.flags.Flags; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.WindowManagerShellWrapper; Loading Loading @@ -59,6 +60,7 @@ import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver; import com.android.wm.shell.desktopmode.DesktopModeStatus; import com.android.wm.shell.desktopmode.DesktopModeTaskRepository; import com.android.wm.shell.desktopmode.DesktopTasksController; import com.android.wm.shell.desktopmode.DesktopTasksLimiter; import com.android.wm.shell.desktopmode.DesktopTasksTransitionObserver; import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler; import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler; Loading Loading @@ -517,23 +519,39 @@ public abstract class WMShellModule { LaunchAdjacentController launchAdjacentController, RecentsTransitionHandler recentsTransitionHandler, MultiInstanceHelper multiInstanceHelper, @ShellMainThread ShellExecutor mainExecutor ) { @ShellMainThread ShellExecutor mainExecutor, Optional<DesktopTasksLimiter> desktopTasksLimiter) { return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController, displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, dragAndDropController, transitions, enterDesktopTransitionHandler, exitDesktopTransitionHandler, toggleResizeDesktopTaskTransitionHandler, dragToDesktopTransitionHandler, desktopModeTaskRepository, desktopModeLoggerTransitionObserver, launchAdjacentController, recentsTransitionHandler, multiInstanceHelper, mainExecutor); recentsTransitionHandler, multiInstanceHelper, mainExecutor, desktopTasksLimiter); } @WMSingleton @Provides static Optional<DesktopTasksLimiter> provideDesktopTasksLimiter( Transitions transitions, @DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository, ShellTaskOrganizer shellTaskOrganizer) { if (!DesktopModeStatus.isEnabled() || !Flags.enableDesktopWindowingTaskLimit()) { return Optional.empty(); } return Optional.of( new DesktopTasksLimiter( transitions, desktopModeTaskRepository, shellTaskOrganizer)); } @WMSingleton @Provides static DragToDesktopTransitionHandler provideDragToDesktopTransitionHandler( Context context, Transitions transitions, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, Optional<DesktopTasksLimiter> desktopTasksLimiter) { return new DragToDesktopTransitionHandler(context, transitions, rootTaskDisplayAreaOrganizer); } Loading @@ -541,7 +559,8 @@ public abstract class WMShellModule { @WMSingleton @Provides static EnterDesktopTaskTransitionHandler provideEnterDesktopModeTaskTransitionHandler( Transitions transitions) { Transitions transitions, Optional<DesktopTasksLimiter> desktopTasksLimiter) { return new EnterDesktopTaskTransitionHandler(transitions); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java +23 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,22 @@ public class DesktopModeStatus { private static final boolean ENFORCE_DEVICE_RESTRICTIONS = SystemProperties.getBoolean( "persist.wm.debug.desktop_mode_enforce_device_restrictions", true); /** * Default value for {@code MAX_TASK_LIMIT}. */ @VisibleForTesting public static final int DEFAULT_MAX_TASK_LIMIT = 4; // TODO(b/335131008): add a config-overlay field for the max number of tasks in Desktop Mode /** * Flag declaring the maximum number of Tasks to show in Desktop Mode at any one time. * * <p> The limit does NOT affect Picture-in-Picture, Bubbles, or System Modals (like a screen * recording window, or Bluetooth pairing window). */ private static final int MAX_TASK_LIMIT = SystemProperties.getInt( "persist.wm.debug.desktop_max_task_limit", DEFAULT_MAX_TASK_LIMIT); /** * Return {@code true} if desktop windowing is enabled */ Loading Loading @@ -123,6 +139,13 @@ public class DesktopModeStatus { return ENFORCE_DEVICE_RESTRICTIONS; } /** * Return the maximum limit on the number of Tasks to show in Desktop Mode at any one time. */ static int getMaxTaskLimit() { return MAX_TASK_LIMIT; } /** * Return {@code true} if the current device supports desktop mode. */ Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt +47 −1 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ class DesktopModeTaskRepository { */ val activeTasks: ArraySet<Int> = ArraySet(), val visibleTasks: ArraySet<Int> = ArraySet(), val minimizedTasks: ArraySet<Int> = ArraySet(), var stashed: Boolean = false ) Loading Loading @@ -202,6 +203,13 @@ class DesktopModeTaskRepository { } } /** Return whether the given Task is minimized. */ fun isMinimizedTask(taskId: Int): Boolean { return displayData.valueIterator().asSequence().any { data -> data.minimizedTasks.contains(taskId) } } /** * Check if a task with the given [taskId] is the only active task on its display */ Loading @@ -218,6 +226,25 @@ class DesktopModeTaskRepository { return ArraySet(displayData[displayId]?.activeTasks) } /** * Returns whether Desktop Mode is currently showing any tasks, i.e. whether any Desktop Tasks * are visible. */ fun isDesktopModeShowing(displayId: Int): Boolean = getVisibleTaskCount(displayId) > 0 /** * Returns a list of Tasks IDs representing all active non-minimized Tasks on the given display, * ordered from front to back. */ fun getActiveNonMinimizedTasksOrderedFrontToBack(displayId: Int): List<Int> { val activeTasks = getActiveTasks(displayId) val allTasksInZOrder = getFreeformTasksInZOrder() return activeTasks // Don't show already minimized Tasks .filter { taskId -> !isMinimizedTask(taskId) } .sortedBy { taskId -> allTasksInZOrder.indexOf(taskId) } } /** * Get a list of freeform tasks, ordered from top-bottom (top at index 0). */ Loading Loading @@ -255,6 +282,7 @@ class DesktopModeTaskRepository { val prevCount = getVisibleTaskCount(displayId) if (visible) { displayData.getOrCreate(displayId).visibleTasks.add(taskId) unminimizeTask(displayId, taskId) } else { displayData[displayId]?.visibleTasks?.remove(taskId) } Loading Loading @@ -312,6 +340,24 @@ class DesktopModeTaskRepository { freeformTasksInZOrder.add(0, taskId) } /** Mark a Task as minimized. */ fun minimizeTask(displayId: Int, taskId: Int) { KtProtoLog.v( WM_SHELL_DESKTOP_MODE, "DesktopModeTaskRepository: minimize Task: display=%d, task=%d", displayId, taskId) displayData.getOrCreate(displayId).minimizedTasks.add(taskId) } /** Mark a Task as non-minimized. */ fun unminimizeTask(displayId: Int, taskId: Int) { KtProtoLog.v( WM_SHELL_DESKTOP_MODE, "DesktopModeTaskRepository: unminimize Task: display=%d, task=%d", displayId, taskId) displayData[displayId]?.minimizedTasks?.remove(taskId) } /** * Remove the task from the ordered list. */ Loading @@ -325,7 +371,7 @@ class DesktopModeTaskRepository { boundsBeforeMaximizeByTaskId.remove(taskId) KtProtoLog.d( WM_SHELL_DESKTOP_MODE, "DesktopTaskRepo: remaining freeform tasks: " + freeformTasksInZOrder.toDumpString() "DesktopTaskRepo: remaining freeform tasks: %s", freeformTasksInZOrder.toDumpString(), ) } Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +99 −27 Original line number Diff line number Diff line Loading @@ -88,6 +88,7 @@ import com.android.wm.shell.windowdecor.OnTaskResizeAnimationListener import com.android.wm.shell.windowdecor.extension.isFreeform import com.android.wm.shell.windowdecor.extension.isFullscreen import java.io.PrintWriter import java.util.Optional import java.util.concurrent.Executor import java.util.function.Consumer Loading @@ -113,7 +114,8 @@ class DesktopTasksController( private val launchAdjacentController: LaunchAdjacentController, private val recentsTransitionHandler: RecentsTransitionHandler, private val multiInstanceHelper: MultiInstanceHelper, @ShellMainThread private val mainExecutor: ShellExecutor @ShellMainThread private val mainExecutor: ShellExecutor, private val desktopTasksLimiter: Optional<DesktopTasksLimiter>, ) : RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler, DragAndDropController.DragAndDropListener { Loading Loading @@ -341,11 +343,13 @@ class DesktopTasksController( ) exitSplitIfApplicable(wct, task) // Bring other apps to front first bringDesktopAppsToFront(task.displayId, wct) val taskToMinimize = bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, task.taskId) addMoveToDesktopChanges(wct, task) if (Transitions.ENABLE_SHELL_TRANSITIONS) { enterDesktopTaskTransitionHandler.moveToDesktop(wct) val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct) addPendingMinimizeTransition(transition, taskToMinimize) } else { shellTaskOrganizer.applyTransaction(wct) } Loading Loading @@ -382,10 +386,14 @@ class DesktopTasksController( ) val wct = WindowContainerTransaction() exitSplitIfApplicable(wct, taskInfo) bringDesktopAppsToFront(taskInfo.displayId, wct) moveHomeTaskToFront(wct) val taskToMinimize = bringDesktopAppsToFrontBeforeShowingNewTask( taskInfo.displayId, wct, taskInfo.taskId) addMoveToDesktopChanges(wct, taskInfo) wct.setBounds(taskInfo.token, freeformBounds) dragToDesktopTransitionHandler.finishDragToDesktopTransition(wct) val transition = dragToDesktopTransitionHandler.finishDragToDesktopTransition(wct) transition?.let { addPendingMinimizeTransition(it, taskToMinimize) } } /** Loading Loading @@ -507,8 +515,10 @@ class DesktopTasksController( val wct = WindowContainerTransaction() wct.reorder(taskInfo.token, true) val taskToMinimize = addAndGetMinimizeChangesIfNeeded(taskInfo.displayId, wct, taskInfo) if (Transitions.ENABLE_SHELL_TRANSITIONS) { transitions.startTransition(TRANSIT_TO_FRONT, wct, null /* handler */) val transition = transitions.startTransition(TRANSIT_TO_FRONT, wct, null /* handler */) addPendingMinimizeTransition(transition, taskToMinimize) } else { shellTaskOrganizer.applyTransaction(wct) } Loading Loading @@ -688,9 +698,20 @@ class DesktopTasksController( ?: WINDOWING_MODE_UNDEFINED } private fun bringDesktopAppsToFront(displayId: Int, wct: WindowContainerTransaction) { KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: bringDesktopAppsToFront") val activeTasks = desktopModeTaskRepository.getActiveTasks(displayId) private fun bringDesktopAppsToFrontBeforeShowingNewTask( displayId: Int, wct: WindowContainerTransaction, newTaskIdInFront: Int ): RunningTaskInfo? = bringDesktopAppsToFront(displayId, wct, newTaskIdInFront) private fun bringDesktopAppsToFront( displayId: Int, wct: WindowContainerTransaction, newTaskIdInFront: Int? = null ): RunningTaskInfo? { KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: bringDesktopAppsToFront, newTaskIdInFront=%s", newTaskIdInFront ?: "null") if (Flags.enableDesktopWindowingWallpaperActivity()) { // Add translucent wallpaper activity to show the wallpaper underneath Loading @@ -700,13 +721,21 @@ class DesktopTasksController( moveHomeTaskToFront(wct) } // Then move other tasks on top of it val allTasksInZOrder = desktopModeTaskRepository.getFreeformTasksInZOrder() activeTasks // Sort descending as the top task is at index 0. It should be ordered to top last .sortedByDescending { taskId -> allTasksInZOrder.indexOf(taskId) } val nonMinimizedTasksOrderedFrontToBack = desktopModeTaskRepository.getActiveNonMinimizedTasksOrderedFrontToBack(displayId) // If we're adding a new Task we might need to minimize an old one val taskToMinimize: RunningTaskInfo? = if (newTaskIdInFront != null && desktopTasksLimiter.isPresent) { desktopTasksLimiter.get().getTaskToMinimizeIfNeeded( nonMinimizedTasksOrderedFrontToBack, newTaskIdInFront) } else { null } nonMinimizedTasksOrderedFrontToBack // If there is a Task to minimize, let it stay behind the Home Task .filter { taskId -> taskId != taskToMinimize?.taskId } .mapNotNull { taskId -> shellTaskOrganizer.getRunningTaskInfo(taskId) } .reversed() // Start from the back so the front task is brought forward last .forEach { task -> wct.reorder(task.token, true /* onTop */) } return taskToMinimize } private fun moveHomeTaskToFront(wct: WindowContainerTransaction) { Loading Loading @@ -824,13 +853,13 @@ class DesktopTasksController( when { request.type == TRANSIT_TO_BACK -> handleBackNavigation(task) // If display has tasks stashed, handle as stashed launch task.isStashed -> handleStashedTaskLaunch(task) task.isStashed -> handleStashedTaskLaunch(task, transition) // Check if the task has a top transparent activity shouldLaunchAsModal(task) -> handleTransparentTaskLaunch(task) // Check if fullscreen task should be updated task.isFullscreen -> handleFullscreenTaskLaunch(task) task.isFullscreen -> handleFullscreenTaskLaunch(task, transition) // Check if freeform task should be updated task.isFreeform -> handleFreeformTaskLaunch(task) task.isFreeform -> handleFreeformTaskLaunch(task, transition) else -> { null } Loading Loading @@ -878,10 +907,12 @@ class DesktopTasksController( } ?: false } private fun handleFreeformTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? { private fun handleFreeformTaskLaunch( task: RunningTaskInfo, transition: IBinder ): WindowContainerTransaction? { KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: handleFreeformTaskLaunch") val activeTasks = desktopModeTaskRepository.getActiveTasks(task.displayId) if (activeTasks.none { desktopModeTaskRepository.isVisibleTask(it) }) { if (!desktopModeTaskRepository.isDesktopModeShowing(task.displayId)) { KtProtoLog.d( WM_SHELL_DESKTOP_MODE, "DesktopTasksController: switch freeform task to fullscreen oon transition" + Loading @@ -892,13 +923,23 @@ class DesktopTasksController( addMoveToFullscreenChanges(wct, task) } } // Desktop Mode is showing and we're launching a new Task - we might need to minimize // a Task. val wct = WindowContainerTransaction() val taskToMinimize = addAndGetMinimizeChangesIfNeeded(task.displayId, wct, task) if (taskToMinimize != null) { addPendingMinimizeTransition(transition, taskToMinimize) return wct } return null } private fun handleFullscreenTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? { private fun handleFullscreenTaskLaunch( task: RunningTaskInfo, transition: IBinder ): WindowContainerTransaction? { KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: handleFullscreenTaskLaunch") val activeTasks = desktopModeTaskRepository.getActiveTasks(task.displayId) if (activeTasks.any { desktopModeTaskRepository.isVisibleTask(it) }) { if (desktopModeTaskRepository.isDesktopModeShowing(task.displayId)) { KtProtoLog.d( WM_SHELL_DESKTOP_MODE, "DesktopTasksController: switch fullscreen task to freeform on transition" + Loading @@ -907,21 +948,30 @@ class DesktopTasksController( ) return WindowContainerTransaction().also { wct -> addMoveToDesktopChanges(wct, task) // Desktop Mode is already showing and we're launching a new Task - we might need to // minimize another Task. val taskToMinimize = addAndGetMinimizeChangesIfNeeded(task.displayId, wct, task) addPendingMinimizeTransition(transition, taskToMinimize) } } return null } private fun handleStashedTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction { private fun handleStashedTaskLaunch( task: RunningTaskInfo, transition: IBinder ): WindowContainerTransaction { KtProtoLog.d( WM_SHELL_DESKTOP_MODE, "DesktopTasksController: launch apps with stashed on transition taskId=%d", task.taskId ) val wct = WindowContainerTransaction() bringDesktopAppsToFront(task.displayId, wct) val taskToMinimize = bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, task.taskId) addMoveToDesktopChanges(wct, task) desktopModeTaskRepository.setStashed(task.displayId, false) addPendingMinimizeTransition(transition, taskToMinimize) return wct } Loading Loading @@ -1002,6 +1052,28 @@ class DesktopTasksController( wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi()) } /** Returns the ID of the Task that will be minimized, or null if no task will be minimized. */ private fun addAndGetMinimizeChangesIfNeeded( displayId: Int, wct: WindowContainerTransaction, newTaskInfo: RunningTaskInfo ): RunningTaskInfo? { if (!desktopTasksLimiter.isPresent) return null return desktopTasksLimiter.get().addAndGetMinimizeTaskChangesIfNeeded( displayId, wct, newTaskInfo) } private fun addPendingMinimizeTransition( transition: IBinder, taskToMinimize: RunningTaskInfo? ) { if (taskToMinimize == null) return desktopTasksLimiter.ifPresent { it.addPendingMinimizeChange( transition, taskToMinimize.displayId, taskToMinimize.taskId) } } /** Enter split by using the focused desktop task in given `displayId`. */ fun enterSplit( displayId: Int, Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt 0 → 100644 +217 −0 File added.Preview size limit exceeded, changes collapsed. Show changes Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +24 −5 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.UiEventLogger; import com.android.internal.statusbar.IStatusBarService; import com.android.launcher3.icons.IconProvider; import com.android.window.flags.Flags; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.WindowManagerShellWrapper; Loading Loading @@ -59,6 +60,7 @@ import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver; import com.android.wm.shell.desktopmode.DesktopModeStatus; import com.android.wm.shell.desktopmode.DesktopModeTaskRepository; import com.android.wm.shell.desktopmode.DesktopTasksController; import com.android.wm.shell.desktopmode.DesktopTasksLimiter; import com.android.wm.shell.desktopmode.DesktopTasksTransitionObserver; import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler; import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler; Loading Loading @@ -517,23 +519,39 @@ public abstract class WMShellModule { LaunchAdjacentController launchAdjacentController, RecentsTransitionHandler recentsTransitionHandler, MultiInstanceHelper multiInstanceHelper, @ShellMainThread ShellExecutor mainExecutor ) { @ShellMainThread ShellExecutor mainExecutor, Optional<DesktopTasksLimiter> desktopTasksLimiter) { return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController, displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, dragAndDropController, transitions, enterDesktopTransitionHandler, exitDesktopTransitionHandler, toggleResizeDesktopTaskTransitionHandler, dragToDesktopTransitionHandler, desktopModeTaskRepository, desktopModeLoggerTransitionObserver, launchAdjacentController, recentsTransitionHandler, multiInstanceHelper, mainExecutor); recentsTransitionHandler, multiInstanceHelper, mainExecutor, desktopTasksLimiter); } @WMSingleton @Provides static Optional<DesktopTasksLimiter> provideDesktopTasksLimiter( Transitions transitions, @DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository, ShellTaskOrganizer shellTaskOrganizer) { if (!DesktopModeStatus.isEnabled() || !Flags.enableDesktopWindowingTaskLimit()) { return Optional.empty(); } return Optional.of( new DesktopTasksLimiter( transitions, desktopModeTaskRepository, shellTaskOrganizer)); } @WMSingleton @Provides static DragToDesktopTransitionHandler provideDragToDesktopTransitionHandler( Context context, Transitions transitions, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, Optional<DesktopTasksLimiter> desktopTasksLimiter) { return new DragToDesktopTransitionHandler(context, transitions, rootTaskDisplayAreaOrganizer); } Loading @@ -541,7 +559,8 @@ public abstract class WMShellModule { @WMSingleton @Provides static EnterDesktopTaskTransitionHandler provideEnterDesktopModeTaskTransitionHandler( Transitions transitions) { Transitions transitions, Optional<DesktopTasksLimiter> desktopTasksLimiter) { return new EnterDesktopTaskTransitionHandler(transitions); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java +23 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,22 @@ public class DesktopModeStatus { private static final boolean ENFORCE_DEVICE_RESTRICTIONS = SystemProperties.getBoolean( "persist.wm.debug.desktop_mode_enforce_device_restrictions", true); /** * Default value for {@code MAX_TASK_LIMIT}. */ @VisibleForTesting public static final int DEFAULT_MAX_TASK_LIMIT = 4; // TODO(b/335131008): add a config-overlay field for the max number of tasks in Desktop Mode /** * Flag declaring the maximum number of Tasks to show in Desktop Mode at any one time. * * <p> The limit does NOT affect Picture-in-Picture, Bubbles, or System Modals (like a screen * recording window, or Bluetooth pairing window). */ private static final int MAX_TASK_LIMIT = SystemProperties.getInt( "persist.wm.debug.desktop_max_task_limit", DEFAULT_MAX_TASK_LIMIT); /** * Return {@code true} if desktop windowing is enabled */ Loading Loading @@ -123,6 +139,13 @@ public class DesktopModeStatus { return ENFORCE_DEVICE_RESTRICTIONS; } /** * Return the maximum limit on the number of Tasks to show in Desktop Mode at any one time. */ static int getMaxTaskLimit() { return MAX_TASK_LIMIT; } /** * Return {@code true} if the current device supports desktop mode. */ Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt +47 −1 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ class DesktopModeTaskRepository { */ val activeTasks: ArraySet<Int> = ArraySet(), val visibleTasks: ArraySet<Int> = ArraySet(), val minimizedTasks: ArraySet<Int> = ArraySet(), var stashed: Boolean = false ) Loading Loading @@ -202,6 +203,13 @@ class DesktopModeTaskRepository { } } /** Return whether the given Task is minimized. */ fun isMinimizedTask(taskId: Int): Boolean { return displayData.valueIterator().asSequence().any { data -> data.minimizedTasks.contains(taskId) } } /** * Check if a task with the given [taskId] is the only active task on its display */ Loading @@ -218,6 +226,25 @@ class DesktopModeTaskRepository { return ArraySet(displayData[displayId]?.activeTasks) } /** * Returns whether Desktop Mode is currently showing any tasks, i.e. whether any Desktop Tasks * are visible. */ fun isDesktopModeShowing(displayId: Int): Boolean = getVisibleTaskCount(displayId) > 0 /** * Returns a list of Tasks IDs representing all active non-minimized Tasks on the given display, * ordered from front to back. */ fun getActiveNonMinimizedTasksOrderedFrontToBack(displayId: Int): List<Int> { val activeTasks = getActiveTasks(displayId) val allTasksInZOrder = getFreeformTasksInZOrder() return activeTasks // Don't show already minimized Tasks .filter { taskId -> !isMinimizedTask(taskId) } .sortedBy { taskId -> allTasksInZOrder.indexOf(taskId) } } /** * Get a list of freeform tasks, ordered from top-bottom (top at index 0). */ Loading Loading @@ -255,6 +282,7 @@ class DesktopModeTaskRepository { val prevCount = getVisibleTaskCount(displayId) if (visible) { displayData.getOrCreate(displayId).visibleTasks.add(taskId) unminimizeTask(displayId, taskId) } else { displayData[displayId]?.visibleTasks?.remove(taskId) } Loading Loading @@ -312,6 +340,24 @@ class DesktopModeTaskRepository { freeformTasksInZOrder.add(0, taskId) } /** Mark a Task as minimized. */ fun minimizeTask(displayId: Int, taskId: Int) { KtProtoLog.v( WM_SHELL_DESKTOP_MODE, "DesktopModeTaskRepository: minimize Task: display=%d, task=%d", displayId, taskId) displayData.getOrCreate(displayId).minimizedTasks.add(taskId) } /** Mark a Task as non-minimized. */ fun unminimizeTask(displayId: Int, taskId: Int) { KtProtoLog.v( WM_SHELL_DESKTOP_MODE, "DesktopModeTaskRepository: unminimize Task: display=%d, task=%d", displayId, taskId) displayData[displayId]?.minimizedTasks?.remove(taskId) } /** * Remove the task from the ordered list. */ Loading @@ -325,7 +371,7 @@ class DesktopModeTaskRepository { boundsBeforeMaximizeByTaskId.remove(taskId) KtProtoLog.d( WM_SHELL_DESKTOP_MODE, "DesktopTaskRepo: remaining freeform tasks: " + freeformTasksInZOrder.toDumpString() "DesktopTaskRepo: remaining freeform tasks: %s", freeformTasksInZOrder.toDumpString(), ) } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +99 −27 Original line number Diff line number Diff line Loading @@ -88,6 +88,7 @@ import com.android.wm.shell.windowdecor.OnTaskResizeAnimationListener import com.android.wm.shell.windowdecor.extension.isFreeform import com.android.wm.shell.windowdecor.extension.isFullscreen import java.io.PrintWriter import java.util.Optional import java.util.concurrent.Executor import java.util.function.Consumer Loading @@ -113,7 +114,8 @@ class DesktopTasksController( private val launchAdjacentController: LaunchAdjacentController, private val recentsTransitionHandler: RecentsTransitionHandler, private val multiInstanceHelper: MultiInstanceHelper, @ShellMainThread private val mainExecutor: ShellExecutor @ShellMainThread private val mainExecutor: ShellExecutor, private val desktopTasksLimiter: Optional<DesktopTasksLimiter>, ) : RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler, DragAndDropController.DragAndDropListener { Loading Loading @@ -341,11 +343,13 @@ class DesktopTasksController( ) exitSplitIfApplicable(wct, task) // Bring other apps to front first bringDesktopAppsToFront(task.displayId, wct) val taskToMinimize = bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, task.taskId) addMoveToDesktopChanges(wct, task) if (Transitions.ENABLE_SHELL_TRANSITIONS) { enterDesktopTaskTransitionHandler.moveToDesktop(wct) val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct) addPendingMinimizeTransition(transition, taskToMinimize) } else { shellTaskOrganizer.applyTransaction(wct) } Loading Loading @@ -382,10 +386,14 @@ class DesktopTasksController( ) val wct = WindowContainerTransaction() exitSplitIfApplicable(wct, taskInfo) bringDesktopAppsToFront(taskInfo.displayId, wct) moveHomeTaskToFront(wct) val taskToMinimize = bringDesktopAppsToFrontBeforeShowingNewTask( taskInfo.displayId, wct, taskInfo.taskId) addMoveToDesktopChanges(wct, taskInfo) wct.setBounds(taskInfo.token, freeformBounds) dragToDesktopTransitionHandler.finishDragToDesktopTransition(wct) val transition = dragToDesktopTransitionHandler.finishDragToDesktopTransition(wct) transition?.let { addPendingMinimizeTransition(it, taskToMinimize) } } /** Loading Loading @@ -507,8 +515,10 @@ class DesktopTasksController( val wct = WindowContainerTransaction() wct.reorder(taskInfo.token, true) val taskToMinimize = addAndGetMinimizeChangesIfNeeded(taskInfo.displayId, wct, taskInfo) if (Transitions.ENABLE_SHELL_TRANSITIONS) { transitions.startTransition(TRANSIT_TO_FRONT, wct, null /* handler */) val transition = transitions.startTransition(TRANSIT_TO_FRONT, wct, null /* handler */) addPendingMinimizeTransition(transition, taskToMinimize) } else { shellTaskOrganizer.applyTransaction(wct) } Loading Loading @@ -688,9 +698,20 @@ class DesktopTasksController( ?: WINDOWING_MODE_UNDEFINED } private fun bringDesktopAppsToFront(displayId: Int, wct: WindowContainerTransaction) { KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: bringDesktopAppsToFront") val activeTasks = desktopModeTaskRepository.getActiveTasks(displayId) private fun bringDesktopAppsToFrontBeforeShowingNewTask( displayId: Int, wct: WindowContainerTransaction, newTaskIdInFront: Int ): RunningTaskInfo? = bringDesktopAppsToFront(displayId, wct, newTaskIdInFront) private fun bringDesktopAppsToFront( displayId: Int, wct: WindowContainerTransaction, newTaskIdInFront: Int? = null ): RunningTaskInfo? { KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: bringDesktopAppsToFront, newTaskIdInFront=%s", newTaskIdInFront ?: "null") if (Flags.enableDesktopWindowingWallpaperActivity()) { // Add translucent wallpaper activity to show the wallpaper underneath Loading @@ -700,13 +721,21 @@ class DesktopTasksController( moveHomeTaskToFront(wct) } // Then move other tasks on top of it val allTasksInZOrder = desktopModeTaskRepository.getFreeformTasksInZOrder() activeTasks // Sort descending as the top task is at index 0. It should be ordered to top last .sortedByDescending { taskId -> allTasksInZOrder.indexOf(taskId) } val nonMinimizedTasksOrderedFrontToBack = desktopModeTaskRepository.getActiveNonMinimizedTasksOrderedFrontToBack(displayId) // If we're adding a new Task we might need to minimize an old one val taskToMinimize: RunningTaskInfo? = if (newTaskIdInFront != null && desktopTasksLimiter.isPresent) { desktopTasksLimiter.get().getTaskToMinimizeIfNeeded( nonMinimizedTasksOrderedFrontToBack, newTaskIdInFront) } else { null } nonMinimizedTasksOrderedFrontToBack // If there is a Task to minimize, let it stay behind the Home Task .filter { taskId -> taskId != taskToMinimize?.taskId } .mapNotNull { taskId -> shellTaskOrganizer.getRunningTaskInfo(taskId) } .reversed() // Start from the back so the front task is brought forward last .forEach { task -> wct.reorder(task.token, true /* onTop */) } return taskToMinimize } private fun moveHomeTaskToFront(wct: WindowContainerTransaction) { Loading Loading @@ -824,13 +853,13 @@ class DesktopTasksController( when { request.type == TRANSIT_TO_BACK -> handleBackNavigation(task) // If display has tasks stashed, handle as stashed launch task.isStashed -> handleStashedTaskLaunch(task) task.isStashed -> handleStashedTaskLaunch(task, transition) // Check if the task has a top transparent activity shouldLaunchAsModal(task) -> handleTransparentTaskLaunch(task) // Check if fullscreen task should be updated task.isFullscreen -> handleFullscreenTaskLaunch(task) task.isFullscreen -> handleFullscreenTaskLaunch(task, transition) // Check if freeform task should be updated task.isFreeform -> handleFreeformTaskLaunch(task) task.isFreeform -> handleFreeformTaskLaunch(task, transition) else -> { null } Loading Loading @@ -878,10 +907,12 @@ class DesktopTasksController( } ?: false } private fun handleFreeformTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? { private fun handleFreeformTaskLaunch( task: RunningTaskInfo, transition: IBinder ): WindowContainerTransaction? { KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: handleFreeformTaskLaunch") val activeTasks = desktopModeTaskRepository.getActiveTasks(task.displayId) if (activeTasks.none { desktopModeTaskRepository.isVisibleTask(it) }) { if (!desktopModeTaskRepository.isDesktopModeShowing(task.displayId)) { KtProtoLog.d( WM_SHELL_DESKTOP_MODE, "DesktopTasksController: switch freeform task to fullscreen oon transition" + Loading @@ -892,13 +923,23 @@ class DesktopTasksController( addMoveToFullscreenChanges(wct, task) } } // Desktop Mode is showing and we're launching a new Task - we might need to minimize // a Task. val wct = WindowContainerTransaction() val taskToMinimize = addAndGetMinimizeChangesIfNeeded(task.displayId, wct, task) if (taskToMinimize != null) { addPendingMinimizeTransition(transition, taskToMinimize) return wct } return null } private fun handleFullscreenTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? { private fun handleFullscreenTaskLaunch( task: RunningTaskInfo, transition: IBinder ): WindowContainerTransaction? { KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: handleFullscreenTaskLaunch") val activeTasks = desktopModeTaskRepository.getActiveTasks(task.displayId) if (activeTasks.any { desktopModeTaskRepository.isVisibleTask(it) }) { if (desktopModeTaskRepository.isDesktopModeShowing(task.displayId)) { KtProtoLog.d( WM_SHELL_DESKTOP_MODE, "DesktopTasksController: switch fullscreen task to freeform on transition" + Loading @@ -907,21 +948,30 @@ class DesktopTasksController( ) return WindowContainerTransaction().also { wct -> addMoveToDesktopChanges(wct, task) // Desktop Mode is already showing and we're launching a new Task - we might need to // minimize another Task. val taskToMinimize = addAndGetMinimizeChangesIfNeeded(task.displayId, wct, task) addPendingMinimizeTransition(transition, taskToMinimize) } } return null } private fun handleStashedTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction { private fun handleStashedTaskLaunch( task: RunningTaskInfo, transition: IBinder ): WindowContainerTransaction { KtProtoLog.d( WM_SHELL_DESKTOP_MODE, "DesktopTasksController: launch apps with stashed on transition taskId=%d", task.taskId ) val wct = WindowContainerTransaction() bringDesktopAppsToFront(task.displayId, wct) val taskToMinimize = bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, task.taskId) addMoveToDesktopChanges(wct, task) desktopModeTaskRepository.setStashed(task.displayId, false) addPendingMinimizeTransition(transition, taskToMinimize) return wct } Loading Loading @@ -1002,6 +1052,28 @@ class DesktopTasksController( wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi()) } /** Returns the ID of the Task that will be minimized, or null if no task will be minimized. */ private fun addAndGetMinimizeChangesIfNeeded( displayId: Int, wct: WindowContainerTransaction, newTaskInfo: RunningTaskInfo ): RunningTaskInfo? { if (!desktopTasksLimiter.isPresent) return null return desktopTasksLimiter.get().addAndGetMinimizeTaskChangesIfNeeded( displayId, wct, newTaskInfo) } private fun addPendingMinimizeTransition( transition: IBinder, taskToMinimize: RunningTaskInfo? ) { if (taskToMinimize == null) return desktopTasksLimiter.ifPresent { it.addPendingMinimizeChange( transition, taskToMinimize.displayId, taskToMinimize.taskId) } } /** Enter split by using the focused desktop task in given `displayId`. */ fun enterSplit( displayId: Int, Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt 0 → 100644 +217 −0 File added.Preview size limit exceeded, changes collapsed. Show changes