diff options
Diffstat (limited to 'libs')
3 files changed, 114 insertions, 35 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 2cf671b0f446..99d4a4066a9a 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 @@ -1341,7 +1341,9 @@ public abstract class WMShellModule { Context context, ShellInit shellInit, @ShellMainThread CoroutineScope mainScope, + ShellController shellController, DisplayController displayController, + RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, Optional<DesktopUserRepositories> desktopUserRepositories, Optional<DesktopTasksController> desktopTasksController, Optional<DesktopDisplayModeController> desktopDisplayModeController, @@ -1355,7 +1357,9 @@ public abstract class WMShellModule { context, shellInit, mainScope, + shellController, displayController, + rootTaskDisplayAreaOrganizer, desktopRepositoryInitializer, desktopUserRepositories.get(), desktopTasksController.get(), diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt index 683b74392fa6..3b98f8123b46 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt @@ -17,16 +17,20 @@ package com.android.wm.shell.desktopmode import android.content.Context +import android.view.Display import android.view.Display.DEFAULT_DISPLAY import android.window.DesktopExperienceFlags 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.OnDeskRemovedListener 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.DesktopModeStatus +import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit +import com.android.wm.shell.sysui.UserChangeListener import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.cancel import kotlinx.coroutines.launch @@ -36,7 +40,9 @@ class DesktopDisplayEventHandler( private val context: Context, shellInit: ShellInit, private val mainScope: CoroutineScope, + private val shellController: ShellController, private val displayController: DisplayController, + private val rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, private val desktopRepositoryInitializer: DesktopRepositoryInitializer, private val desktopUserRepositories: DesktopUserRepositories, private val desktopTasksController: DesktopTasksController, @@ -53,8 +59,17 @@ class DesktopDisplayEventHandler( private fun onInit() { displayController.addDisplayWindowListener(this) - if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue()) { + if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { desktopTasksController.onDeskRemovedListener = this + + shellController.addUserChangeListener( + object : UserChangeListener { + override fun onUserChanged(newUserId: Int, userContext: Context) { + val displayIds = rootTaskDisplayAreaOrganizer.displayIds + createDefaultDesksIfNeeded(displayIds.toSet()) + } + } + ) } } @@ -63,23 +78,7 @@ class DesktopDisplayEventHandler( desktopDisplayModeController.refreshDisplayWindowingMode() } - if (!supportsDesks(displayId)) { - logV("Display #$displayId does not support desks") - return - } - - mainScope.launch { - desktopRepositoryInitializer.isInitialized.collect { initialized -> - if (!initialized) return@collect - if (desktopRepository.getNumberOfDesks(displayId) == 0) { - logV("Creating new desk in new display#$displayId") - // TODO: b/393978539 - consider activating the desk on creation when - // applicable, such as for connected displays. - desktopTasksController.createDesk(displayId) - } - cancel() - } - } + createDefaultDesksIfNeeded(displayIds = setOf(displayId)) } override fun onDisplayRemoved(displayId: Int) { @@ -93,8 +92,34 @@ class DesktopDisplayEventHandler( override fun onDeskRemoved(lastDisplayId: Int, deskId: Int) { val remainingDesks = desktopRepository.getNumberOfDesks(lastDisplayId) if (remainingDesks == 0) { - logV("All desks removed from display#$lastDisplayId, creating empty desk") - desktopTasksController.createDesk(lastDisplayId) + logV("All desks removed from display#$lastDisplayId") + createDefaultDesksIfNeeded(setOf(lastDisplayId)) + } + } + + private fun createDefaultDesksIfNeeded(displayIds: Set<Int>) { + if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return + logV("createDefaultDesksIfNeeded displays=%s", displayIds) + mainScope.launch { + desktopRepositoryInitializer.isInitialized.collect { initialized -> + if (!initialized) return@collect + displayIds + .filter { displayId -> displayId != Display.INVALID_DISPLAY } + .filter { displayId -> supportsDesks(displayId) } + .filter { displayId -> desktopRepository.getNumberOfDesks(displayId) == 0 } + .also { displaysNeedingDesk -> + logV( + "createDefaultDesksIfNeeded creating default desks in displays=%s", + displaysNeedingDesk, + ) + } + .forEach { displayId -> + // TODO: b/393978539 - consider activating the desk on creation when + // applicable, such as for connected displays. + desktopTasksController.createDesk(displayId) + } + cancel() + } } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt index 2aebcdcc3bf5..9268db60aa51 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt @@ -24,13 +24,16 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession import com.android.dx.mockito.inline.extended.ExtendedMockito.never import com.android.dx.mockito.inline.extended.StaticMockitoSession import com.android.window.flags.Flags +import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.ShellTestCase import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayController.OnDisplaysChangedListener import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer import com.android.wm.shell.shared.desktopmode.DesktopModeStatus +import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit +import com.android.wm.shell.sysui.UserChangeListener import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.MutableStateFlow @@ -46,6 +49,7 @@ import org.mockito.Mockito.spy import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.clearInvocations import org.mockito.kotlin.whenever import org.mockito.quality.Strictness @@ -60,6 +64,8 @@ import org.mockito.quality.Strictness class DesktopDisplayEventHandlerTest : ShellTestCase() { @Mock lateinit var testExecutor: ShellExecutor @Mock lateinit var displayController: DisplayController + @Mock private lateinit var mockShellController: ShellController + @Mock private lateinit var mockRootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer @Mock private lateinit var mockDesktopUserRepositories: DesktopUserRepositories @Mock private lateinit var mockDesktopRepository: DesktopRepository @Mock private lateinit var mockDesktopTasksController: DesktopTasksController @@ -89,7 +95,9 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { context, shellInit, testScope.backgroundScope, + mockShellController, displayController, + mockRootTaskDisplayAreaOrganizer, desktopRepositoryInitializer, mockDesktopUserRepositories, mockDesktopTasksController, @@ -107,6 +115,7 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { } @Test + @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun testDisplayAdded_supportsDesks_desktopRepositoryInitialized_createsDesk() = testScope.runTest { whenever(DesktopModeStatus.canEnterDesktopMode(context)).thenReturn(true) @@ -119,6 +128,7 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { } @Test + @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun testDisplayAdded_supportsDesks_desktopRepositoryNotInitialized_doesNotCreateDesk() = testScope.runTest { whenever(DesktopModeStatus.canEnterDesktopMode(context)).thenReturn(true) @@ -130,6 +140,7 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { } @Test + @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun testDisplayAdded_supportsDesks_desktopRepositoryInitializedTwice_createsDeskOnce() = testScope.runTest { whenever(DesktopModeStatus.canEnterDesktopMode(context)).thenReturn(true) @@ -143,6 +154,7 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { } @Test + @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun testDisplayAdded_supportsDesks_desktopRepositoryInitialized_deskExists_doesNotCreateDesk() = testScope.runTest { whenever(DesktopModeStatus.canEnterDesktopMode(context)).thenReturn(true) @@ -156,33 +168,71 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { } @Test - fun testDisplayAdded_cannotEnterDesktopMode_doesNotCreateDesk() { - whenever(DesktopModeStatus.canEnterDesktopMode(context)).thenReturn(false) + @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + fun testDisplayAdded_cannotEnterDesktopMode_doesNotCreateDesk() = + testScope.runTest { + whenever(DesktopModeStatus.canEnterDesktopMode(context)).thenReturn(false) + desktopRepositoryInitializer.initialize(mockDesktopUserRepositories) - onDisplaysChangedListenerCaptor.lastValue.onDisplayAdded(DEFAULT_DISPLAY) + onDisplaysChangedListenerCaptor.lastValue.onDisplayAdded(DEFAULT_DISPLAY) + runCurrent() - verify(mockDesktopTasksController, never()).createDesk(DEFAULT_DISPLAY) - } + verify(mockDesktopTasksController, never()).createDesk(DEFAULT_DISPLAY) + } @Test @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) - fun testDeskRemoved_noDesksRemain_createsDesk() { - whenever(mockDesktopRepository.getNumberOfDesks(DEFAULT_DISPLAY)).thenReturn(0) + fun testDeskRemoved_noDesksRemain_createsDesk() = + testScope.runTest { + whenever(DesktopModeStatus.canEnterDesktopMode(context)).thenReturn(true) + whenever(mockDesktopRepository.getNumberOfDesks(DEFAULT_DISPLAY)).thenReturn(0) + desktopRepositoryInitializer.initialize(mockDesktopUserRepositories) - handler.onDeskRemoved(DEFAULT_DISPLAY, deskId = 1) + handler.onDeskRemoved(DEFAULT_DISPLAY, deskId = 1) + runCurrent() - verify(mockDesktopTasksController).createDesk(DEFAULT_DISPLAY) - } + verify(mockDesktopTasksController).createDesk(DEFAULT_DISPLAY) + } @Test @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) - fun testDeskRemoved_desksRemain_doesNotCreateDesk() { - whenever(mockDesktopRepository.getNumberOfDesks(DEFAULT_DISPLAY)).thenReturn(1) + fun testDeskRemoved_desksRemain_doesNotCreateDesk() = + testScope.runTest { + whenever(DesktopModeStatus.canEnterDesktopMode(context)).thenReturn(true) + whenever(mockDesktopRepository.getNumberOfDesks(DEFAULT_DISPLAY)).thenReturn(1) + desktopRepositoryInitializer.initialize(mockDesktopUserRepositories) + + handler.onDeskRemoved(DEFAULT_DISPLAY, deskId = 1) + runCurrent() - handler.onDeskRemoved(DEFAULT_DISPLAY, deskId = 1) + verify(mockDesktopTasksController, never()).createDesk(DEFAULT_DISPLAY) + } - verify(mockDesktopTasksController, never()).createDesk(DEFAULT_DISPLAY) - } + @Test + @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) + fun testUserChanged_createsDeskWhenNeeded() = + testScope.runTest { + whenever(DesktopModeStatus.canEnterDesktopMode(context)).thenReturn(true) + val userChangeListenerCaptor = argumentCaptor<UserChangeListener>() + verify(mockShellController).addUserChangeListener(userChangeListenerCaptor.capture()) + whenever(mockDesktopRepository.getNumberOfDesks(displayId = 2)).thenReturn(0) + whenever(mockDesktopRepository.getNumberOfDesks(displayId = 3)).thenReturn(0) + whenever(mockDesktopRepository.getNumberOfDesks(displayId = 4)).thenReturn(1) + whenever(mockRootTaskDisplayAreaOrganizer.displayIds).thenReturn(intArrayOf(2, 3, 4)) + desktopRepositoryInitializer.initialize(mockDesktopUserRepositories) + handler.onDisplayAdded(displayId = 2) + handler.onDisplayAdded(displayId = 3) + handler.onDisplayAdded(displayId = 4) + runCurrent() + + clearInvocations(mockDesktopTasksController) + userChangeListenerCaptor.lastValue.onUserChanged(1, context) + runCurrent() + + verify(mockDesktopTasksController).createDesk(displayId = 2) + verify(mockDesktopTasksController).createDesk(displayId = 3) + verify(mockDesktopTasksController, never()).createDesk(displayId = 4) + } @Test fun testConnectExternalDisplay() { |