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

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

Merge "Desks: Remove desk when last task is removed" into main

parents e3e50ef4 275f1636
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -297,6 +297,7 @@ class DesktopPipTransitionController(
                deskId = deskId,
                displayId = displayId,
                willExitDesktop = true,
                removingLastTaskId = taskId,
            )
        desktopExitRunnable?.invoke(transition)
    }
+9 −0
Original line number Diff line number Diff line
@@ -674,6 +674,15 @@ class DesktopRepository(
            .singleOrNull() == taskId
    }

    /**
     * Whether the task is the only task in the desk, regardless of its visibility or minimized
     * state.
     */
    fun isOnlyTaskInDesk(taskId: Int, deskId: Int): Boolean {
        val desk = desktopData.getDesk(deskId) ?: return false
        return desk.activeTasks.size == 1 && desk.activeTasks.single() == taskId
    }

    /** Whether the task is the only visible desktop task in the display. */
    fun isOnlyVisibleTask(taskId: Int, displayId: Int): Boolean {
        val desk = desktopData.getActiveDesk(displayId) ?: return false
+118 −63
Original line number Diff line number Diff line
@@ -540,6 +540,7 @@ class DesktopTasksController(
                deskId = activeDeskIdOnRecentsStart,
                displayId = DEFAULT_DISPLAY,
                willExitDesktop = true,
                removingLastTaskId = null,
                // No need to clean up the wallpaper / home when coming from a recents transition.
                skipWallpaperAndHomeOrdering = true,
                // This is a recents-finish, so taskbar animation on transit start does not apply.
@@ -911,7 +912,7 @@ class DesktopTasksController(
            } else {
                // The disconnected display's active desk was reparented to the back, ensure it is
                // no longer an active launch root.
                prepareDeskDeactivationIfNeeded(wct, disconnectedDisplayActiveDesk)
                addDeskDeactivationChanges(wct, disconnectedDisplayActiveDesk)
            }
        return runOnTransitStart
    }
@@ -1268,13 +1269,20 @@ class DesktopTasksController(
                forceExitDesktop = false,
            )
        val desktopExitRunnable =
            if (shouldExitDesktop) {
                val isLastTask =
                    deskId?.let { taskRepository.isOnlyTaskInDesk(taskInfo.taskId, it) } ?: false
                performDesktopExitCleanUp(
                    wct = wct,
                    deskId = deskId,
                    displayId = displayId,
                willExitDesktop = shouldExitDesktop,
                    willExitDesktop = true,
                    removingLastTaskId = if (isLastTask) taskInfo.taskId else null,
                    shouldEndUpAtHome = true,
                )
            } else {
                null
            }

        taskRepository.addClosingTask(displayId = displayId, deskId = deskId, taskId = taskId)
        taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(
@@ -1385,6 +1393,7 @@ class DesktopTasksController(
                        deskId = deskId,
                        displayId = displayId,
                        willExitDesktop = true,
                        removingLastTaskId = null,
                    )
            }
            val transition = freeformTaskTransitionStarter.startPipTransition(wct)
@@ -1413,6 +1422,7 @@ class DesktopTasksController(
                    deskId = deskId,
                    displayId = displayId,
                    willExitDesktop = willExitDesktop,
                    removingLastTaskId = null,
                )
            // Notify immersive handler as it might need to exit immersive state.
            val exitResult =
@@ -1596,7 +1606,7 @@ class DesktopTasksController(

        // handles case where we are moving to full screen without closing all DW tasks.
        if (
            !taskRepository.isOnlyVisibleNonClosingTask(task.taskId)
            !isOnlyVisibleNonClosingTask(task.taskId, displayId)
            // This callback is already invoked by |addMoveToFullscreenChanges| when this flag is
            // enabled.
            &&
@@ -2005,6 +2015,8 @@ class DesktopTasksController(
        val shouldExitDesktopIfNeeded =
            ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY.isTrue ||
                DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue
        val isLastTask =
            sourceDeskId?.let { taskRepository.isOnlyTaskInDesk(task.taskId, it) } ?: false
        val deactivationRunnable =
            if (shouldExitDesktopIfNeeded) {
                performDesktopExitCleanupIfNeeded(
@@ -2012,6 +2024,7 @@ class DesktopTasksController(
                    deskId = sourceDeskId,
                    displayId = sourceDisplayId,
                    wct = wct,
                    removingLastTaskId = if (isLastTask) task.taskId else null,
                    forceToFullscreen = false,
                )
            } else {
@@ -2080,6 +2093,7 @@ class DesktopTasksController(
                    deskId = activeDeskId,
                    displayId = displayId,
                    willExitDesktop = true,
                    removingLastTaskId = null,
                    shouldEndUpAtHome = false,
                )
            } else {
@@ -2616,16 +2630,15 @@ class DesktopTasksController(
            // explicitly going fullscreen, so there's no point in checking the desktop state.
            return true
        }
        if (ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY.isTrue) {
            if (!taskRepository.isOnlyVisibleNonClosingTask(triggerTaskId, displayId)) {
                return false
        return isOnlyVisibleNonClosingTask(triggerTaskId, displayId)
    }

    private fun isOnlyVisibleNonClosingTask(taskId: Int, displayId: Int): Boolean {
        return if (ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY.isTrue) {
            taskRepository.isOnlyVisibleNonClosingTask(taskId, displayId)
        } else {
            if (!taskRepository.isOnlyVisibleNonClosingTask(triggerTaskId)) {
                return false
            }
            taskRepository.isOnlyVisibleNonClosingTask(taskId)
        }
        return true
    }

    private fun performDesktopExitCleanupIfNeeded(
@@ -2633,6 +2646,7 @@ class DesktopTasksController(
        deskId: Int? = null,
        displayId: Int,
        wct: WindowContainerTransaction,
        removingLastTaskId: Int?,
        forceToFullscreen: Boolean,
    ): RunOnTransitStart? {
        if (!willExitDesktop(taskId, displayId, forceToFullscreen)) {
@@ -2645,6 +2659,7 @@ class DesktopTasksController(
            deskId = deskId,
            displayId = displayId,
            willExitDesktop = true,
            removingLastTaskId = removingLastTaskId,
            shouldEndUpAtHome = true,
        )
    }
@@ -2655,6 +2670,7 @@ class DesktopTasksController(
        deskId: Int?,
        displayId: Int,
        willExitDesktop: Boolean,
        removingLastTaskId: Int?,
        shouldEndUpAtHome: Boolean = true,
        skipWallpaperAndHomeOrdering: Boolean = false,
        skipUpdatingExitDesktopListener: Boolean = false,
@@ -2685,7 +2701,15 @@ class DesktopTasksController(
                addLaunchHomePendingIntent(wct, displayId)
            }
        }
        return prepareDeskDeactivationIfNeeded(wct, deskId)
        val shouldRemoveDesk =
            DesktopExperienceFlags.ENABLE_REMOVE_DESK_ON_LAST_TASK_REMOVAL.isTrue &&
                removingLastTaskId != null &&
                !rootTaskDisplayAreaOrganizer.isDisplayDesktopFirst(displayId)
        return if (shouldRemoveDesk) {
            addDeskRemovalChanges(wct, deskId, displayId, excludingTaskId = removingLastTaskId)
        } else {
            addDeskDeactivationChanges(wct, deskId)
        }
    }

    fun releaseVisualIndicator() {
@@ -3093,6 +3117,7 @@ class DesktopTasksController(
                deskId = activeDeskId,
                displayId = task.displayId,
                willExitDesktop = true,
                removingLastTaskId = null,
                shouldEndUpAtHome = true,
                // No need to clean up the wallpaper / home order if Home is launching directly.
                skipWallpaperAndHomeOrdering = true,
@@ -3486,11 +3511,11 @@ class DesktopTasksController(
            return null
        }
        val wct = WindowContainerTransaction()
        val isLastTask = taskRepository.isOnlyTaskInDesk(task.taskId, task.displayId)
        if (
            DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue &&
                requestType == TRANSIT_TO_BACK
        ) {
            val isLastTask = taskRepository.isOnlyVisibleTask(task.taskId, task.displayId)
            logV(
                "Handling to-back of taskId=%d (isLast=%b) as minimize in deskId=%d",
                task.taskId,
@@ -3515,6 +3540,7 @@ class DesktopTasksController(
                    deskId = deskId,
                    displayId = task.displayId,
                    wct = wct,
                    removingLastTaskId = if (isLastTask) task.taskId else null,
                    forceToFullscreen = false,
                )
            deactivationRunnable?.invoke(transition)
@@ -3715,15 +3741,24 @@ class DesktopTasksController(
                } else {
                    null
                }

        if (willExitDesktop) {
            val isLastTask =
                deskId?.let {
                    userRepositories
                        .getProfile(taskInfo.userId)
                        .isOnlyTaskInDesk(taskInfo.taskId, it)
                } ?: false
            return performDesktopExitCleanUp(
                wct = wct,
                deskId = deskId,
                displayId = displayId,
            willExitDesktop = willExitDesktop,
                willExitDesktop = true,
                removingLastTaskId = if (isLastTask) taskInfo.taskId else null,
                shouldEndUpAtHome = false,
            )
        }
        return null
    }

    private fun cascadeWindow(
        bounds: Rect,
@@ -3953,7 +3988,7 @@ class DesktopTasksController(
                }
        }
        val deactivatingDesk = taskRepository.getActiveDeskId(displayId)?.takeIf { it != deskId }
        val deactivationRunnable = prepareDeskDeactivationIfNeeded(wct, deactivatingDesk)
        val deactivationRunnable = addDeskDeactivationChanges(wct, deactivatingDesk)
        return { transition ->
            val activateDeskTransition =
                if (newTaskIdInFront != null) {
@@ -4148,10 +4183,56 @@ class DesktopTasksController(
        }
    }

    private fun addDeskRemovalChanges(
        wct: WindowContainerTransaction,
        deskId: Int?,
        displayId: Int,
        excludingTaskId: Int? = null,
        repository: DesktopRepository = taskRepository,
    ): RunOnTransitStart? {
        if (deskId == null) return null
        val tasksToRemove =
            if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
                val activeTaskIdsInDesk = repository.getActiveTaskIdsInDesk(deskId)
                if (DesktopExperienceFlags.ENABLE_REMOVE_DESK_ON_LAST_TASK_REMOVAL.isTrue) {
                    activeTaskIdsInDesk.filterNot { taskId -> taskId == excludingTaskId }.toSet()
                } else {
                    activeTaskIdsInDesk
                }
            } else {
                repository.removeDesk(deskId)
            }
        tasksToRemove.forEach {
            // TODO: b/404595635 - consider moving this block into [DesksOrganizer].
            val task = shellTaskOrganizer.getRunningTaskInfo(it)
            if (task != null) {
                wct.removeTask(task.token)
            } else {
                recentTasksController?.removeBackgroundTask(it)
            }
        }
        if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            desksOrganizer.removeDesk(wct, deskId, userId)
            return { transition ->
                desksTransitionObserver.addPendingTransition(
                    DeskTransition.RemoveDesk(
                        token = transition,
                        displayId = displayId,
                        deskId = deskId,
                        tasks = tasksToRemove,
                        onDeskRemovedListener = onDeskRemovedListener,
                        runOnTransitEnd = { snapEventHandler.onDeskRemoved(deskId) },
                    )
                )
            }
        }
        return null
    }

    /**
     * TODO: b/393978539 - Deactivation should not happen in desktop-first devices when going home.
     */
    private fun prepareDeskDeactivationIfNeeded(
    private fun addDeskDeactivationChanges(
        wct: WindowContainerTransaction,
        deskId: Int?,
    ): RunOnTransitStart? {
@@ -4234,43 +4315,17 @@ class DesktopTasksController(
    ) {
        if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue()) return
        logV("removeDesk deskId=%d from displayId=%d", deskId, displayId)

        val tasksToRemove =
            if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
                desktopRepository.getActiveTaskIdsInDesk(deskId)
            } else {
                // TODO: 362720497 - make sure minimized windows are also removed in WM
                //  and the repository.
                desktopRepository.removeDesk(deskId)
            }

        val wct = WindowContainerTransaction()
        tasksToRemove.forEach {
            // TODO: b/404595635 - consider moving this block into [DesksOrganizer].
            val task = shellTaskOrganizer.getRunningTaskInfo(it)
            if (task != null) {
                wct.removeTask(task.token)
            } else {
                recentTasksController?.removeBackgroundTask(it)
            }
        }
        if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            desksOrganizer.removeDesk(wct, deskId, userId)
        }
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue && wct.isEmpty) return
        val transition = transitions.startTransition(TRANSIT_CLOSE, wct, /* handler= */ null)
        if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            desksTransitionObserver.addPendingTransition(
                DeskTransition.RemoveDesk(
                    token = transition,
                    displayId = displayId,
        val runOnTransitStart =
            addDeskRemovalChanges(
                wct = wct,
                deskId = deskId,
                    tasks = tasksToRemove,
                    onDeskRemovedListener = onDeskRemovedListener,
                    runOnTransitEnd = { snapEventHandler.onDeskRemoved(deskId) },
                )
                displayId = displayId,
                repository = desktopRepository,
            )
        }
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue && wct.isEmpty) return
        val transition = transitions.startTransition(TRANSIT_CLOSE, wct, /* handler= */ null)
        runOnTransitStart?.invoke(transition)
    }

    /** Enter split by using the focused desktop task in given `displayId`. */
+0 −2
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ import android.app.ActivityTaskManager.INVALID_TASK_ID
import android.os.IBinder
import android.view.Display.INVALID_DISPLAY
import android.view.WindowManager.TRANSIT_CHANGE
import android.view.WindowManager.TRANSIT_CLOSE
import android.view.WindowManager.TRANSIT_TO_BACK
import android.view.WindowManager.TRANSIT_TO_FRONT
import android.window.DesktopExperienceFlags
@@ -127,7 +126,6 @@ class DesksTransitionObserver(
        val desktopRepository = desktopUserRepositories.current
        when (deskTransition) {
            is DeskTransition.RemoveDesk -> {
                check(info.type == TRANSIT_CLOSE) { "Expected close transition for desk removal" }
                // TODO: b/362720497 - consider verifying the desk was actually removed through the
                //  DesksOrganizer. The transition info won't have changes if the desk was not
                //  visible, such as when dismissing from Overview.
+11 −1
Original line number Diff line number Diff line
@@ -299,10 +299,20 @@ class DesktopPipTransitionControllerTest(flags: FlagsParameterization) : ShellTe
                    deskId = DESK_ID,
                    displayId = DEFAULT_DISPLAY,
                    willExitDesktop = true,
                    removingLastTaskId = taskInfo.taskId,
                )
        } else {
            verify(mockDesktopTasksController, never())
                .performDesktopExitCleanUp(any(), anyOrNull(), any(), any(), any(), any(), any())
                .performDesktopExitCleanUp(
                    wct = any(),
                    deskId = anyOrNull(),
                    displayId = any(),
                    willExitDesktop = any(),
                    removingLastTaskId = anyOrNull(),
                    shouldEndUpAtHome = any(),
                    skipWallpaperAndHomeOrdering = any(),
                    skipUpdatingExitDesktopListener = any(),
                )
        }
    }

Loading