Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e804e54 authored by Gustav Sennton's avatar Gustav Sennton Committed by Android (Google) Code Review
Browse files

Merge "Minimize a Task whenever we reach the Desktop Task limit" into main

parents c0fec65d 1096b70b
Loading
Loading
Loading
Loading
+24 −5
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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);
    }
@@ -541,7 +559,8 @@ public abstract class WMShellModule {
    @WMSingleton
    @Provides
    static EnterDesktopTaskTransitionHandler provideEnterDesktopModeTaskTransitionHandler(
            Transitions transitions) {
            Transitions transitions,
            Optional<DesktopTasksLimiter> desktopTasksLimiter) {
        return new EnterDesktopTaskTransitionHandler(transitions);
    }

+23 −0
Original line number Diff line number Diff line
@@ -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
     */
@@ -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.
     */
+47 −1
Original line number Diff line number Diff line
@@ -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
    )

@@ -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
     */
@@ -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).
     */
@@ -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)
        }
@@ -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.
     */
@@ -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(),
        )
    }

+99 −27
Original line number Diff line number Diff line
@@ -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

@@ -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 {

@@ -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)
        }
@@ -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) }
    }

    /**
@@ -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)
        }
@@ -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
@@ -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) {
@@ -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
                }
@@ -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" +
@@ -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" +
@@ -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
    }

@@ -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,
+217 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading