Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +4 −0 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -1355,7 +1357,9 @@ public abstract class WMShellModule { context, shellInit, mainScope, shellController, displayController, rootTaskDisplayAreaOrganizer, desktopRepositoryInitializer, desktopUserRepositories.get(), desktopTasksController.get(), Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt +45 −20 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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, Loading @@ -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()) } } ) } } Loading @@ -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) { Loading @@ -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() } } } Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt +65 −15 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading Loading @@ -89,7 +95,9 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { context, shellInit, testScope.backgroundScope, mockShellController, displayController, mockRootTaskDisplayAreaOrganizer, desktopRepositoryInitializer, mockDesktopUserRepositories, mockDesktopTasksController, Loading @@ -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) Loading @@ -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) Loading @@ -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) Loading @@ -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) Loading @@ -156,34 +168,72 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { } @Test fun testDisplayAdded_cannotEnterDesktopMode_doesNotCreateDesk() { @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) runCurrent() verify(mockDesktopTasksController, never()).createDesk(DEFAULT_DISPLAY) } @Test @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun testDeskRemoved_noDesksRemain_createsDesk() { 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) runCurrent() verify(mockDesktopTasksController).createDesk(DEFAULT_DISPLAY) } @Test @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun testDeskRemoved_desksRemain_doesNotCreateDesk() { 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() 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() { onDisplaysChangedListenerCaptor.lastValue.onDisplayAdded(externalDisplayId) Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +4 −0 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -1355,7 +1357,9 @@ public abstract class WMShellModule { context, shellInit, mainScope, shellController, displayController, rootTaskDisplayAreaOrganizer, desktopRepositoryInitializer, desktopUserRepositories.get(), desktopTasksController.get(), Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt +45 −20 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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, Loading @@ -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()) } } ) } } Loading @@ -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) { Loading @@ -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() } } } Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt +65 −15 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading Loading @@ -89,7 +95,9 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { context, shellInit, testScope.backgroundScope, mockShellController, displayController, mockRootTaskDisplayAreaOrganizer, desktopRepositoryInitializer, mockDesktopUserRepositories, mockDesktopTasksController, Loading @@ -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) Loading @@ -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) Loading @@ -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) Loading @@ -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) Loading @@ -156,34 +168,72 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { } @Test fun testDisplayAdded_cannotEnterDesktopMode_doesNotCreateDesk() { @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) runCurrent() verify(mockDesktopTasksController, never()).createDesk(DEFAULT_DISPLAY) } @Test @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun testDeskRemoved_noDesksRemain_createsDesk() { 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) runCurrent() verify(mockDesktopTasksController).createDesk(DEFAULT_DISPLAY) } @Test @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun testDeskRemoved_desksRemain_doesNotCreateDesk() { 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() 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() { onDisplaysChangedListenerCaptor.lastValue.onDisplayAdded(externalDisplayId) Loading