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

Commit 48ea9ec9 authored by Matt Sziklay's avatar Matt Sziklay Committed by Android (Google) Code Review
Browse files

Merge "[3/N] Store freeform bounds on disconnect." into main

parents d2503c2d 6e064766
Loading
Loading
Loading
Loading
+22 −2
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import com.android.wm.shell.desktopmode.desktopfirst.isDisplayDesktopFirst
import com.android.wm.shell.desktopmode.multidesks.DesksOrganizer
import com.android.wm.shell.desktopmode.multidesks.DesksTransitionObserver
import com.android.wm.shell.desktopmode.multidesks.OnDeskRemovedListener
import com.android.wm.shell.desktopmode.multidesks.PreserveDisplayRequestHandler
import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
import com.android.wm.shell.shared.desktopmode.DesktopState
@@ -59,13 +60,17 @@ class DesktopDisplayEventHandler(
    private val desktopDisplayModeController: DesktopDisplayModeController,
    private val desksTransitionObserver: DesksTransitionObserver,
    private val desktopState: DesktopState,
) : OnDisplaysChangedListener, OnDeskRemovedListener {
) : OnDisplaysChangedListener, OnDeskRemovedListener, PreserveDisplayRequestHandler {

    private val onDisplayAreaChangeListener = OnDisplayAreaChangeListener { displayId ->
        logV("displayAreaChanged in displayId=%d", displayId)
        createDefaultDesksIfNeeded(displayIds = listOf(displayId), userId = null)
    }

    // Mapping of display uniqueIds to displayId. Used to match a disconnected
    // displayId to its uniqueId since we will not be able to fetch it after disconnect.
    private val uniqueIdByDisplayId = mutableMapOf<Int, String>()

    init {
        shellInit.addInitCallback({ onInit() }, this)
    }
@@ -84,6 +89,7 @@ class DesktopDisplayEventHandler(
                    }
                }
            )
            desktopTasksController.preserveDisplayRequestHandler = this
        }
    }

