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

Commit a949833e authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "[8/N] Desks: Implement move-to-desk for running tasks" into main

parents 98b6933d 9c3a783f
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
                return false
            }
        if (!Flags.enableMultipleDesktopsBackend()) {
            return controller.moveTaskToDesktop(taskId, transitionSource = UNKNOWN)
            return controller.moveTaskToDefaultDeskAndActivate(taskId, transitionSource = UNKNOWN)
        }
        if (args.size < 3) {
            pw.println("Error: desk id should be provided as arguments")
@@ -70,8 +70,9 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
                pw.println("Error: desk id should be an integer")
                return false
            }
        controller.moveTaskToDesk(taskId = taskId, deskId = deskId, transitionSource = UNKNOWN)
        pw.println("Not implemented.")
        return false
        return true
    }

    private fun runMoveToNextDisplay(args: Array<String>, pw: PrintWriter): Boolean {
+78 −43
Original line number Diff line number Diff line
@@ -236,25 +236,32 @@ class DesktopRepository(
     * TODO: b/389960283 - add explicit [deskId] argument.
     */
    fun addTask(displayId: Int, taskId: Int, isVisible: Boolean) {
        addOrMoveFreeformTaskToTop(displayId, taskId)
        addActiveTask(displayId, taskId)
        updateTask(displayId, taskId, isVisible)
        val activeDesk =
            checkNotNull(desktopData.getDefaultDesk(displayId)) {
                "Expected desk in display: $displayId"
            }
        addTaskToDesk(displayId = displayId, deskId = activeDesk.deskId, taskId = taskId, isVisible)
    }

    /**
     * Adds task with [taskId] to the list of active tasks on [displayId]'s active desk.
     *
     * TODO: b/389960283 - add explicit [deskId] argument.
     */
    private fun addActiveTask(displayId: Int, taskId: Int) {
        val activeDesk = desktopData.getDefaultDesk(displayId)
        checkNotNull(activeDesk) { "Expected desk in display: $displayId" }
    fun addTaskToDesk(displayId: Int, deskId: Int, taskId: Int, isVisible: Boolean) {
        addOrMoveTaskToTopOfDesk(displayId = displayId, deskId = deskId, taskId = taskId)
        addActiveTaskToDesk(displayId = displayId, deskId = deskId, taskId = taskId)
        updateTaskInDesk(
            displayId = displayId,
            deskId = deskId,
            taskId = taskId,
            isVisible = isVisible,
        )
    }

        // Removes task if it is active on another desk excluding [activeDesk].
        removeActiveTask(taskId, excludedDeskId = activeDesk.deskId)
    private fun addActiveTaskToDesk(displayId: Int, deskId: Int, taskId: Int) {
        val desk = checkNotNull(desktopData.getDesk(deskId)) { "Did not find desk: $deskId" }

        if (activeDesk.activeTasks.add(taskId)) {
            logD("Adds active task=%d displayId=%d deskId=%d", taskId, displayId, activeDesk.deskId)
        // Removes task if it is active on another desk excluding this desk.
        removeActiveTask(taskId, excludedDeskId = deskId)

        if (desk.activeTasks.add(taskId)) {
            logD("Adds active task=%d displayId=%d deskId=%d", taskId, displayId, deskId)
            updateActiveTasksListeners(displayId)
        }
    }
@@ -405,10 +412,10 @@ class DesktopRepository(
                emptySet()
            }

    /** Removes task from visible tasks of all displays except [excludedDisplayId]. */
    private fun removeVisibleTask(taskId: Int, excludedDisplayId: Int? = null) {
    /** Removes task from visible tasks of all desks except [excludedDeskId]. */
    private fun removeVisibleTask(taskId: Int, excludedDeskId: Int? = null) {
        desktopData.forAllDesks { displayId, desk ->
            if (displayId != excludedDisplayId && desk.visibleTasks.remove(taskId)) {
            if (desk.deskId != excludedDeskId && desk.visibleTasks.remove(taskId)) {
                notifyVisibleTaskListeners(displayId, desk.visibleTasks.size)
            }
        }
@@ -423,30 +430,58 @@ class DesktopRepository(
     * TODO: b/389960283 - add explicit [deskId] argument.
     */
    fun updateTask(displayId: Int, taskId: Int, isVisible: Boolean) {
        logD("updateTask taskId=%d, displayId=%d, isVisible=%b", taskId, displayId, isVisible)
        val validDisplayId =
            if (displayId == INVALID_DISPLAY) {
                // When a task vanishes it doesn't have a displayId. Find the display of the task.
                getDisplayIdForTask(taskId)
            } else {
                displayId
            }
        if (validDisplayId == null) {
            logW("No display id found for task: taskId=%d", taskId)
            return
        }
        val desk =
            checkNotNull(desktopData.getDefaultDesk(validDisplayId)) {
                "Expected a desk in display: $validDisplayId"
            }
        updateTaskInDesk(
            displayId = validDisplayId,
            deskId = desk.deskId,
            taskId = taskId,
            isVisible,
        )
    }

    private fun updateTaskInDesk(displayId: Int, deskId: Int, taskId: Int, isVisible: Boolean) {
        check(displayId != INVALID_DISPLAY) { "Display must be valid" }
        logD(
            "updateTaskInDesk taskId=%d, deskId=%d, displayId=%d, isVisible=%b",
            taskId,
            deskId,
            displayId,
            isVisible,
        )

        if (isVisible) {
            // If task is visible, remove it from any other display besides [displayId].
            removeVisibleTask(taskId, excludedDisplayId = displayId)
        } else if (displayId == INVALID_DISPLAY) {
            // Task has vanished. Check which display to remove the task from.
            removeVisibleTask(taskId)
            return
            // If task is visible, remove it from any other desk besides [deskId].
            removeVisibleTask(taskId, excludedDeskId = deskId)
        }
        val prevCount = getVisibleTaskCount(displayId)
        val desk = checkNotNull(desktopData.getDesk(deskId)) { "Did not find desk: $deskId" }
        val prevCount = getVisibleTaskCountInDesk(deskId)
        if (isVisible) {
            desktopData.getDefaultDesk(displayId)?.visibleTasks?.add(taskId)
                ?: error("Expected non-null desk in display $displayId")
            desk.visibleTasks.add(taskId)
            unminimizeTask(displayId, taskId)
        } else {
            desktopData.getDefaultDesk(displayId)?.visibleTasks?.remove(taskId)
            desk.visibleTasks.remove(taskId)
        }
        val newCount = getVisibleTaskCount(displayId)
        val newCount = getVisibleTaskCount(deskId)
        if (prevCount != newCount) {
            logD(
                "Update task visibility taskId=%d visible=%b displayId=%d",
                "Update task visibility taskId=%d visible=%b deskId=%d displayId=%d",
                taskId,
                isVisible,
                deskId,
                displayId,
            )
            logD("VisibleTaskCount has changed from %d to %d", prevCount, newCount)
@@ -606,33 +641,32 @@ class DesktopRepository(
    /**
     * Gets number of visible freeform tasks on given [displayId]'s active desk.
     *
     * TODO: b/389960283 - add explicit [deskId] argument.
     * TODO: b/389960283 - migrate callers to [getVisibleTaskCountInDesk].
     */
    fun getVisibleTaskCount(displayId: Int): Int =
        (desktopData.getActiveDesk(displayId)?.visibleTasks?.size ?: 0).also {
            logD("getVisibleTaskCount=$it")
        }

    /** Gets the number of visible tasks on the given desk. */
    fun getVisibleTaskCountInDesk(deskId: Int): Int =
        desktopData.getDesk(deskId)?.visibleTasks?.size ?: 0

    /**
     * Adds task (or moves if it already exists) to the top of the ordered list.
     *
     * Unminimizes the task if it is minimized.
     *
     * TODO: b/389960283 - add explicit [deskId] argument.
     */
    private fun addOrMoveFreeformTaskToTop(displayId: Int, taskId: Int) {
        val desk = getDefaultDesk(displayId) ?: error("Expected a desk in display: $displayId")
        logD(
            "Add or move task to top: display=%d taskId=%d deskId=%d",
            taskId,
            displayId,
            desk.deskId,
        )
    private fun addOrMoveTaskToTopOfDesk(displayId: Int, deskId: Int, taskId: Int) {
        val desk = desktopData.getDesk(deskId) ?: error("Could not find desk: $deskId")
        logD("addOrMoveTaskToTopOfDesk: display=%d deskId=%d taskId=%d", displayId, deskId, taskId)
        desktopData.forAllDesks { _, desk1 -> desk1.freeformTasksInZOrder.remove(taskId) }
        desk.freeformTasksInZOrder.add(0, taskId)
        // TODO: double check minimization logic.
        // Unminimize the task if it is minimized.
        unminimizeTask(displayId, taskId)
        if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) {
            // TODO: can probably just update the desk.
            updatePersistentRepository(displayId)
        }
    }
@@ -648,6 +682,7 @@ class DesktopRepository(
            // mark it as minimized.
            getDisplayIdForTask(taskId)?.let { minimizeTask(it, taskId) }
                ?: logW("Minimize task: No display id found for task: taskId=%d", taskId)
            return
        } else {
            logD("Minimize Task: display=%d, task=%d", displayId, taskId)
            desktopData.getActiveDesk(displayId)?.minimizedTasks?.add(taskId)
@@ -680,7 +715,7 @@ class DesktopRepository(
    private fun getDisplayIdForTask(taskId: Int): Int? {
        var displayForTask: Int? = null
        desktopData.forAllDesks { displayId, desk ->
            if (taskId in desk.freeformTasksInZOrder) {
            if (taskId in desk.activeTasks) {
                displayForTask = displayId
            }
        }
+118 −15
Original line number Diff line number Diff line
@@ -357,15 +357,15 @@ class DesktopTasksController(
            0 -> return
            // Full screen case
            1 ->
                moveRunningTaskToDesktop(
                    allFocusedTasks.single(),
                moveTaskToDefaultDeskAndActivate(
                    allFocusedTasks.single().taskId,
                    transitionSource = transitionSource,
                )
            // Split-screen case where there are two focused tasks, then we find the child
            // task to move to desktop.
            2 ->
                moveRunningTaskToDesktop(
                    getSplitFocusedTask(allFocusedTasks[0], allFocusedTasks[1]),
                moveTaskToDefaultDeskAndActivate(
                    getSplitFocusedTask(allFocusedTasks[0], allFocusedTasks[1]).taskId,
                    transitionSource = transitionSource,
                )
            else ->
@@ -428,7 +428,7 @@ class DesktopTasksController(

    /** Moves task to desktop mode if task is running, else launches it in desktop mode. */
    @JvmOverloads
    fun moveTaskToDesktop(
    fun moveTaskToDefaultDeskAndActivate(
        taskId: Int,
        wct: WindowContainerTransaction = WindowContainerTransaction(),
        transitionSource: DesktopModeTransitionSource,
@@ -436,7 +436,49 @@ class DesktopTasksController(
        callback: IMoveToDesktopCallback? = null,
    ): Boolean {
        val runningTask = shellTaskOrganizer.getRunningTaskInfo(taskId)
        if (runningTask == null) {
        val backgroundTask = recentTasksController?.findTaskInBackground(taskId)
        if (runningTask == null && backgroundTask == null) {
            logW("moveTaskToDefaultDeskAndActivate taskId=%d not found", taskId)
            return false
        }
        // TODO(342378842): Instead of using default display, support multiple displays
        val displayId = runningTask?.displayId ?: DEFAULT_DISPLAY
        val deskId =
            checkNotNull(taskRepository.getDefaultDeskId(displayId)) {
                "Expected a default desk to exist"
            }
        return moveTaskToDesk(
            taskId = taskId,
            deskId = deskId,
            wct = wct,
            transitionSource = transitionSource,
            remoteTransition = remoteTransition,
        )
    }

    /** Moves task to desktop mode if task is running, else launches it in desktop mode. */
    fun moveTaskToDesk(
        taskId: Int,
        deskId: Int,
        wct: WindowContainerTransaction = WindowContainerTransaction(),
        transitionSource: DesktopModeTransitionSource,
        remoteTransition: RemoteTransition? = null,
        callback: IMoveToDesktopCallback? = null,
    ): Boolean {
        val runningTask = shellTaskOrganizer.getRunningTaskInfo(taskId)
        if (runningTask != null) {
            moveRunningTaskToDesk(
                task = runningTask,
                deskId = deskId,
                wct = wct,
                transitionSource = transitionSource,
                remoteTransition = remoteTransition,
                callback = callback,
            )
        }
        val backgroundTask = recentTasksController?.findTaskInBackground(taskId)
        if (backgroundTask != null) {
            // TODO: b/391484662 - add support for |deskId|.
            return moveBackgroundTaskToDesktop(
                taskId,
                wct,
@@ -445,8 +487,8 @@ class DesktopTasksController(
                callback,
            )
        }
        moveRunningTaskToDesktop(runningTask, wct, transitionSource, remoteTransition, callback)
        return true
        logW("moveTaskToDesk taskId=%d not found", taskId)
        return false
    }

    private fun moveBackgroundTaskToDesktop(
@@ -500,8 +542,9 @@ class DesktopTasksController(
    }

    /** Moves a running task to desktop. */
    fun moveRunningTaskToDesktop(
    private fun moveRunningTaskToDesk(
        task: RunningTaskInfo,
        deskId: Int,
        wct: WindowContainerTransaction = WindowContainerTransaction(),
        transitionSource: DesktopModeTransitionSource,
        remoteTransition: RemoteTransition? = null,
@@ -511,20 +554,49 @@ class DesktopTasksController(
            logW("Cannot enter desktop for taskId %d, ineligible top activity found", task.taskId)
            return
        }
        logV("moveRunningTaskToDesktop taskId=%d", task.taskId)
        val displayId = taskRepository.getDisplayForDesk(deskId)
        logV(
            "moveRunningTaskToDesk taskId=%d deskId=%d displayId=%d",
            task.taskId,
            deskId,
            displayId,
        )
        exitSplitIfApplicable(wct, task)
        val exitResult =
            desktopImmersiveController.exitImmersiveIfApplicable(
                wct = wct,
                displayId = task.displayId,
                displayId = displayId,
                excludeTaskId = task.taskId,
                reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH,
            )

        // Bring other apps to front first
        val taskIdToMinimize =
            if (Flags.enableMultipleDesktopsBackend()) {
                // Activate the desk first.
                prepareForDeskActivation(displayId, wct)
                desksOrganizer.activateDesk(wct, deskId)
                if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) {
                    // TODO: 362720497 - do non-running tasks need to be restarted with
                    // |wct#startTask|?
                }
                taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(
                    doesAnyTaskRequireTaskbarRounding(displayId)
                )
                // TODO: 362720497 - activating a desk with the intention to move a new task to it
                //  means we may need to minimize something in the activating desk. Do so here
                // similar
                //  to how it's done in #bringDesktopAppsToFrontBeforeShowingNewTask instead of
                //  returning null.
                null
            } else {
                // Bring other apps to front first.
                bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, task.taskId)
            }
        if (Flags.enableMultipleDesktopsBackend()) {
            prepareMoveTaskToDesk(wct, task, deskId)
        } else {
            addMoveToDesktopChanges(wct, task)
        }

        val transition: IBinder
        if (remoteTransition != null) {
@@ -543,6 +615,18 @@ class DesktopTasksController(
            addPendingMinimizeTransition(transition, it, MinimizeReason.TASK_LIMIT)
        }
        exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
        if (Flags.enableMultipleDesktopsBackend()) {
            desksTransitionObserver.addPendingTransition(
                DeskTransition.ActiveDeskWithTask(
                    token = transition,
                    displayId = displayId,
                    deskId = deskId,
                    enterTaskId = task.taskId,
                )
            )
        } else {
            taskRepository.setActiveDesk(displayId = displayId, deskId = deskId)
        }
    }

    private fun invokeCallbackToOverview(transition: IBinder, callback: IMoveToDesktopCallback?) {
@@ -2152,6 +2236,7 @@ class DesktopTasksController(
     * different [displayId] if the task should be moved to a different display.
     */
    @VisibleForTesting
    @Deprecated("Deprecated with multiple desks", ReplaceWith("prepareMoveTaskToDesk()"))
    fun addMoveToDesktopChanges(
        wct: WindowContainerTransaction,
        taskInfo: RunningTaskInfo,
@@ -2179,6 +2264,24 @@ class DesktopTasksController(
        }
    }

    private fun prepareMoveTaskToDesk(
        wct: WindowContainerTransaction,
        taskInfo: RunningTaskInfo,
        deskId: Int,
    ) {
        if (!Flags.enableMultipleDesktopsBackend()) return
        val displayId = taskRepository.getDisplayForDesk(deskId)
        val displayLayout = displayController.getDisplayLayout(displayId) ?: return
        val initialBounds = getInitialBounds(displayLayout, taskInfo, displayId)
        if (canChangeTaskPosition(taskInfo)) {
            wct.setBounds(taskInfo.token, initialBounds)
        }
        desksOrganizer.moveTaskToDesk(wct, deskId = deskId, task = taskInfo)
        if (useDesktopOverrideDensity()) {
            wct.setDensityDpi(taskInfo.token, DESKTOP_DENSITY_OVERRIDE)
        }
    }

    /**
     * Apply changes to move a freeform task from one display to another, which includes handling
     * density changes between displays.
@@ -3173,7 +3276,7 @@ class DesktopTasksController(
            callback: IMoveToDesktopCallback?,
        ) {
            executeRemoteCallWithTaskPermission(controller, "moveTaskToDesktop") { c ->
                c.moveTaskToDesktop(
                c.moveTaskToDefaultDeskAndActivate(
                    taskId,
                    transitionSource = transitionSource,
                    remoteTransition = remoteTransition,
+8 −0
Original line number Diff line number Diff line
@@ -34,4 +34,12 @@ sealed class DeskTransition {
    /** A transition to activate a desk in its display. */
    data class ActivateDesk(override val token: IBinder, val displayId: Int, val deskId: Int) :
        DeskTransition()

    /** A transition to activate a desk by moving an outside task to it. */
    data class ActiveDeskWithTask(
        override val token: IBinder,
        val displayId: Int,
        val deskId: Int,
        val enterTaskId: Int,
    ) : DeskTransition()
}
+20 −0
Original line number Diff line number Diff line
@@ -68,6 +68,26 @@ class DesksTransitionObserver(
                    )
                }
            }
            is DeskTransition.ActiveDeskWithTask -> {
                val withTask =
                    info.changes.find { change ->
                        change.taskInfo?.taskId == deskTransition.enterTaskId &&
                            change.taskInfo?.isVisibleRequested == true &&
                            desksOrganizer.getDeskAtEnd(change) == deskTransition.deskId
                    }
                withTask?.let {
                    desktopRepository.setActiveDesk(
                        displayId = deskTransition.displayId,
                        deskId = deskTransition.deskId,
                    )
                    desktopRepository.addTaskToDesk(
                        displayId = deskTransition.displayId,
                        deskId = deskTransition.deskId,
                        taskId = deskTransition.enterTaskId,
                        isVisible = true,
                    )
                }
            }
        }
    }
}
Loading