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

Commit fd2f2cdd authored by Orhan Uysal's avatar Orhan Uysal
Browse files

Handle minimized tasks on reboot.

- Add minimized tasks to repository on reboot.
- Find the correct task to minimize in bringDesktopAppsToFront when moving to
  desktop after a reboot.
- Refactor DesktopTaskLimiter to work on taskIds rather than running
  tasks.

Fix: 365725441
Fix: 365497269
Test: atest DesktopTasksControllerTest
Test: atest DesktopModeTasksRepositoryTest
Test: atest DesktopTasksLimiterTest
Flag: com.android.window.flags.enable_desktop_windowing_persistence
Change-Id: I96ca750846e7158e9f6b5353ac526aa48ca0964c
parent fd042f14
Loading
Loading
Loading
Loading
+14 −9
Original line number Diff line number Diff line
@@ -129,19 +129,24 @@ class DesktopRepository (
                DesktopModeStatus.getMaxTaskLimit(context).takeIf { it > 0 }
                    ?: desktop.zOrderedTasksCount

            var visibleTasksCount = 0
            desktop.zOrderedTasksList
                // Reverse it so we initialize the repo from bottom to top.
                .reversed()
                .mapNotNull { taskId ->
                    desktop.tasksByTaskIdMap[taskId]?.takeIf {
                        it.desktopTaskState == DesktopTaskState.VISIBLE
                    }
                }
                .take(maxTasks)
                .mapNotNull { taskId -> desktop.tasksByTaskIdMap[taskId] }
                .forEach { task ->
                    if (task.desktopTaskState == DesktopTaskState.VISIBLE
                        && visibleTasksCount < maxTasks
                    ) {
                        visibleTasksCount++
                        addOrMoveFreeformTaskToTop(desktop.displayId, task.taskId)
                        addActiveTask(desktop.displayId, task.taskId)
                        updateTaskVisibility(desktop.displayId, task.taskId, visible = false)
                    } else {
                        addActiveTask(desktop.displayId, task.taskId)
                        updateTaskVisibility(desktop.displayId, task.taskId, visible = false)
                        minimizeTask(desktop.displayId, task.taskId)
                    }
                }
        }
    }
+36 −32
Original line number Diff line number Diff line
@@ -373,7 +373,7 @@ class DesktopTasksController(
        }
        logV("moveBackgroundTaskToDesktop with taskId=%d", taskId)
        // TODO(342378842): Instead of using default display, support multiple displays
        val taskToMinimize = bringDesktopAppsToFrontBeforeShowingNewTask(
        val taskIdToMinimize = bringDesktopAppsToFrontBeforeShowingNewTask(
            DEFAULT_DISPLAY, wct, taskId)
        val runOnTransit = desktopImmersiveController.exitImmersiveIfApplicable(
            wct = wct,
@@ -388,7 +388,7 @@ class DesktopTasksController(
        )
        // TODO(343149901): Add DPI changes for task launch
        val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource)
        addPendingMinimizeTransition(transition, taskToMinimize)
        taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
        runOnTransit?.invoke(transition)
        return true
    }
@@ -412,12 +412,12 @@ class DesktopTasksController(
            excludeTaskId = task.taskId,
        )
        // Bring other apps to front first
        val taskToMinimize =
        val taskIdToMinimize =
            bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, task.taskId)
        addMoveToDesktopChanges(wct, task)

        val transition = enterDesktopTaskTransitionHandler.moveToDesktop(wct, transitionSource)
        addPendingMinimizeTransition(transition, taskToMinimize)
        taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
        runOnTransit?.invoke(transition)
    }

@@ -452,14 +452,14 @@ class DesktopTasksController(
        val wct = WindowContainerTransaction()
        exitSplitIfApplicable(wct, taskInfo)
        moveHomeTask(wct, toTop = true)
        val taskToMinimize =
        val taskIdToMinimize =
            bringDesktopAppsToFrontBeforeShowingNewTask(taskInfo.displayId, wct, taskInfo.taskId)
        addMoveToDesktopChanges(wct, taskInfo)
        val runOnTransit = desktopImmersiveController.exitImmersiveIfApplicable(
            wct, taskInfo.displayId)
        val transition = dragToDesktopTransitionHandler.finishDragToDesktopTransition(wct)
        transition?.let {
            addPendingMinimizeTransition(it, taskToMinimize)
            taskIdToMinimize?.let { taskId -> addPendingMinimizeTransition(it, taskId) }
            runOnTransit?.invoke(transition)
        }
    }
@@ -651,7 +651,13 @@ class DesktopTasksController(
            excludeTaskId = taskInfo.taskId,
        )
        val transition =
            startLaunchTransition(TRANSIT_TO_FRONT, wct, taskInfo.taskId, remoteTransition)
            startLaunchTransition(
                TRANSIT_TO_FRONT,
                wct,
                taskInfo.taskId,
                remoteTransition,
                taskInfo.displayId
            )
        runOnTransit?.invoke(transition)
    }

