diff options
5 files changed, 144 insertions, 7 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index f959683701d2..fa960367cf60 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -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 diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt index 2130474ff603..49ca58e7b32a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt @@ -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] diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java index 897e2d1601a5..2fe786531af5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java @@ -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); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt index 891a1f1685cd..6b2f90fc0a59 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt @@ -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()) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java index 9509aaf20c9b..52c5ad1f8e49 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java @@ -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(); |