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

Commit 8703cf93 authored by Jorge Gil's avatar Jorge Gil
Browse files

[38/N] Desks: Disable launch-adjacent when a desk is active

To prevent a launching task with the launch-adjacent flag set from
launching outside of desktop mode, this change disables the
launch-adjacent container temporarily while the desk is active.

This is the multiple-desks version of what FreeformTaskListener did
before, but because desk roots (freeform root tasks) aren't managed by
FreeformTaskListener, the handling needs to be moved into
RootTaskDesksOrganizer. Also because a desk could be empty, so relying
on freeform task count doesn't work anymore.

Flag: com.android.window.flags.enable_multiple_desktops_backend
Bug: 400495830
Test: Use Chrome's "New Window" to launch an adjacent instance - verify
it launches inside the desk.

Change-Id: I6bbba8e50dc2f596ac5a9f1ef18b404a5af4863c
parent 5e294222
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -727,9 +727,11 @@ public abstract class WMShellModule {
    static DesksOrganizer provideDesksOrganizer(
            @NonNull ShellInit shellInit,
            @NonNull ShellCommandHandler shellCommandHandler,
            @NonNull ShellTaskOrganizer shellTaskOrganizer
            @NonNull ShellTaskOrganizer shellTaskOrganizer,
            @NonNull LaunchAdjacentController launchAdjacentController
    ) {
        return new RootTaskDesksOrganizer(shellInit, shellCommandHandler, shellTaskOrganizer);
        return new RootTaskDesksOrganizer(shellInit, shellCommandHandler, shellTaskOrganizer,
                launchAdjacentController);
    }

    @WMSingleton
+34 −2
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import androidx.core.util.forEach
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.common.LaunchAdjacentController
import com.android.wm.shell.desktopmode.multidesks.DesksOrganizer.OnCreateCallback
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
import com.android.wm.shell.sysui.ShellCommandHandler
@@ -44,6 +45,7 @@ class RootTaskDesksOrganizer(
    shellInit: ShellInit,
    shellCommandHandler: ShellCommandHandler,
    private val shellTaskOrganizer: ShellTaskOrganizer,
    private val launchAdjacentController: LaunchAdjacentController,
) : DesksOrganizer, ShellTaskOrganizer.TaskListener {

    private val createDeskRootRequests = mutableListOf<CreateDeskRequest>()
@@ -212,6 +214,21 @@ class RootTaskDesksOrganizer(
            change.mode == TRANSIT_TO_FRONT

    override fun onTaskAppeared(taskInfo: RunningTaskInfo, leash: SurfaceControl) {
        handleTaskAppeared(taskInfo, leash)
        updateLaunchAdjacentController()
    }

    override fun onTaskInfoChanged(taskInfo: RunningTaskInfo) {
        handleTaskInfoChanged(taskInfo)
        updateLaunchAdjacentController()
    }

    override fun onTaskVanished(taskInfo: RunningTaskInfo) {
        handleTaskVanished(taskInfo)
        updateLaunchAdjacentController()
    }

    private fun handleTaskAppeared(taskInfo: RunningTaskInfo, leash: SurfaceControl) {
        // Check whether this task is appearing inside a desk.
        if (taskInfo.parentTaskId in deskRootsByDeskId) {
            val deskId = taskInfo.parentTaskId
@@ -264,7 +281,7 @@ class RootTaskDesksOrganizer(
        hideMinimizationRoot(deskMinimizationRoot)
    }

    override fun onTaskInfoChanged(taskInfo: RunningTaskInfo) {
    private fun handleTaskInfoChanged(taskInfo: RunningTaskInfo) {
        if (deskRootsByDeskId.contains(taskInfo.taskId)) {
            val deskId = taskInfo.taskId
            deskRootsByDeskId[deskId] = deskRootsByDeskId[deskId].copy(taskInfo = taskInfo)
@@ -302,7 +319,7 @@ class RootTaskDesksOrganizer(
        logE("onTaskInfoChanged: unknown task: ${taskInfo.taskId}")
    }

    override fun onTaskVanished(taskInfo: RunningTaskInfo) {
    private fun handleTaskVanished(taskInfo: RunningTaskInfo) {
        if (deskRootsByDeskId.contains(taskInfo.taskId)) {
            val deskId = taskInfo.taskId
            val deskRoot = deskRootsByDeskId[deskId]
@@ -384,6 +401,18 @@ class RootTaskDesksOrganizer(
        deskRootsByDeskId.forEach { _, deskRoot -> deskRoot.children -= taskId }
    }

    private fun updateLaunchAdjacentController() {
        deskRootsByDeskId.forEach { deskId, root ->
            if (root.taskInfo.isVisible) {
                // Disable launch adjacent handling if any desk is active, otherwise the split
                // launch root and the desk root will both be eligible to take launching tasks.
                launchAdjacentController.launchAdjacentEnabled = false
                return
            }
        }
        launchAdjacentController.launchAdjacentEnabled = true
    }

    @VisibleForTesting
    data class DeskRoot(
        val deskId: Int,
@@ -425,6 +454,9 @@ class RootTaskDesksOrganizer(
    override fun dump(pw: PrintWriter, prefix: String) {
        val innerPrefix = "$prefix  "
        pw.println("$prefix$TAG")
        pw.println(
            "${innerPrefix}launchAdjacentEnabled=" + launchAdjacentController.launchAdjacentEnabled
        )
        pw.println("${innerPrefix}Desk Roots:")
        deskRootsByDeskId.forEach { deskId, root ->
            val minimizationRoot = deskMinimizationRootsByDeskId[deskId]
+6 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.util.SparseArray;
import android.view.SurfaceControl;
import android.window.DesktopExperienceFlags;
import android.window.DesktopModeFlags;

import com.android.internal.protolog.ProtoLog;
@@ -167,6 +168,11 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener,
    }

    private void updateLaunchAdjacentController() {
        if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue()) {
            // With multiple desks, freeform tasks are children of a root task controlled by
            // DesksOrganizer, so toggling launch-adjacent should be managed there.
            return;
        }
        for (int i = 0; i < mTasks.size(); i++) {
            if (mTasks.valueAt(i).mTaskInfo.isVisible) {
                mLaunchAdjacentController.setLaunchAdjacentEnabled(false);
+97 −3
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import androidx.test.filters.SmallTest
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.TestShellExecutor
import com.android.wm.shell.common.LaunchAdjacentController
import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask
import com.android.wm.shell.desktopmode.multidesks.RootTaskDesksOrganizer.DeskMinimizationRoot
import com.android.wm.shell.desktopmode.multidesks.RootTaskDesksOrganizer.DeskRoot
@@ -60,13 +61,19 @@ class RootTaskDesksOrganizerTest : ShellTestCase() {
    private val testShellInit = ShellInit(testExecutor)
    private val mockShellCommandHandler = mock<ShellCommandHandler>()
    private val mockShellTaskOrganizer = mock<ShellTaskOrganizer>()
    private val launchAdjacentController = LaunchAdjacentController(mock())

    private lateinit var organizer: RootTaskDesksOrganizer

    @Before
    fun setUp() {
        organizer =
            RootTaskDesksOrganizer(testShellInit, mockShellCommandHandler, mockShellTaskOrganizer)
            RootTaskDesksOrganizer(
                testShellInit,
                mockShellCommandHandler,
                mockShellTaskOrganizer,
                launchAdjacentController,
            )
    }

    @Test
@@ -607,14 +614,101 @@ class RootTaskDesksOrganizerTest : ShellTestCase() {
            .isNotNull()
    }

    @Test
    fun onTaskAppeared_visibleDesk_onlyDesk_disablesLaunchAdjacent() {
        launchAdjacentController.launchAdjacentEnabled = true

        createDesk(visible = true)

        assertThat(launchAdjacentController.launchAdjacentEnabled).isFalse()
    }

    @Test
    fun onTaskAppeared_invisibleDesk_onlyDesk_enablesLaunchAdjacent() {
        launchAdjacentController.launchAdjacentEnabled = false

        createDesk(visible = false)

        assertThat(launchAdjacentController.launchAdjacentEnabled).isTrue()
    }

    @Test
    fun onTaskAppeared_invisibleDesk_otherVisibleDesk_disablesLaunchAdjacent() {
        launchAdjacentController.launchAdjacentEnabled = true

        createDesk(visible = true)
        createDesk(visible = false)

        assertThat(launchAdjacentController.launchAdjacentEnabled).isFalse()
    }

    @Test
    fun onTaskInfoChanged_deskBecomesVisible_onlyDesk_disablesLaunchAdjacent() {
        launchAdjacentController.launchAdjacentEnabled = true

        val desk = createDesk(visible = false)
        desk.deskRoot.taskInfo.isVisible = true
        organizer.onTaskInfoChanged(desk.deskRoot.taskInfo)

        assertThat(launchAdjacentController.launchAdjacentEnabled).isFalse()
    }

    @Test
    fun onTaskInfoChanged_deskBecomesInvisible_onlyDesk_enablesLaunchAdjacent() {
        launchAdjacentController.launchAdjacentEnabled = false

        val desk = createDesk(visible = true)
        desk.deskRoot.taskInfo.isVisible = false
        organizer.onTaskInfoChanged(desk.deskRoot.taskInfo)

        assertThat(launchAdjacentController.launchAdjacentEnabled).isTrue()
    }

    @Test
    fun onTaskInfoChanged_deskBecomesInvisible_otherVisibleDesk_disablesLaunchAdjacent() {
        launchAdjacentController.launchAdjacentEnabled = true

        createDesk(visible = true)
        val desk = createDesk(visible = true)
        desk.deskRoot.taskInfo.isVisible = false
        organizer.onTaskInfoChanged(desk.deskRoot.taskInfo)

        assertThat(launchAdjacentController.launchAdjacentEnabled).isFalse()
    }

    @Test
    fun onTaskVanished_visibleDeskDisappears_onlyDesk_enablesLaunchAdjacent() {
        launchAdjacentController.launchAdjacentEnabled = false

        val desk = createDesk(visible = true)
        organizer.onTaskVanished(desk.deskRoot.taskInfo)

        assertThat(launchAdjacentController.launchAdjacentEnabled).isTrue()
    }

    @Test
    fun onTaskVanished_visibleDeskDisappears_otherDeskVisible_disablesLaunchAdjacent() {
        launchAdjacentController.launchAdjacentEnabled = true

        createDesk(visible = true)
        val desk = createDesk(visible = true)
        organizer.onTaskVanished(desk.deskRoot.taskInfo)

        assertThat(launchAdjacentController.launchAdjacentEnabled).isFalse()
    }

    private data class DeskRoots(
        val deskRoot: DeskRoot,
        val minimizationRoot: DeskMinimizationRoot,
    )

    private fun createDesk(): DeskRoots {
    private fun createDesk(visible: Boolean = true): DeskRoots {
        organizer.createDesk(Display.DEFAULT_DISPLAY, FakeOnCreateCallback())
        val freeformRoot = createFreeformTask().apply { parentTaskId = -1 }
        val freeformRoot =
            createFreeformTask().apply {
                parentTaskId = -1
                isVisible = visible
            }
        organizer.onTaskAppeared(freeformRoot, SurfaceControl())
        val minimizationRoot = createFreeformTask().apply { parentTaskId = -1 }
        organizer.onTaskAppeared(minimizationRoot, SurfaceControl())
+3 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;

import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.window.flags.Flags;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
@@ -198,6 +199,7 @@ public final class FreeformTaskListenerTests extends ShellTestCase {
    }

    @Test
    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    public void visibilityTaskChanged_visible_setLaunchAdjacentDisabled() {
        ActivityManager.RunningTaskInfo task =
                new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build();
@@ -209,6 +211,7 @@ public final class FreeformTaskListenerTests extends ShellTestCase {
    }

    @Test
    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    public void visibilityTaskChanged_notVisible_setLaunchAdjacentEnabled() {
        ActivityManager.RunningTaskInfo task =
                new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build();