@@ -97,6 +103,13 @@ class DesktopDisplayEventHandler(
            // display. So updating the default display's windowing mode here.
            desktopDisplayModeController.updateDefaultDisplayWindowingMode()
        }
        if (DesktopExperienceFlags.ENABLE_DISPLAY_RECONNECT_INTERACTION.isTrue) {
            // TODO - b/365873835: Restore a display if a uniqueId match is found in
            //  the desktop repository.
            displayController.getDisplay(displayId)?.uniqueId?.let { uniqueId ->
                uniqueIdByDisplayId[displayId] = uniqueId
            }
        }
    }

    override fun onDisplayRemoved(displayId: Int) {
@@ -106,7 +119,14 @@ class DesktopDisplayEventHandler(
        if (displayId != DEFAULT_DISPLAY) {
            desktopDisplayModeController.updateDefaultDisplayWindowingMode()
        }
        // TODO(b/391652399): store a persisted DesktopDisplay in DesktopRepository
        uniqueIdByDisplayId.remove(displayId)
    }

    override fun requestPreserveDisplay(displayId: Int) {
        logV("requestPreserveDisplay displayId=%d", displayId)
        val uniqueId = uniqueIdByDisplayId.remove(displayId) ?: return
        // TODO: b/365873835 - Preserve/restore bounds for other repositories.
        desktopUserRepositories.current.preserveDisplay(displayId, uniqueId)
    }

    override fun onDesktopModeEligibleChanged(displayId: Int) {
+101 −24
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ class DesktopRepository(
    private data class Desk(
        val deskId: Int,
        var displayId: Int,
        // TODO: b/421928445 - Refactor these and boundsByTaskId into a new data class.
        val activeTasks: ArraySet<Int> = ArraySet(),
        val visibleTasks: ArraySet<Int> = ArraySet(),
        val minimizedTasks: ArraySet<Int> = ArraySet(),
@@ -92,6 +93,12 @@ class DesktopRepository(
        var leftTiledTaskId: Int? = null,
        var rightTiledTaskId: Int? = null,
    ) {
        // TODO: b/417907552 - Add these variables to persistent repository.
        // The display's unique id that will remain the same across reboots.
        var uniqueDisplayId: String? = null
        // Bounds of tasks in this desk mapped to their respective task ids. Used for reconnect.
        var boundsByTaskId: MutableMap<Int, Rect> = mutableMapOf()

        fun deepCopy(): Desk =
            Desk(
                    deskId = deskId,
@@ -106,6 +113,10 @@ class DesktopRepository(
                    leftTiledTaskId = leftTiledTaskId,
                    rightTiledTaskId = rightTiledTaskId,
                )
                .also {
                    it.uniqueDisplayId = uniqueDisplayId
                    it.boundsByTaskId = boundsByTaskId.toMutableMap()
                }

        // TODO: b/362720497 - remove when multi-desktops is enabled where instances aren't
        //  reusable.
@@ -119,6 +130,7 @@ class DesktopRepository(
            topTransparentFullscreenTaskData = null
            leftTiledTaskId = null
            rightTiledTaskId = null
            boundsByTaskId.clear()
        }
    }

@@ -141,6 +153,9 @@ class DesktopRepository(
    private var desktopGestureExclusionListener: Consumer<Region>? = null
    private var desktopGestureExclusionExecutor: Executor? = null

    // TODO - b/365873835: Add this to persistent repository.
    private val preservedDisplaysByUniqueId = ArrayMap<String, DesktopDisplay>()

    private val desktopData: DesktopData =
        if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            MultiDesktopData()
@@ -178,6 +193,33 @@ class DesktopRepository(
        activeTasksListeners.onEach { it.onActiveTasksChanged(displayId) }
    }

    /** Stores the last state of the given display, along with the bounds of the tasks on it. */
    fun preserveDisplay(displayId: Int, uniqueId: String) {
        val orderedDesks = desktopData.getOrderedDesks(displayId)
        // Do not preserve the display if there are no active tasks on it.
        if (!orderedDesks.any { it.activeTasks.isNotEmpty() }) return
        val preservedDisplay = DesktopDisplay(displayId)
        orderedDesks.mapTo(preservedDisplay.orderedDesks) { it.deepCopy() }
        preservedDisplay.activeDeskId = desktopData.getActiveDesk(displayId)?.deskId
        preservedDisplaysByUniqueId[uniqueId] = preservedDisplay
    }

    /** Returns the bounds of all tasks in all desks of the preserved display. */
    @VisibleForTesting
    fun getPreservedTaskBounds(uniqueDisplayId: String): Map<Int, Rect> {
        val combinedBoundsMap = mutableMapOf<Int, Rect>()
        val orderedDesks =
            preservedDisplaysByUniqueId[uniqueDisplayId]?.orderedDesks ?: return emptyMap()
        for (desk in orderedDesks) {
            combinedBoundsMap.putAll(desk.boundsByTaskId)
        }
        return combinedBoundsMap
    }

    @VisibleForTesting
    fun getPreservedDeskIds(uniqueDisplayId: String): List<Int> =
        preservedDisplaysByUniqueId[uniqueDisplayId]?.orderedDesks?.map { it.deskId } ?: emptyList()

    /** Returns a list of all [Desk]s in the repository. */
    private fun desksSequence(): Sequence<Desk> = desktopData.desksSequence()

@@ -411,22 +453,41 @@ class DesktopRepository(
     *
     * TODO: b/389960283 - add explicit [deskId] argument.
     */
    fun addTask(displayId: Int, taskId: Int, isVisible: Boolean) {
        logD("addTask for displayId=%d, taskId=%d, isVisible=%b", displayId, taskId, isVisible)
    fun addTask(displayId: Int, taskId: Int, isVisible: Boolean, taskBounds: Rect) {
        logD(
            "addTask for displayId=%d, taskId=%d, isVisible=%b," + "taskBounds=%s",
            displayId,
            taskId,
            isVisible,
            taskBounds,
        )
        val activeDesk =
            checkNotNull(desktopData.getDefaultDesk(displayId)) {
                "Expected desk in display: $displayId"
            }
        addTaskToDesk(displayId = displayId, deskId = activeDesk.deskId, taskId = taskId, isVisible)
        addTaskToDesk(
            displayId = displayId,
            deskId = activeDesk.deskId,
            taskId = taskId,
            isVisible = isVisible,
            taskBounds = taskBounds,
        )
    }

    fun addTaskToDesk(displayId: Int, deskId: Int, taskId: Int, isVisible: Boolean) {
    fun addTaskToDesk(
        displayId: Int,
        deskId: Int,
        taskId: Int,
        isVisible: Boolean,
        taskBounds: Rect?,
    ) {
        logD(
            "addTaskToDesk for displayId=%d, deskId=%d, taskId=%d, isVisible=%b",
            "addTaskToDesk for displayId=%d, deskId=%d, taskId=%d, isVisible=%b, taskBounds=%s",
            displayId,
            deskId,
            taskId,
            isVisible,
            taskBounds,
        )
        if (deskId == taskId) {
            Slog.e(TAG, "Adding desk to itself: deskId=$deskId", Exception())
@@ -438,6 +499,7 @@ class DesktopRepository(
            deskId = deskId,
            taskId = taskId,
            isVisible = isVisible,
            taskBounds = taskBounds,
        )
    }

@@ -674,7 +736,7 @@ class DesktopRepository(
     *
     * TODO: b/389960283 - add explicit [deskId] argument.
     */
    fun updateTask(displayId: Int, taskId: Int, isVisible: Boolean) {
    fun updateTask(displayId: Int, taskId: Int, isVisible: Boolean, taskBounds: Rect?) {
        val validDisplayId =
            if (displayId == INVALID_DISPLAY) {
                // When a task vanishes it doesn't have a displayId. Find the display of the task.
@@ -694,18 +756,26 @@ class DesktopRepository(
            displayId = validDisplayId,
            deskId = desk.deskId,
            taskId = taskId,
            isVisible,
            isVisible = isVisible,
            taskBounds = taskBounds,
        )
    }

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

        if (isVisible) {
@@ -720,6 +790,7 @@ class DesktopRepository(
        } else {
            desk.visibleTasks.remove(taskId)
        }
        taskBounds?.let { desk.boundsByTaskId[taskId] = it }
        val newCount = getVisibleTaskCountInDesk(deskId)
        if (prevCount != newCount) {
            logD(
@@ -855,8 +926,13 @@ class DesktopRepository(
     */
    private fun addOrMoveTaskToTopOfDesk(displayId: Int, deskId: Int, taskId: Int) {
        val desk = desktopData.getDesk(deskId) ?: error("Could not find desk: $deskId")
        desktopData.forAllDesks { _, desk1 -> desk1.freeformTasksInZOrder.remove(taskId) }
        val bounds = Rect()
        desktopData.forAllDesks { _, desk1 ->
            desk1.freeformTasksInZOrder.remove(taskId)
            desk1.boundsByTaskId[taskId]?.let { bounds.set(it) }
        }
        desk.freeformTasksInZOrder.add(0, taskId)
        if (!bounds.isEmpty) desk.boundsByTaskId[taskId] = bounds
        if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) {
            // TODO: can probably just update the desk.
            updatePersistentRepository(displayId)
@@ -890,7 +966,7 @@ class DesktopRepository(
        logD("MinimizeTaskInDesk: displayId=%d deskId=%d, task=%d", displayId, deskId, taskId)
        desktopData.getDesk(deskId)?.minimizedTasks?.add(taskId)
            ?: logD("Minimize task: No active desk found for task: taskId=%d", taskId)
        updateTaskInDesk(displayId, deskId, taskId, isVisible = false)
        updateTaskInDesk(displayId, deskId, taskId, isVisible = false, taskBounds = null)
        if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) {
            updatePersistentRepositoryForDesk(deskId)
        }
@@ -955,6 +1031,7 @@ class DesktopRepository(
        boundsBeforeFullImmersiveByTaskId.remove(taskId)
        val desk = desktopData.getDesk(deskId) ?: return
        if (desk.freeformTasksInZOrder.remove(taskId)) {
            desk.boundsByTaskId.remove(taskId)
            logD(
                "Remaining freeform tasks in desk: %d, tasks: %s",
                desk.deskId,
@@ -1420,7 +1497,7 @@ class DesktopRepository(
        }

        override fun getOrderedDesks(displayId: Int): List<Desk> =
            desktopDisplays[displayId].orderedDesks.toList()
            desktopDisplays[displayId]?.orderedDesks?.toList() ?: emptyList()

        override fun getAllActiveDesks(): Set<Desk> {
            return desktopDisplays
+30 −5
Original line number Diff line number Diff line
@@ -54,7 +54,12 @@ class DesktopTaskChangeListener(
                )
                return
            }
            desktopRepository.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible)
            desktopRepository.addTask(
                taskInfo.displayId,
                taskInfo.taskId,
                taskInfo.isVisible,
                taskInfo.configuration.windowConfiguration.bounds,
            )
        }
    }

@@ -90,7 +95,12 @@ class DesktopTaskChangeListener(
            }
            // If the task is already active in the repository, then moves task to the front,
            // else adds the task.
            desktopRepository.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible)
            desktopRepository.addTask(
                taskInfo.displayId,
                taskInfo.taskId,
                taskInfo.isVisible,
                taskInfo.configuration.windowConfiguration.bounds,
            )
        }
    }

@@ -134,7 +144,12 @@ class DesktopTaskChangeListener(
            }
            // If the task is already active in the repository, then it only moves the task to the
            // front.
            desktopRepository.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible)
            desktopRepository.addTask(
                taskInfo.displayId,
                taskInfo.taskId,
                taskInfo.isVisible,
                taskInfo.configuration.windowConfiguration.bounds,
            )
        }
    }

@@ -149,7 +164,12 @@ class DesktopTaskChangeListener(
        val desktopRepository: DesktopRepository =
            desktopUserRepositories.getProfile(taskInfo.userId)
        if (!desktopRepository.isActiveTask(taskInfo.taskId)) return
        desktopRepository.updateTask(taskInfo.displayId, taskInfo.taskId, /* isVisible= */ false)
        desktopRepository.updateTask(
            taskInfo.displayId,
            taskInfo.taskId,
            isVisible = false,
            taskInfo.configuration.windowConfiguration.bounds,
        )
    }

    override fun onTaskClosing(taskInfo: RunningTaskInfo) {
@@ -172,7 +192,12 @@ class DesktopTaskChangeListener(
            // the repo.
            desktopRepository.removeClosingTask(taskInfo.taskId)
            if (isMinimized) {
                desktopRepository.updateTask(taskInfo.displayId, taskInfo.taskId, isVisible = false)
                desktopRepository.updateTask(
                    taskInfo.displayId,
                    taskInfo.taskId,
                    isVisible = false,
                    taskInfo.configuration.windowConfiguration.bounds,
                )
            } else {
                desktopRepository.removeTask(taskInfo.taskId)
            }
+5 −0
Original line number Diff line number Diff line
@@ -128,6 +128,7 @@ import com.android.wm.shell.desktopmode.multidesks.DeskTransition
import com.android.wm.shell.desktopmode.multidesks.DesksOrganizer
import com.android.wm.shell.desktopmode.multidesks.DesksTransitionObserver
import com.android.wm.shell.desktopmode.multidesks.OnDeskRemovedListener
import com.android.wm.shell.desktopmode.multidesks.PreserveDisplayRequestHandler
import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer
import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer.DeskRecreationFactory
import com.android.wm.shell.draganddrop.DragAndDropController
@@ -295,6 +296,9 @@ class DesktopTasksController(
    // A listener that is invoked after a desk has been remove from the system. */
    var onDeskRemovedListener: OnDeskRemovedListener? = null

    // A handler for requests to preserve a disconnected display to potentially restore later.
    var preserveDisplayRequestHandler: PreserveDisplayRequestHandler? = null

    private val toDesktopAnimationDurationMs =
        context.resources.getInteger(SharedR.integer.to_desktop_animation_duration_ms)

@@ -680,6 +684,7 @@ class DesktopTasksController(
        destinationDisplayId: Int,
        transition: IBinder,
    ): WindowContainerTransaction {
        preserveDisplayRequestHandler?.requestPreserveDisplay(disconnectedDisplayId)
        // TODO: b/406320371 - Verify this works with non-system users once the underlying bug is
        //  resolved.
        val wct = WindowContainerTransaction()
+1 −0
Original line number Diff line number Diff line
@@ -187,6 +187,7 @@ class DesksTransitionObserver(
                        deskId = deskTransition.deskId,
                        taskId = deskTransition.enterTaskId,
                        isVisible = true,
                        taskBounds = taskChange.taskInfo?.configuration?.windowConfiguration?.bounds,
                    )
                } else {
                    // This is possible in cases where the task that was originally launched is a
Loading