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

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

Merge "[1/N] Reparent desks on display disconnect." into main

parents 51b5fb54 2584fae4
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -1373,7 +1373,8 @@ public abstract class WMShellModule {
            Optional<DesktopUserRepositories> desktopUserRepositories,
            Optional<DesktopTasksController> desktopTasksController,
            Optional<DesktopDisplayModeController> desktopDisplayModeController,
            DesktopRepositoryInitializer desktopRepositoryInitializer
            DesktopRepositoryInitializer desktopRepositoryInitializer,
            Optional<DesksTransitionObserver> desksTransitionObserver
    ) {
        if (!DesktopModeStatus.canEnterDesktopMode(context)) {
            return Optional.empty();
@@ -1389,7 +1390,8 @@ public abstract class WMShellModule {
                        desktopRepositoryInitializer,
                        desktopUserRepositories.get(),
                        desktopTasksController.get(),
                        desktopDisplayModeController.get()));
                        desktopDisplayModeController.get(),
                        desksTransitionObserver.get()));
    }

    @WMSingleton
+24 −6
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayController.OnDisplaysChangedListener
import com.android.wm.shell.desktopmode.multidesks.DesksTransitionObserver
import com.android.wm.shell.desktopmode.multidesks.OnDeskDisplayChangeListener
import com.android.wm.shell.desktopmode.multidesks.OnDeskRemovedListener
import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
@@ -47,7 +49,8 @@ class DesktopDisplayEventHandler(
    private val desktopUserRepositories: DesktopUserRepositories,
    private val desktopTasksController: DesktopTasksController,
    private val desktopDisplayModeController: DesktopDisplayModeController,
) : OnDisplaysChangedListener, OnDeskRemovedListener {
    private val desksTransitionObserver: DesksTransitionObserver,
) : OnDisplaysChangedListener, OnDeskRemovedListener, OnDeskDisplayChangeListener {

    init {
        shellInit.addInitCallback({ onInit() }, this)
@@ -67,6 +70,10 @@ class DesktopDisplayEventHandler(
                    }
                }
            )

            if (DesktopExperienceFlags.ENABLE_DISPLAY_DISCONNECT_INTERACTION.isTrue) {
                desksTransitionObserver.deskDisplayChangeListener = this
            }
        }
    }

@@ -85,8 +92,7 @@ class DesktopDisplayEventHandler(
        if (displayId != DEFAULT_DISPLAY) {
            desktopDisplayModeController.updateDefaultDisplayWindowingMode()
        }

        // TODO: b/362720497 - move desks in closing display to the remaining desk.
        // TODO(b/391652399): store a persisted DesktopDisplay in DesktopRepository
    }

    override fun onDesktopModeEligibleChanged(displayId: Int) {
@@ -125,15 +131,27 @@ class DesktopDisplayEventHandler(
                        )
                    }
                    .forEach { displayId ->
                        // TODO: b/393978539 - consider activating the desk on creation when
                        //  applicable, such as for connected displays.
                        desktopTasksController.createDesk(displayId, repository.userId)
                        desktopTasksController.createDesk(
                            displayId,
                            repository.userId,
                            isDesktopFirstDisplay(displayId),
                        )
                    }
                cancel()
            }
        }
    }

    override fun onDeskDisplayChange(
        deskDisplayChanges: Set<OnDeskDisplayChangeListener.DeskDisplayChange>
    ) {
        if (!DesktopExperienceFlags.ENABLE_DISPLAY_DISCONNECT_INTERACTION.isTrue()) return
        desktopTasksController.onDeskDisconnectTransition(deskDisplayChanges)
    }

    // TODO: b/393978539 - implement this
    private fun isDesktopFirstDisplay(displayId: Int): Boolean = displayId != DEFAULT_DISPLAY

    // TODO: b/362720497 - connected/projected display considerations.
    private fun supportsDesks(displayId: Int): Boolean =
        DesktopModeStatus.canEnterDesktopMode(context)
