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

Commit 778c0836 authored by Jorge Gil's avatar Jorge Gil
Browse files

Desks: Update desk launch root state on core-started transitions

When switching users, visible desks can be moved to back (or to front if
the new user had a desk visible) without Shell knowing about the
transition and thus not applying launch-root updates correctly.

With this change, DesksTransitionObserver monitors for updates to desk
roots and applies launch-root updates accordingly.

Desk state in the repository doesn't need to be changed because:
1) We want to keep the desk "active" from the repository pov even it's
   in the back (because it belongs to a non active user)
2) There isn't enough information in TransitionInfo to know to which
   user a desk belongs anyway - desks, and thus deskIds can be shared
   across users right now, also TaskInfo#userId of non leaf task is
   meaningless (it just points to the current user), and also the
   transition comes in before SysUI/Shell knows about the user-switch,
   so the "currentUserId" to Shell will point to the old user.

Flag: com.android.window.flags.enable_multiple_desktops_backend
Bug: 404591902
Test: switch users with desks active on both users, verify desk and
desktop windows are restored - and repeat with both reused deskIds and
different deskIds.

Change-Id: I452d819e0b4e782286f297331d91598434497d2b
parent ffc99ac9
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -1407,11 +1407,13 @@ public abstract class WMShellModule {
    static Optional<DesksTransitionObserver> provideDesksTransitionObserver(
            @DynamicOverride DesktopUserRepositories desktopUserRepositories,
            @NonNull DesksOrganizer desksOrganizer,
            @NonNull Transitions transitions,
            DesktopState desktopState
    ) {
        if (desktopState.canEnterDesktopModeOrShowAppHandle()) {
            return Optional.of(
                    new DesksTransitionObserver(desktopUserRepositories, desksOrganizer));
                    new DesksTransitionObserver(desktopUserRepositories, desksOrganizer,
                            transitions));
        }
        return Optional.empty();
    }
