Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +2 −0 Original line number Diff line number Diff line Loading @@ -810,6 +810,7 @@ public abstract class WMShellModule { RecentsTransitionHandler recentsTransitionHandler, MultiInstanceHelper multiInstanceHelper, @ShellMainThread ShellExecutor mainExecutor, @ShellMainThread CoroutineScope mainScope, @ShellMainThread Handler mainHandler, @ShellDesktopThread ShellExecutor desktopExecutor, Optional<DesktopTasksLimiter> desktopTasksLimiter, Loading Loading @@ -856,6 +857,7 @@ public abstract class WMShellModule { recentsTransitionHandler, multiInstanceHelper, mainExecutor, mainScope, desktopExecutor, desktopTasksLimiter, recentTasksController.orElse(null), Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +55 −15 Original line number Diff line number Diff line Loading @@ -131,6 +131,7 @@ import com.android.wm.shell.recents.RecentsTransitionHandler import com.android.wm.shell.recents.RecentsTransitionStateListener import com.android.wm.shell.recents.RecentsTransitionStateListener.RecentsTransitionState import com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_NOT_RUNNING import com.android.wm.shell.shared.R as SharedR import com.android.wm.shell.shared.TransitionUtil import com.android.wm.shell.shared.annotations.ExternalThread import com.android.wm.shell.shared.annotations.ShellDesktopThread Loading Loading @@ -169,7 +170,8 @@ import java.util.concurrent.TimeUnit import java.util.function.Consumer import kotlin.coroutines.suspendCoroutine import kotlin.jvm.optionals.getOrNull import com.android.wm.shell.shared.R as SharedR import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch /** * A callback to be invoked when a transition is started via |Transitions.startTransition| with the Loading Loading @@ -207,6 +209,7 @@ class DesktopTasksController( private val recentsTransitionHandler: RecentsTransitionHandler, private val multiInstanceHelper: MultiInstanceHelper, @ShellMainThread private val mainExecutor: ShellExecutor, @ShellMainThread private val mainScope: CoroutineScope, @ShellDesktopThread private val desktopExecutor: ShellExecutor, private val desktopTasksLimiter: Optional<DesktopTasksLimiter>, private val recentTasksController: RecentTasksController?, Loading Loading @@ -487,8 +490,16 @@ class DesktopTasksController( runOnTransitStart?.invoke(transition) } /** Adds a new desk to the given display for the given user. */ fun createDesk(displayId: Int, userId: Int = this.userId, activateDesk: Boolean = false) { /** * Adds a new desk to the given display for the given user and invokes [onResult] once the desk * is created, but necessarily activated. */ fun createDesk( displayId: Int, userId: Int = this.userId, activateDesk: Boolean = false, onResult: ((Int) -> Unit) = {}, ) { logV("addDesk displayId=%d, userId=%d", displayId, userId) val repository = userRepositories.getProfile(userId) createDeskRoot(displayId, userId) { deskId -> Loading @@ -496,6 +507,7 @@ class DesktopTasksController( logW("Failed to add desk in displayId=%d for userId=%d", displayId, userId) } else { repository.addDesk(displayId = displayId, deskId = deskId) onResult(deskId) if (activateDesk) { activateDesk(deskId) } Loading @@ -503,7 +515,7 @@ class DesktopTasksController( } } @Deprecated("Use createDesk() instead.", ReplaceWith("createDesk()")) @Deprecated("Use createDeskSuspending() instead.", ReplaceWith("createDeskSuspending()")) private fun createDeskImmediate(displayId: Int, userId: Int = this.userId): Int? { logV("createDeskImmediate displayId=%d, userId=%d", displayId, userId) val repository = userRepositories.getProfile(userId) Loading @@ -516,6 +528,11 @@ class DesktopTasksController( return deskId } private suspend fun createDeskSuspending(displayId: Int, userId: Int): Int = suspendCoroutine { cont -> createDesk(displayId, userId) { deskId -> cont.resumeWith(Result.success(deskId)) } } private fun createDeskRoot( displayId: Int, userId: Int = this.userId, Loading @@ -538,6 +555,7 @@ class DesktopTasksController( UserHandle.USER_SYSTEM == userId ) { logW("createDesk ignoring attempt for system user") onResult(null) return } desksOrganizer.createDesk(displayId, userId) { deskId -> Loading Loading @@ -665,6 +683,7 @@ class DesktopTasksController( return false } val displayId = getDisplayIdForTaskOrDefault(task) if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { val deskId = getOrCreateDefaultDeskId(displayId) ?: return false return moveTaskToDesk( taskId = taskId, Loading @@ -674,6 +693,21 @@ class DesktopTasksController( remoteTransition = remoteTransition, ) } mainScope.launch { try { moveTaskToDesk( taskId = taskId, deskId = getOrCreateDefaultDeskIdSuspending(displayId), wct = wct, transitionSource = transitionSource, remoteTransition = remoteTransition, ) } catch (t: Throwable) { logE("Failed to move task to default desk: %s", t.message) } } return true } /** Moves task to desktop mode if task is running, else launches it in desktop mode. */ fun moveTaskToDesk( Loading Loading @@ -3420,10 +3454,13 @@ class DesktopTasksController( * that a non-null desk can be returned by this function because even if one does not exist yet, * [createDeskImmediate] should succeed. * * TODO: b/406890311 - replace with a suspending version that can wait for a desk to be created * from scratch before continuing their normal flow. * TODO: b/406890311 - replace callers with [getOrCreateDefaultDeskIdSuspending], which is safer * because it does not depend on pre-creating desk roots. */ @Deprecated("Use createDesk() instead", ReplaceWith("createDesk()")) @Deprecated( "Use getOrCreateDefaultDeskIdSuspending() instead", ReplaceWith("getOrCreateDefaultDeskIdSuspending()"), ) private fun getOrCreateDefaultDeskId(displayId: Int): Int? { val existingDefaultDeskId = taskRepository.getDefaultDeskId(displayId) if (existingDefaultDeskId != null) { Loading @@ -3441,6 +3478,9 @@ class DesktopTasksController( return immediateDeskId } private suspend fun getOrCreateDefaultDeskIdSuspending(displayId: Int): Int = taskRepository.getDefaultDeskId(displayId) ?: createDeskSuspending(displayId, userId) /** Removes the given desk. */ fun removeDesk(deskId: Int) { val displayId = taskRepository.getDisplayForDesk(deskId) Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt +37 −15 Original line number Diff line number Diff line Loading @@ -126,7 +126,7 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { runCurrent() verify(mockDesktopTasksController) .createDesk(eq(SECOND_DISPLAY), eq(PRIMARY_USER_ID), any()) .createDesk(eq(SECOND_DISPLAY), eq(PRIMARY_USER_ID), any(), any()) } @Test Loading Loading @@ -159,9 +159,10 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { verify(mockDesktopTasksController) .createDesk( displayId = desktopFirstDisplay, userId = mockDesktopRepository.userId, activateDesk = true, displayId = eq(desktopFirstDisplay), userId = eq(PRIMARY_USER_ID), activateDesk = eq(true), onResult = any(), ) } Loading @@ -175,7 +176,7 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { runCurrent() verify(mockDesktopTasksController, never()) .createDesk(eq(DEFAULT_DISPLAY), any(), any()) .createDesk(eq(DEFAULT_DISPLAY), any(), any(), any()) } @Test Loading @@ -190,7 +191,7 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { runCurrent() verify(mockDesktopTasksController, times(1)) .createDesk(eq(SECOND_DISPLAY), eq(PRIMARY_USER_ID), any()) .createDesk(eq(SECOND_DISPLAY), eq(PRIMARY_USER_ID), any(), any()) } @Test Loading Loading @@ -220,7 +221,7 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { runCurrent() verify(mockDesktopTasksController, never()) .createDesk(eq(DEFAULT_DISPLAY), any(), any()) .createDesk(eq(DEFAULT_DISPLAY), any(), any(), any()) verify(mockDesksOrganizer, never()) .warmUpDefaultDesk(DEFAULT_DISPLAY, mockDesktopRepository.userId) } Loading @@ -236,7 +237,7 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { runCurrent() verify(mockDesktopTasksController, never()) .createDesk(eq(DEFAULT_DISPLAY), any(), any()) .createDesk(eq(DEFAULT_DISPLAY), any(), any(), any()) verify(mockDesksOrganizer, never()) .warmUpDefaultDesk(DEFAULT_DISPLAY, mockDesktopRepository.userId) } Loading @@ -253,7 +254,12 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { runCurrent() verify(mockDesktopTasksController) .createDesk(eq(SECOND_DISPLAY), eq(PRIMARY_USER_ID), activateDesk = any()) .createDesk( eq(SECOND_DISPLAY), eq(PRIMARY_USER_ID), activateDesk = any(), onResult = any(), ) } @Test Loading Loading @@ -288,9 +294,10 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { verify(mockDesktopTasksController) .createDesk( displayId = desktopFirstDisplay, userId = mockDesktopRepository.userId, activateDesk = true, displayId = eq(desktopFirstDisplay), userId = eq(PRIMARY_USER_ID), activateDesk = eq(true), onResult = any(), ) } Loading Loading @@ -341,11 +348,26 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { runCurrent() verify(mockDesktopTasksController) .createDesk(displayId = eq(2), userId = eq(userId), activateDesk = any()) .createDesk( displayId = eq(2), userId = eq(userId), activateDesk = any(), onResult = any(), ) verify(mockDesktopTasksController) .createDesk(displayId = eq(3), userId = eq(userId), activateDesk = any()) .createDesk( displayId = eq(3), userId = eq(userId), activateDesk = any(), onResult = any(), ) verify(mockDesktopTasksController, never()) .createDesk(displayId = eq(4), userId = any(), activateDesk = any()) .createDesk( displayId = eq(4), userId = any(), activateDesk = any(), onResult = any(), ) } @Test Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +431 −380 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +2 −0 Original line number Diff line number Diff line Loading @@ -810,6 +810,7 @@ public abstract class WMShellModule { RecentsTransitionHandler recentsTransitionHandler, MultiInstanceHelper multiInstanceHelper, @ShellMainThread ShellExecutor mainExecutor, @ShellMainThread CoroutineScope mainScope, @ShellMainThread Handler mainHandler, @ShellDesktopThread ShellExecutor desktopExecutor, Optional<DesktopTasksLimiter> desktopTasksLimiter, Loading Loading @@ -856,6 +857,7 @@ public abstract class WMShellModule { recentsTransitionHandler, multiInstanceHelper, mainExecutor, mainScope, desktopExecutor, desktopTasksLimiter, recentTasksController.orElse(null), Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +55 −15 Original line number Diff line number Diff line Loading @@ -131,6 +131,7 @@ import com.android.wm.shell.recents.RecentsTransitionHandler import com.android.wm.shell.recents.RecentsTransitionStateListener import com.android.wm.shell.recents.RecentsTransitionStateListener.RecentsTransitionState import com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_NOT_RUNNING import com.android.wm.shell.shared.R as SharedR import com.android.wm.shell.shared.TransitionUtil import com.android.wm.shell.shared.annotations.ExternalThread import com.android.wm.shell.shared.annotations.ShellDesktopThread Loading Loading @@ -169,7 +170,8 @@ import java.util.concurrent.TimeUnit import java.util.function.Consumer import kotlin.coroutines.suspendCoroutine import kotlin.jvm.optionals.getOrNull import com.android.wm.shell.shared.R as SharedR import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch /** * A callback to be invoked when a transition is started via |Transitions.startTransition| with the Loading Loading @@ -207,6 +209,7 @@ class DesktopTasksController( private val recentsTransitionHandler: RecentsTransitionHandler, private val multiInstanceHelper: MultiInstanceHelper, @ShellMainThread private val mainExecutor: ShellExecutor, @ShellMainThread private val mainScope: CoroutineScope, @ShellDesktopThread private val desktopExecutor: ShellExecutor, private val desktopTasksLimiter: Optional<DesktopTasksLimiter>, private val recentTasksController: RecentTasksController?, Loading Loading @@ -487,8 +490,16 @@ class DesktopTasksController( runOnTransitStart?.invoke(transition) } /** Adds a new desk to the given display for the given user. */ fun createDesk(displayId: Int, userId: Int = this.userId, activateDesk: Boolean = false) { /** * Adds a new desk to the given display for the given user and invokes [onResult] once the desk * is created, but necessarily activated. */ fun createDesk( displayId: Int, userId: Int = this.userId, activateDesk: Boolean = false, onResult: ((Int) -> Unit) = {}, ) { logV("addDesk displayId=%d, userId=%d", displayId, userId) val repository = userRepositories.getProfile(userId) createDeskRoot(displayId, userId) { deskId -> Loading @@ -496,6 +507,7 @@ class DesktopTasksController( logW("Failed to add desk in displayId=%d for userId=%d", displayId, userId) } else { repository.addDesk(displayId = displayId, deskId = deskId) onResult(deskId) if (activateDesk) { activateDesk(deskId) } Loading @@ -503,7 +515,7 @@ class DesktopTasksController( } } @Deprecated("Use createDesk() instead.", ReplaceWith("createDesk()")) @Deprecated("Use createDeskSuspending() instead.", ReplaceWith("createDeskSuspending()")) private fun createDeskImmediate(displayId: Int, userId: Int = this.userId): Int? { logV("createDeskImmediate displayId=%d, userId=%d", displayId, userId) val repository = userRepositories.getProfile(userId) Loading @@ -516,6 +528,11 @@ class DesktopTasksController( return deskId } private suspend fun createDeskSuspending(displayId: Int, userId: Int): Int = suspendCoroutine { cont -> createDesk(displayId, userId) { deskId -> cont.resumeWith(Result.success(deskId)) } } private fun createDeskRoot( displayId: Int, userId: Int = this.userId, Loading @@ -538,6 +555,7 @@ class DesktopTasksController( UserHandle.USER_SYSTEM == userId ) { logW("createDesk ignoring attempt for system user") onResult(null) return } desksOrganizer.createDesk(displayId, userId) { deskId -> Loading Loading @@ -665,6 +683,7 @@ class DesktopTasksController( return false } val displayId = getDisplayIdForTaskOrDefault(task) if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { val deskId = getOrCreateDefaultDeskId(displayId) ?: return false return moveTaskToDesk( taskId = taskId, Loading @@ -674,6 +693,21 @@ class DesktopTasksController( remoteTransition = remoteTransition, ) } mainScope.launch { try { moveTaskToDesk( taskId = taskId, deskId = getOrCreateDefaultDeskIdSuspending(displayId), wct = wct, transitionSource = transitionSource, remoteTransition = remoteTransition, ) } catch (t: Throwable) { logE("Failed to move task to default desk: %s", t.message) } } return true } /** Moves task to desktop mode if task is running, else launches it in desktop mode. */ fun moveTaskToDesk( Loading Loading @@ -3420,10 +3454,13 @@ class DesktopTasksController( * that a non-null desk can be returned by this function because even if one does not exist yet, * [createDeskImmediate] should succeed. * * TODO: b/406890311 - replace with a suspending version that can wait for a desk to be created * from scratch before continuing their normal flow. * TODO: b/406890311 - replace callers with [getOrCreateDefaultDeskIdSuspending], which is safer * because it does not depend on pre-creating desk roots. */ @Deprecated("Use createDesk() instead", ReplaceWith("createDesk()")) @Deprecated( "Use getOrCreateDefaultDeskIdSuspending() instead", ReplaceWith("getOrCreateDefaultDeskIdSuspending()"), ) private fun getOrCreateDefaultDeskId(displayId: Int): Int? { val existingDefaultDeskId = taskRepository.getDefaultDeskId(displayId) if (existingDefaultDeskId != null) { Loading @@ -3441,6 +3478,9 @@ class DesktopTasksController( return immediateDeskId } private suspend fun getOrCreateDefaultDeskIdSuspending(displayId: Int): Int = taskRepository.getDefaultDeskId(displayId) ?: createDeskSuspending(displayId, userId) /** Removes the given desk. */ fun removeDesk(deskId: Int) { val displayId = taskRepository.getDisplayForDesk(deskId) Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt +37 −15 Original line number Diff line number Diff line Loading @@ -126,7 +126,7 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { runCurrent() verify(mockDesktopTasksController) .createDesk(eq(SECOND_DISPLAY), eq(PRIMARY_USER_ID), any()) .createDesk(eq(SECOND_DISPLAY), eq(PRIMARY_USER_ID), any(), any()) } @Test Loading Loading @@ -159,9 +159,10 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { verify(mockDesktopTasksController) .createDesk( displayId = desktopFirstDisplay, userId = mockDesktopRepository.userId, activateDesk = true, displayId = eq(desktopFirstDisplay), userId = eq(PRIMARY_USER_ID), activateDesk = eq(true), onResult = any(), ) } Loading @@ -175,7 +176,7 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { runCurrent() verify(mockDesktopTasksController, never()) .createDesk(eq(DEFAULT_DISPLAY), any(), any()) .createDesk(eq(DEFAULT_DISPLAY), any(), any(), any()) } @Test Loading @@ -190,7 +191,7 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { runCurrent() verify(mockDesktopTasksController, times(1)) .createDesk(eq(SECOND_DISPLAY), eq(PRIMARY_USER_ID), any()) .createDesk(eq(SECOND_DISPLAY), eq(PRIMARY_USER_ID), any(), any()) } @Test Loading Loading @@ -220,7 +221,7 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { runCurrent() verify(mockDesktopTasksController, never()) .createDesk(eq(DEFAULT_DISPLAY), any(), any()) .createDesk(eq(DEFAULT_DISPLAY), any(), any(), any()) verify(mockDesksOrganizer, never()) .warmUpDefaultDesk(DEFAULT_DISPLAY, mockDesktopRepository.userId) } Loading @@ -236,7 +237,7 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { runCurrent() verify(mockDesktopTasksController, never()) .createDesk(eq(DEFAULT_DISPLAY), any(), any()) .createDesk(eq(DEFAULT_DISPLAY), any(), any(), any()) verify(mockDesksOrganizer, never()) .warmUpDefaultDesk(DEFAULT_DISPLAY, mockDesktopRepository.userId) } Loading @@ -253,7 +254,12 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { runCurrent() verify(mockDesktopTasksController) .createDesk(eq(SECOND_DISPLAY), eq(PRIMARY_USER_ID), activateDesk = any()) .createDesk( eq(SECOND_DISPLAY), eq(PRIMARY_USER_ID), activateDesk = any(), onResult = any(), ) } @Test Loading Loading @@ -288,9 +294,10 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { verify(mockDesktopTasksController) .createDesk( displayId = desktopFirstDisplay, userId = mockDesktopRepository.userId, activateDesk = true, displayId = eq(desktopFirstDisplay), userId = eq(PRIMARY_USER_ID), activateDesk = eq(true), onResult = any(), ) } Loading Loading @@ -341,11 +348,26 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { runCurrent() verify(mockDesktopTasksController) .createDesk(displayId = eq(2), userId = eq(userId), activateDesk = any()) .createDesk( displayId = eq(2), userId = eq(userId), activateDesk = any(), onResult = any(), ) verify(mockDesktopTasksController) .createDesk(displayId = eq(3), userId = eq(userId), activateDesk = any()) .createDesk( displayId = eq(3), userId = eq(userId), activateDesk = any(), onResult = any(), ) verify(mockDesktopTasksController, never()) .createDesk(displayId = eq(4), userId = any(), activateDesk = any()) .createDesk( displayId = eq(4), userId = any(), activateDesk = any(), onResult = any(), ) } @Test Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +431 −380 File changed.Preview size limit exceeded, changes collapsed. Show changes