+34 −2
Original line number Diff line number Diff line
@@ -72,7 +72,7 @@ class DesktopRepository(
     */
    private data class Desk(
        val deskId: Int,
        val displayId: Int,
        var displayId: Int,
        val activeTasks: ArraySet<Int> = ArraySet(),
        val visibleTasks: ArraySet<Int> = ArraySet(),
        val minimizedTasks: ArraySet<Int> = ArraySet(),
@@ -221,6 +221,19 @@ class DesktopRepository(
        }
    }

    /** Update the data to reflect a desk changing displays. */
    fun onDeskDisplayChanged(deskId: Int, newDisplayId: Int) {
        val desk =
            desktopData.getDesk(deskId)?.deepCopy()
                ?: error("Expected to find desk with id: $deskId")
        desk.displayId = newDisplayId
        removeDesk(deskId)
        desktopData.addDesk(newDisplayId, desk)
        deskChangeListeners.forEach { (listener, executor) ->
            executor.execute { listener.onDeskAdded(displayId = newDisplayId, deskId = deskId) }
        }
    }

    /** Returns the ids of the existing desks in the given display. */
    @VisibleForTesting
    fun getDeskIds(displayId: Int): Set<Int> =
@@ -1178,10 +1191,13 @@ class DesktopRepository(
        /** Creates a desk record. */
        fun createDesk(displayId: Int, deskId: Int)

        /** Adds an existing desk to a specific display */
        fun addDesk(displayId: Int, desk: Desk)

        /** Returns the desk with the given id, or null if it does not exist. */
        fun getDesk(deskId: Int): Desk?

        /** Returns the active desk in this diplay, or null if none are active. */
        /** Returns the active desk in this display, or null if none are active. */
        fun getActiveDesk(displayId: Int): Desk?

        /** Sets the given desk as the active desk in the given display. */
@@ -1254,6 +1270,10 @@ class DesktopRepository(
            deskByDisplayId.getOrCreate(displayId)
        }

        override fun addDesk(displayId: Int, desk: Desk) {
            // No-op, not supported
        }

        override fun getDesk(deskId: Int): Desk =
            // TODO: b/362720497 - consider enforcing that the desk has been created before trying
            //  to use it. As of now, there are cases where a task may be created faster than a
@@ -1327,6 +1347,18 @@ class DesktopRepository(
            display.orderedDesks.add(Desk(deskId = deskId, displayId = displayId))
        }

        override fun addDesk(displayId: Int, desk: Desk) {
            val display =
                desktopDisplays[displayId]
                    ?: DesktopDisplay(displayId).also { desktopDisplays[displayId] = it }
            check(
                display.orderedDesks.none { existingDesk -> desk.deskId == existingDesk.deskId }
            ) {
                "Attempting to add desk#${desk.deskId} that already exists in display#$displayId"
            }
            display.orderedDesks.add(desk)
        }

        override fun getDesk(deskId: Int): Desk? {
            desktopDisplays.forEach { _, display ->
                val desk = display.orderedDesks.find { desk -> desk.deskId == deskId }
+68 −1
Original line number Diff line number Diff line
@@ -117,6 +117,7 @@ import com.android.wm.shell.desktopmode.minimize.DesktopWindowLimitRemoteHandler
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.OnDeskDisplayChangeListener
import com.android.wm.shell.desktopmode.multidesks.OnDeskRemovedListener
import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer
import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer.DeskRecreationFactory
@@ -468,7 +469,7 @@ class DesktopTasksController(
    }

    /** Adds a new desk to the given display for the given user. */
    fun createDesk(displayId: Int, userId: Int = this.userId) {
    fun createDesk(displayId: Int, userId: Int = this.userId, activateDesk: Boolean = false) {
        logV("addDesk displayId=%d, userId=%d", displayId, userId)
        val repository = userRepositories.getProfile(userId)
        createDesk(displayId, userId) { deskId ->
@@ -476,6 +477,9 @@ class DesktopTasksController(
                logW("Failed to add desk in displayId=%d for userId=%d", displayId, userId)
            } else {
                repository.addDesk(displayId = displayId, deskId = deskId)
                if (activateDesk) {
                    activateDesk(deskId)
                }
            }
        }
    }
@@ -516,6 +520,69 @@ class DesktopTasksController(
            createDesk(displayId, userId) { deskId -> cont.resumeWith(Result.success(deskId)) }
        }

    /**
     * Handle desk operations resulting from a display disconnect transition. Forks to two separate
     * methods depending on whether the destination display supports desktop mode.
     *
     * @param deskDisconnectChanges the individual changes resulting from the disconnect
     */
    fun onDeskDisconnectTransition(
        deskDisconnectChanges: Set<OnDeskDisplayChangeListener.DeskDisplayChange>
    ) {
        val wct = WindowContainerTransaction()
        // TODO(b/391652399): Remove the wallpaper of the disconnected display.
        val transitStartRunnables = mutableSetOf<RunOnTransitStart?>()
        for (change in deskDisconnectChanges) {
            if (
                DesktopModeStatus.isDesktopModeSupportedOnDisplay(
                    context,
                    displayController.getDisplay(change.destinationDisplayId),
                )
            ) {
                transitStartRunnables.add(
                    updateDesksActivationOnDisconnection(
                        disconnectedDisplayActiveDesk = change.deskId,
                        wct = wct,
                        change.toTop,
                    )
                )
            } else {
                // TODO(b/391652399): Implement desktop-not-supported case.
            }
        }
        val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null)
        for (transitStartRunnable in transitStartRunnables) {
            transitStartRunnable?.invoke(transition)
        }
    }

    /**
     * Handle desk operations when disconnecting a display and all desks on that display are moving
     * to a display that supports desks. The previously focused display will determine which desk
     * will move to the front.
     *
     * @param disconnectedDisplayActiveDesk the id of the active desk on the disconnected display
     * @param toTop whether this desk was reordered to the top
     */
    @VisibleForTesting
    fun updateDesksActivationOnDisconnection(
        disconnectedDisplayActiveDesk: Int,
        wct: WindowContainerTransaction,
        toTop: Boolean,
    ): RunOnTransitStart? {
        val runOnTransitStart =
            if (toTop) {
                // The disconnected display's active desk was reparented to the top, activate it
                // here.
                addDeskActivationChanges(disconnectedDisplayActiveDesk, wct)
            } else {
                // The disconnected display's active desk was reparented to the back, ensure it is
                // no longer an active launch root.
                prepareDeskDeactivationIfNeeded(wct, disconnectedDisplayActiveDesk)
            }
        return runOnTransitStart
    }

    /** Moves task to desktop mode if task is running, else launches it in desktop mode. */
    @JvmOverloads
    fun moveTaskToDefaultDeskAndActivate(
+11 −0
Original line number Diff line number Diff line
@@ -106,6 +106,17 @@ class DesktopUserRepositories(
        else return profileId
    }

    /** Find the repositories that contains the specified desk; returns empty set if none found. */
    fun getRepositoriesWithDeskId(deskId: Int): Set<DesktopRepository> {
        val repositories = mutableSetOf<DesktopRepository>()
        desktopRepoByUserId.forEach { _, desktopRepository ->
            if (desktopRepository.getAllDeskIds().contains(deskId)) {
                repositories.add(desktopRepository)
            }
        }
        return repositories
    }

    /** Dumps [DesktopRepository] for each user. */
    fun dump(pw: PrintWriter, prefix: String) {
        val innerPrefix = "$prefix    "
Loading