+2 −2
Original line number Diff line number Diff line
@@ -35,10 +35,10 @@ interface DesksOrganizer {
    fun createDeskImmediate(displayId: Int, userId: Int): Int?

    /** Activates the given desk, making it visible in its display. */
    fun activateDesk(wct: WindowContainerTransaction, deskId: Int)
    fun activateDesk(wct: WindowContainerTransaction, deskId: Int, skipReorder: Boolean = false)

    /** Deactivates the given desk, removing it as the default launch container for new tasks. */
    fun deactivateDesk(wct: WindowContainerTransaction, deskId: Int)
    fun deactivateDesk(wct: WindowContainerTransaction, deskId: Int, skipReorder: Boolean = false)

    /** Removes the given desk of the given user. */
    fun removeDesk(wct: WindowContainerTransaction, deskId: Int, userId: Int)
+45 −0
Original line number Diff line number Diff line
@@ -17,12 +17,17 @@ package com.android.wm.shell.desktopmode.multidesks

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
import android.window.TransitionInfo
import android.window.WindowContainerTransaction
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.desktopmode.DesktopUserRepositories
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
import com.android.wm.shell.transition.Transitions

/**
 * Observer of desk-related transitions, such as adding, removing or activating a whole desk. It
@@ -31,6 +36,7 @@ import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
class DesksTransitionObserver(
    private val desktopUserRepositories: DesktopUserRepositories,
    private val desksOrganizer: DesksOrganizer,
    private val transitions: Transitions,
) {
    private val deskTransitions = mutableMapOf<IBinder, MutableSet<DeskTransition>>()

@@ -51,6 +57,11 @@ class DesksTransitionObserver(
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return
        val deskTransitions = deskTransitions.remove(transition)
        deskTransitions?.forEach { deskTransition -> handleDeskTransition(info, deskTransition) }
        if (deskTransitions == null || deskTransitions.isEmpty()) {
            // A desk transition could also occur without shell having started it or intercepting
            // it, check for that here in case launch roots need to be updated.
            handleIndependentDeskTransitionIfNeeded(info)
        }
    }

    /**
@@ -215,6 +226,40 @@ class DesksTransitionObserver(
        }
    }

    private fun handleIndependentDeskTransitionIfNeeded(info: TransitionInfo) {
        val deskChanges = info.changes.filter { c -> desksOrganizer.isDeskChange(c) }
        if (deskChanges.isEmpty()) return
        logD(
            "handleIndependentDeskTransitionIfNeeded %d desk related changes found",
            deskChanges.size,
        )
        val wct = WindowContainerTransaction()
        for (change in deskChanges.reversed()) {
            val deskId = desksOrganizer.getDeskIdFromChange(change) ?: continue
            when (change.mode) {
                TRANSIT_TO_BACK -> {
                    logD("handleIndependentDeskTransitionIfNeeded desk=%d moved to back", deskId)
                    desksOrganizer.deactivateDesk(wct, deskId, skipReorder = true)
                }
                TRANSIT_TO_FRONT -> {
                    logD("handleIndependentDeskTransitionIfNeeded desk=%d moved to front", deskId)
                    desksOrganizer.activateDesk(wct, deskId, skipReorder = true)
                }
                else -> {
                    logW(
                        "Unexpected change for desk=%d with mode=%",
                        deskId,
                        TransitionInfo.modeToString(change.mode),
                    )
                }
            }
        }
        if (wct.isEmpty) {
            return
        }
        transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null)
    }

    private fun logD(msg: String, vararg arguments: Any?) {
        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
    }
+14 −5
Original line number Diff line number Diff line
@@ -202,22 +202,32 @@ class RootTaskDesksOrganizer(
        wct.setWindowingMode(minimizationRoot.token, WINDOWING_MODE_FREEFORM)
    }

    override fun activateDesk(wct: WindowContainerTransaction, deskId: Int) {
    override fun activateDesk(wct: WindowContainerTransaction, deskId: Int, skipReorder: Boolean) {
        logV("activateDesk %d", deskId)
        val root = checkNotNull(deskRootsByDeskId[deskId]) { "Root not found for desk: $deskId" }
        wct.reorder(root.token, /* onTop= */ true)
        if (!skipReorder) wct.reorder(root.token, /* onTop= */ true)
        updateLaunchRoot(wct, deskId, enabled = true)
    }

    override fun deactivateDesk(wct: WindowContainerTransaction, deskId: Int) {
    override fun deactivateDesk(
        wct: WindowContainerTransaction,
        deskId: Int,
        skipReorder: Boolean,
    ) {
        logV("deactivateDesk %d", deskId)
        val root = checkNotNull(deskRootsByDeskId[deskId]) { "Root not found for desk: $deskId" }
        if (!skipReorder) wct.reorder(root.taskInfo.token, /* onTop= */ false)
        updateLaunchRoot(wct, deskId, enabled = false)
    }

    private fun updateLaunchRoot(wct: WindowContainerTransaction, deskId: Int, enabled: Boolean) {
        val root = checkNotNull(deskRootsByDeskId[deskId]) { "Root not found for desk: $deskId" }
        if (root.isLaunchRootRequested == enabled) {
            logD("updateLaunchRoot desk=%d launch root already set to enabled=%b", deskId, enabled)
            return
        }
        root.isLaunchRootRequested = enabled
        logD("updateLaunchRoot deskId=%d enabled=%b", deskId, enabled)
        logD("updateLaunchRoot changing desk=%d launch root to enabled=%b", deskId, enabled)
        if (enabled) {
            wct.setLaunchRoot(
                /* container= */ root.taskInfo.token,
@@ -230,7 +240,6 @@ class RootTaskDesksOrganizer(
                /* windowingModes= */ null,
                /* activityTypes= */ null,
            )
            wct.reorder(root.taskInfo.token, /* onTop= */ false)
        }
    }

+22 −18
Original line number Diff line number Diff line
@@ -2969,7 +2969,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()

        val wct = getLatestDesktopMixedTaskWct(type = TRANSIT_TO_FRONT)
        assertNotNull(wct)
        verify(desksOrganizer, never()).activateDesk(eq(wct), any())
        verify(desksOrganizer, never()).activateDesk(eq(wct), any(), any())
    }

    @Test
@@ -3735,7 +3735,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        controller.moveToNextDisplay(task.taskId)

        verify(desksOrganizer).moveTaskToDesk(any(), eq(targetDeskId), eq(task), eq(false))
        verify(desksOrganizer).activateDesk(any(), eq(targetDeskId))
        verify(desksOrganizer).activateDesk(any(), eq(targetDeskId), skipReorder = eq(false))
        verify(desksTransitionsObserver)
            .addPendingTransition(
                DeskTransition.ActivateDeskWithTask(
@@ -3770,7 +3770,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        )
        controller.moveToNextDisplay(task.taskId)

        verify(desksOrganizer).deactivateDesk(any(), eq(sourceDeskId))
        verify(desksOrganizer).deactivateDesk(any(), eq(sourceDeskId), skipReorder = eq(false))
        verify(desksTransitionsObserver)
            .addPendingTransition(
                DeskTransition.DeactivateDesk(token = transition, deskId = sourceDeskId)
@@ -4167,7 +4167,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()

        minimizePipTask(task)

        verify(desksOrganizer).deactivateDesk(any(), eq(deskId))
        verify(desksOrganizer).deactivateDesk(any(), eq(deskId), skipReorder = eq(false))
        verify(desksTransitionsObserver)
            .addPendingTransition(DeskTransition.DeactivateDesk(transition, deskId))
    }
@@ -5948,7 +5948,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()

        controller.handleRequest(Binder(), createTransition(task, type = TRANSIT_CLOSE))

        verify(desksOrganizer).deactivateDesk(any(), /* deskId= */ eq(0))
        verify(desksOrganizer).deactivateDesk(any(), /* deskId= */ eq(0), skipReorder = eq(false))
    }

    @Test
@@ -6098,7 +6098,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        val transition = Binder()
        controller.handleRequest(transition, createTransition(task, type = TRANSIT_TO_BACK))

        verify(desksOrganizer, never()).deactivateDesk(any(), deskId = eq(0))
        verify(desksOrganizer, never())
            .deactivateDesk(any(), deskId = eq(0), skipReorder = eq(false))
        verify(desksTransitionsObserver, never())
            .addPendingTransition(
                argThat {
@@ -6547,7 +6548,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()

        controller.activateDesk(activatingDeskId, RemoteTransition(TestRemoteTransition()))

        verify(desksOrganizer).deactivateDesk(any(), eq(previouslyActiveDeskId))
        verify(desksOrganizer)
            .deactivateDesk(any(), eq(previouslyActiveDeskId), skipReorder = eq(false))
        verify(desksTransitionsObserver)
            .addPendingTransition(
                argThat {
@@ -6570,7 +6572,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()

        controller.activatePreviousDesk(DEFAULT_DISPLAY)

        verify(desksOrganizer).activateDesk(any(), eq(1))
        verify(desksOrganizer).activateDesk(any(), eq(1), skipReorder = eq(false))
    }

    @Test
@@ -6585,7 +6587,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()

        controller.activateNextDesk(DEFAULT_DISPLAY)

        verify(desksOrganizer).activateDesk(any(), eq(2))
        verify(desksOrganizer).activateDesk(any(), eq(2), skipReorder = eq(false))
    }

    @Test
@@ -6598,7 +6600,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()

        controller.activatePreviousDesk(DEFAULT_DISPLAY)

        verify(desksOrganizer, never()).activateDesk(any(), any())
        verify(desksOrganizer, never()).activateDesk(any(), any(), skipReorder = any())
    }

    @Test
@@ -6612,7 +6614,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()

        controller.activateNextDesk(DEFAULT_DISPLAY)

        verify(desksOrganizer, never()).activateDesk(any(), any())
        verify(desksOrganizer, never()).activateDesk(any(), any(), skipReorder = any())
    }

    @Test
@@ -6625,7 +6627,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()

        controller.activatePreviousDesk(DEFAULT_DISPLAY)

        verify(desksOrganizer, never()).activateDesk(any(), any())
        verify(desksOrganizer, never()).activateDesk(any(), any(), any())
    }

    @Test