@@ -660,15 +666,15 @@ class DesktopTasksController(
        wct: WindowContainerTransaction,
        taskId: Int,
        remoteTransition: RemoteTransition?,
        displayId: Int = DEFAULT_DISPLAY,
    ): IBinder {
        val taskToMinimize: RunningTaskInfo? =
            addAndGetMinimizeChanges(DEFAULT_DISPLAY, wct, taskId)
        val taskIdToMinimize = addAndGetMinimizeChanges(displayId, wct, taskId)
        if (remoteTransition == null) {
            val t = transitions.startTransition(transitionType, wct, null /* handler */)
            addPendingMinimizeTransition(t, taskToMinimize)
            taskIdToMinimize?.let { addPendingMinimizeTransition(t, it) }
            return t
        }
        if (taskToMinimize == null) {
        if (taskIdToMinimize == null) {
            val remoteTransitionHandler = OneShotRemoteHandler(mainExecutor, remoteTransition)
            val t = transitions.startTransition(transitionType, wct, remoteTransitionHandler)
            remoteTransitionHandler.setTransition(t)
@@ -676,10 +682,10 @@ class DesktopTasksController(
        }
        val remoteTransitionHandler =
            DesktopWindowLimitRemoteHandler(
                mainExecutor, rootTaskDisplayAreaOrganizer, remoteTransition, taskToMinimize.taskId)
                mainExecutor, rootTaskDisplayAreaOrganizer, remoteTransition, taskIdToMinimize)
        val t = transitions.startTransition(transitionType, wct, remoteTransitionHandler)
        remoteTransitionHandler.setTransition(t)
        addPendingMinimizeTransition(t, taskToMinimize)
        taskIdToMinimize?.let { addPendingMinimizeTransition(t, it) }
        return t
    }

@@ -1032,13 +1038,13 @@ class DesktopTasksController(
        displayId: Int,
        wct: WindowContainerTransaction,
        newTaskIdInFront: Int
    ): RunningTaskInfo? = bringDesktopAppsToFront(displayId, wct, newTaskIdInFront)
    ): Int? = bringDesktopAppsToFront(displayId, wct, newTaskIdInFront)

    private fun bringDesktopAppsToFront(
        displayId: Int,
        wct: WindowContainerTransaction,
        newTaskIdInFront: Int? = null
    ): RunningTaskInfo? {
    ): Int? {
        logV("bringDesktopAppsToFront, newTaskId=%d", newTaskIdInFront)
        // Move home to front, ensures that we go back home when all desktop windows are closed
        moveHomeTask(wct, toTop = true)
@@ -1054,11 +1060,10 @@ class DesktopTasksController(
            taskRepository.getExpandedTasksOrdered(displayId)
        // If we're adding a new Task we might need to minimize an old one
        // TODO(b/365725441): Handle non running task minimization
        val taskToMinimize: RunningTaskInfo? =
        val taskIdToMinimize: Int? =
            if (newTaskIdInFront != null && desktopTasksLimiter.isPresent) {
                desktopTasksLimiter
                    .get()
                    .getTaskToMinimize(
                desktopTasksLimiter.get()
                    .getTaskIdToMinimize(
                        expandedTasksOrderedFrontToBack,
                        newTaskIdInFront
                    )
@@ -1068,7 +1073,7 @@ class DesktopTasksController(

        expandedTasksOrderedFrontToBack
            // If there is a Task to minimize, let it stay behind the Home Task
            .filter { taskId -> taskId != taskToMinimize?.taskId }
            .filter { taskId -> taskId != taskIdToMinimize }
            .reversed() // Start from the back so the front task is brought forward last
            .forEach { taskId ->
                val runningTaskInfo = shellTaskOrganizer.getRunningTaskInfo(taskId)
@@ -1089,7 +1094,7 @@ class DesktopTasksController(
        taskbarDesktopTaskListener?.
            onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding(displayId))

        return taskToMinimize
        return taskIdToMinimize
    }

    private fun moveHomeTask(wct: WindowContainerTransaction, toTop: Boolean) {
@@ -1341,7 +1346,7 @@ class DesktopTasksController(
        val options = createNewWindowOptions(callingTask)
        if (options.launchWindowingMode == WINDOWING_MODE_FREEFORM) {
            wct.startTask(requestedTaskId, options.toBundle())
            val taskToMinimize = bringDesktopAppsToFrontBeforeShowingNewTask(
            val taskIdToMinimize = bringDesktopAppsToFrontBeforeShowingNewTask(
                callingTask.displayId, wct, requestedTaskId)
            val runOnTransit = desktopImmersiveController.exitImmersiveIfApplicable(
                wct = wct,
@@ -1349,7 +1354,7 @@ class DesktopTasksController(
                excludeTaskId = requestedTaskId,
            )
            val transition = transitions.startTransition(TRANSIT_OPEN, wct, null)
            addPendingMinimizeTransition(transition, taskToMinimize)
            taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
            runOnTransit?.invoke(transition)
        } else {
            val splitPosition = splitScreenController.determineNewInstancePosition(callingTask)
@@ -1489,9 +1494,9 @@ class DesktopTasksController(
        // 1) Exit immersive if needed.
        desktopImmersiveController.exitImmersiveIfApplicable(transition, wct, task.displayId)
        // 2) minimize a Task if needed.
        val taskToMinimize = addAndGetMinimizeChanges(task.displayId, wct, task.taskId)
        if (taskToMinimize != null) {
            addPendingMinimizeTransition(transition, taskToMinimize)
        val taskIdToMinimize = addAndGetMinimizeChanges(task.displayId, wct, task.taskId)
        if (taskIdToMinimize != null) {
            addPendingMinimizeTransition(transition, taskIdToMinimize)
            return wct
        }
        return if (wct.isEmpty) null else wct
@@ -1515,9 +1520,8 @@ class DesktopTasksController(

                // Desktop Mode is already showing and we're launching a new Task - we might need to
                // minimize another Task.
                val taskToMinimize =
                    addAndGetMinimizeChanges(task.displayId, wct, task.taskId)
                addPendingMinimizeTransition(transition, taskToMinimize)
                val taskIdToMinimize = addAndGetMinimizeChanges(task.displayId, wct, task.taskId)
                taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
                desktopImmersiveController.exitImmersiveIfApplicable(
                    transition, wct, task.displayId
                )
@@ -1683,7 +1687,7 @@ class DesktopTasksController(
        displayId: Int,
        wct: WindowContainerTransaction,
        newTaskId: Int
    ): RunningTaskInfo? {
    ): Int? {
        if (!desktopTasksLimiter.isPresent) return null
        return desktopTasksLimiter
            .get()
@@ -1692,9 +1696,9 @@ class DesktopTasksController(

    private fun addPendingMinimizeTransition(
        transition: IBinder,
        taskToMinimize: RunningTaskInfo?
        taskIdToMinimize: Int,
    ) {
        if (taskToMinimize == null) return
        val taskToMinimize = shellTaskOrganizer.getRunningTaskInfo(taskIdToMinimize) ?: return
        desktopTasksLimiter.ifPresent {
            it.addPendingMinimizeChange(transition, taskToMinimize.displayId, taskToMinimize.taskId)
        }
+29 −26
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.wm.shell.desktopmode

import android.app.ActivityManager.RunningTaskInfo
import android.content.Context
import android.os.Handler
import android.os.IBinder
@@ -190,17 +189,19 @@ class DesktopTasksLimiter (
            displayId: Int,
            wct: WindowContainerTransaction,
            newFrontTaskId: Int,
    ): RunningTaskInfo? {
    ): Int? {
        logV("addAndGetMinimizeTaskChanges, newFrontTask=%d", newFrontTaskId)
        // This list is ordered from front to back.
        val newTaskOrderedList = createOrderedTaskListWithNewTask(
            taskRepository.getExpandedTasksOrdered(displayId), newFrontTaskId)
        val taskToMinimize = getTaskToMinimize(newTaskOrderedList)
        if (taskToMinimize != null) {
            wct.reorder(taskToMinimize.token, false /* onTop */)
            return taskToMinimize

        val taskIdToMinimize =
            getTaskIdToMinimize(
                taskRepository.getExpandedTasksOrdered(displayId),
                newFrontTaskId
            )
        // If it's a running task, reorder it to back.
        taskIdToMinimize?.let { shellTaskOrganizer.getRunningTaskInfo(it) }?.let {
            wct.reorder(it.token, false /* onTop */)
        }
        return null
        return taskIdToMinimize
    }

    /**
@@ -216,31 +217,33 @@ class DesktopTasksLimiter (
     * Returns the minimized task from the list of visible tasks ordered from front to back with
     * the new task placed in front of other tasks.
     */
    fun getTaskToMinimize(
    fun getTaskIdToMinimize(
            visibleOrderedTasks: List<Int>,
            newTaskIdInFront: Int
    ): RunningTaskInfo? =
        getTaskToMinimize(createOrderedTaskListWithNewTask(visibleOrderedTasks, newTaskIdInFront))
            newTaskIdInFront: Int? = null
    ): Int? {
        return getTaskIdToMinimize(
            createOrderedTaskListWithGivenTaskInFront(
                visibleOrderedTasks, newTaskIdInFront))
    }

    /** Returns the Task to minimize given a list of visible tasks ordered from front to back. */
    fun getTaskToMinimize(visibleOrderedTasks: List<Int>): RunningTaskInfo? {
    private fun getTaskIdToMinimize(visibleOrderedTasks: List<Int>): Int? {
        if (visibleOrderedTasks.size <= maxTasksLimit) {
            logV("No need to minimize; tasks below limit")
            // No need to minimize anything
            return null
        }
        val taskIdToMinimize = visibleOrderedTasks.last()
        val taskToMinimize =
                shellTaskOrganizer.getRunningTaskInfo(taskIdToMinimize)
        if (taskToMinimize == null) {
            logE("taskToMinimize(taskId = %d) == null", taskIdToMinimize)
            return null
        }
        return taskToMinimize
        return visibleOrderedTasks.last()
    }

    private fun createOrderedTaskListWithNewTask(
        orderedTaskIds: List<Int>, newTaskId: Int): List<Int> =
            listOf(newTaskId) + orderedTaskIds.filter { taskId -> taskId != newTaskId }
    private fun createOrderedTaskListWithGivenTaskInFront(
            existingTaskIdsOrderedFrontToBack: List<Int>,
            newTaskId: Int?
    ): List<Int> {
        return if (newTaskId == null) existingTaskIdsOrderedFrontToBack
        else listOf(newTaskId) +
                existingTaskIdsOrderedFrontToBack.filter { taskId -> taskId != newTaskId }
    }

    @VisibleForTesting
    fun getTransitionObserver(): TransitionObserver = minimizeTransitionObserver
+8 −8
Original line number Diff line number Diff line
@@ -329,7 +329,7 @@ class DesktopTasksLimiterTest : ShellTestCase() {
                        wct = wct,
                        newFrontTaskId = setUpFreeformTask().taskId)

        assertThat(minimizedTaskId).isEqualTo(tasks.first())
        assertThat(minimizedTaskId).isEqualTo(tasks.first().taskId)
        assertThat(wct.hierarchyOps.size).isEqualTo(1)
        assertThat(wct.hierarchyOps[0].type).isEqualTo(HIERARCHY_OP_TYPE_REORDER)
        assertThat(wct.hierarchyOps[0].toTop).isFalse() // Reorder to bottom
@@ -355,7 +355,7 @@ class DesktopTasksLimiterTest : ShellTestCase() {
    fun getTaskToMinimize_tasksWithinLimit_returnsNull() {
        val tasks = (1..MAX_TASK_LIMIT).map { setUpFreeformTask() }

        val minimizedTask = desktopTasksLimiter.getTaskToMinimize(
        val minimizedTask = desktopTasksLimiter.getTaskIdToMinimize(
                visibleOrderedTasks = tasks.map { it.taskId })

        assertThat(minimizedTask).isNull()
@@ -365,11 +365,11 @@ class DesktopTasksLimiterTest : ShellTestCase() {
    fun getTaskToMinimize_tasksAboveLimit_returnsBackTask() {
        val tasks = (1..MAX_TASK_LIMIT + 1).map { setUpFreeformTask() }

        val minimizedTask = desktopTasksLimiter.getTaskToMinimize(
        val minimizedTask = desktopTasksLimiter.getTaskIdToMinimize(
                visibleOrderedTasks = tasks.map { it.taskId })

        // first == front, last == back
        assertThat(minimizedTask).isEqualTo(tasks.last())
        assertThat(minimizedTask).isEqualTo(tasks.last().taskId)
    }

    @Test
@@ -379,23 +379,23 @@ class DesktopTasksLimiterTest : ShellTestCase() {
                interactionJankMonitor, mContext, handler)
        val tasks = (1..MAX_TASK_LIMIT2 + 1).map { setUpFreeformTask() }

        val minimizedTask = desktopTasksLimiter.getTaskToMinimize(
        val minimizedTask = desktopTasksLimiter.getTaskIdToMinimize(
            visibleOrderedTasks = tasks.map { it.taskId })

        // first == front, last == back
        assertThat(minimizedTask).isEqualTo(tasks.last())
        assertThat(minimizedTask).isEqualTo(tasks.last().taskId)
    }

    @Test
    fun getTaskToMinimize_withNewTask_tasksAboveLimit_returnsBackTask() {
        val tasks = (1..MAX_TASK_LIMIT).map { setUpFreeformTask() }

        val minimizedTask = desktopTasksLimiter.getTaskToMinimize(
        val minimizedTask = desktopTasksLimiter.getTaskIdToMinimize(
                visibleOrderedTasks = tasks.map { it.taskId },
                newTaskIdInFront = setUpFreeformTask().taskId)

        // first == front, last == back
        assertThat(minimizedTask).isEqualTo(tasks.last())
        assertThat(minimizedTask).isEqualTo(tasks.last().taskId)
    }

    @Test