@@ -6638,7 +6640,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()

        controller.activateNextDesk(DEFAULT_DISPLAY)

        verify(desksOrganizer, never()).activateDesk(any(), any())
        verify(desksOrganizer, never()).activateDesk(any(), any(), any())
    }

    @Test
@@ -6658,7 +6660,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()

        controller.activatePreviousDesk(INVALID_DISPLAY)

        verify(desksOrganizer).activateDesk(any(), eq(1))
        verify(desksOrganizer).activateDesk(any(), eq(1), skipReorder = eq(false))
    }

    @Test
@@ -6678,7 +6680,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()

        controller.activateNextDesk(INVALID_DISPLAY)

        verify(desksOrganizer).activateDesk(any(), eq(4))
        verify(desksOrganizer).activateDesk(any(), eq(4), skipReorder = eq(false))
    }

    @Test
@@ -9218,7 +9220,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
                        this.deskId == DISCONNECTED_DESK_ID
                }
            )
        verify(desksOrganizer).deactivateDesk(any(), eq(DISCONNECTED_DESK_ID))
        verify(desksOrganizer)
            .deactivateDesk(any(), eq(DISCONNECTED_DESK_ID), skipReorder = eq(false))
        verify(desksTransitionsObserver)
            .addPendingTransition(
                argThat {
@@ -9260,7 +9263,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
                        this.deskId == DISCONNECTED_DESK_ID
                }
            )
        verify(desksOrganizer).activateDesk(any(), eq(DISCONNECTED_DESK_ID))
        verify(desksOrganizer)
            .activateDesk(any(), eq(DISCONNECTED_DESK_ID), skipReorder = eq(false))
        verify(desksTransitionsObserver)
            .addPendingTransition(
                argThat {
@@ -9429,7 +9433,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
            displayId = DEFAULT_DISPLAY,
        )

        verify(desksOrganizer).activateDesk(any(), eq(inactiveDesk))
        verify(desksOrganizer).activateDesk(any(), eq(inactiveDesk), skipReorder = eq(false))
        verify(desksTransitionsObserver)
            .addPendingTransition(
                DeskTransition.ActivateDesk(
Loading