Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +3 −2 Original line number Diff line number Diff line Loading @@ -785,10 +785,11 @@ public abstract class WMShellModule { @NonNull ShellInit shellInit, @NonNull ShellCommandHandler shellCommandHandler, @NonNull ShellTaskOrganizer shellTaskOrganizer, @NonNull LaunchAdjacentController launchAdjacentController @NonNull LaunchAdjacentController launchAdjacentController, @NonNull RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer ) { return new RootTaskDesksOrganizer(shellInit, shellCommandHandler, shellTaskOrganizer, launchAdjacentController); launchAdjacentController, rootTaskDisplayAreaOrganizer); } @WMSingleton Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt +1 −13 Original line number Diff line number Diff line Loading @@ -34,7 +34,6 @@ import com.android.wm.shell.desktopmode.desktopfirst.DesktopDisplayModeControlle import com.android.wm.shell.desktopmode.desktopfirst.isDisplayDesktopFirst import com.android.wm.shell.desktopmode.multidesks.DesksOrganizer import com.android.wm.shell.desktopmode.multidesks.DesksTransitionObserver import com.android.wm.shell.desktopmode.multidesks.OnDeskDisplayChangeListener 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 Loading @@ -60,7 +59,7 @@ class DesktopDisplayEventHandler( private val desktopDisplayModeController: DesktopDisplayModeController, private val desksTransitionObserver: DesksTransitionObserver, private val desktopState: DesktopState, ) : OnDisplaysChangedListener, OnDeskRemovedListener, OnDeskDisplayChangeListener { ) : OnDisplaysChangedListener, OnDeskRemovedListener { private val onDisplayAreaChangeListener = OnDisplayAreaChangeListener { displayId -> logV("displayAreaChanged in displayId=%d", displayId) Loading @@ -85,10 +84,6 @@ class DesktopDisplayEventHandler( } } ) if (DesktopExperienceFlags.ENABLE_DISPLAY_DISCONNECT_INTERACTION.isTrue) { desksTransitionObserver.deskDisplayChangeListener = this } } } Loading Loading @@ -173,13 +168,6 @@ class DesktopDisplayEventHandler( } } override fun onDeskDisplayChange( deskDisplayChanges: Set<OnDeskDisplayChangeListener.DeskDisplayChange> ) { if (!DesktopExperienceFlags.ENABLE_DISPLAY_DISCONNECT_INTERACTION.isTrue()) return desktopTasksController.onDeskDisconnectTransition(deskDisplayChanges) } private fun shouldCreateOrWarmUpDesk(displayId: Int, repository: DesktopRepository): Boolean { if (displayId == Display.INVALID_DISPLAY) { logV("shouldCreateOrWarmUpDesk skipping reason: invalid display") Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt +20 −2 Original line number Diff line number Diff line Loading @@ -234,8 +234,15 @@ class DesktopRepository( } } /** Removes any references to the removed display. */ fun removeDisplay(displayId: Int) { val deskIdsToRemove = getAllDeskIds().filter { deskId -> getDisplayForDesk(deskId) == displayId } deskIdsToRemove.forEach { deskId -> removeDesk(deskId) } desktopData.removeDisplay(displayId) } /** Returns the ids of the existing desks in the given display. */ @VisibleForTesting fun getDeskIds(displayId: Int): Set<Int> = desktopData.desksSequence(displayId).map { desk -> desk.deskId }.toSet() Loading Loading @@ -579,7 +586,7 @@ class DesktopRepository( /** Whether the display has only one visible desktop task. */ fun hasOnlyOneVisibleTask(displayId: Int): Boolean = getVisibleTaskCount(displayId) == 1 @VisibleForTesting /** Get all taskIds of the active desktop tasks in the given display. */ fun getActiveTasks(displayId: Int): ArraySet<Int> = ArraySet(desktopData.getActiveDesk(displayId)?.activeTasks) Loading Loading @@ -1234,6 +1241,9 @@ class DesktopRepository( /** Returns the id of the display where the given desk is located. */ fun getDisplayForDesk(deskId: Int): Int /** Perform needed cleanup when a display is removed. */ fun removeDisplay(displayId: Int) } /** Loading Loading @@ -1319,6 +1329,10 @@ class DesktopRepository( } override fun getDisplayForDesk(deskId: Int): Int = deskId override fun removeDisplay(displayId: Int) { deskByDisplayId.remove(displayId) } } /** A [DesktopData] implementation that supports multiple desks. */ Loading Loading @@ -1438,6 +1452,10 @@ class DesktopRepository( override fun getDisplayForDesk(deskId: Int): Int = desksSequence().find { it.deskId == deskId }?.displayId ?: error("Display for desk=$deskId not found") override fun removeDisplay(displayId: Int) { desktopDisplays.remove(displayId) } } private fun logD(msg: String, vararg arguments: Any?) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +127 −53 Original line number Diff line number Diff line Loading @@ -121,7 +121,6 @@ import com.android.wm.shell.desktopmode.minimize.DesktopWindowLimitRemoteHandler import com.android.wm.shell.desktopmode.multidesks.DeskTransition import com.android.wm.shell.desktopmode.multidesks.DesksOrganizer import com.android.wm.shell.desktopmode.multidesks.DesksTransitionObserver import com.android.wm.shell.desktopmode.multidesks.OnDeskDisplayChangeListener import com.android.wm.shell.desktopmode.multidesks.OnDeskRemovedListener import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer.DeskRecreationFactory Loading Loading @@ -622,36 +621,70 @@ class DesktopTasksController( createDeskRoot(displayId, userId) { deskId -> cont.resumeWith(Result.success(deskId)) } } /** * Handle desk operations resulting from a display disconnect transition. Forks to two separate * methods depending on whether the destination display supports desktop mode. * * @param deskDisconnectChanges the individual changes resulting from the disconnect */ fun onDeskDisconnectTransition( deskDisconnectChanges: Set<OnDeskDisplayChangeListener.DeskDisplayChange> ) { private fun onDisplayDisconnect( disconnectedDisplayId: Int, destinationDisplayId: Int, transition: IBinder, ): WindowContainerTransaction { // TODO: b/406320371 - Verify this works with non-system users once the underlying bug is // resolved. val wct = WindowContainerTransaction() // TODO(b/391652399): Remove the wallpaper of the disconnected display. val transitStartRunnables = mutableSetOf<RunOnTransitStart?>() for (change in deskDisconnectChanges) { if (desktopState.isDesktopModeSupportedOnDisplay(change.destinationDisplayId)) { transitStartRunnables.add( updateDesksActivationOnDisconnection( disconnectedDisplayActiveDesk = change.deskId, wct = wct, change.toTop, ) // TODO: b/391652399 - Investigate why sometimes disconnect results in a black background. // Additionally, investigate why wallpaper goes to front for inactive users. removeWallpaperTask(wct, disconnectedDisplayId) removeHomeTask(wct, disconnectedDisplayId) userRepositories.forAllRepositories { desktopRepository -> val deskIds = desktopRepository.getDeskIds(disconnectedDisplayId).toList() if (desktopState.isDesktopModeSupportedOnDisplay(destinationDisplayId)) { // Desktop supported on display; reparent desks, focused desk on top. for (deskId in deskIds) { val toTop = desktopRepository .getActiveTasks(disconnectedDisplayId) .contains(focusTransitionObserver.globallyFocusedTaskId) desksOrganizer.moveDeskToDisplay(wct, deskId, destinationDisplayId, toTop) desksTransitionObserver.addPendingTransition( DeskTransition.ChangeDeskDisplay(transition, deskId, destinationDisplayId) ) updateDesksActivationOnDisconnection(deskId, destinationDisplayId, wct, toTop) ?.invoke(transition) } } else { // TODO(b/391652399): Implement desktop-not-supported case. // Desktop not supported on display; reparent tasks to display area, remove desk. val tdaInfo = checkNotNull( rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(destinationDisplayId) ) { "Expected to find displayAreaInfo for displayId=$destinationDisplayId" } for (deskId in deskIds) { val taskIds = desktopRepository.getActiveTaskIdsInDesk(deskId) for (taskId in taskIds) { val task = shellTaskOrganizer.getRunningTaskInfo(taskId) ?: continue wct.reparent( task.token, tdaInfo.token, focusTransitionObserver.globallyFocusedTaskId == task.taskId, ) } desksOrganizer.removeDesk(wct, deskId, userId) desksTransitionObserver.addPendingTransition( DeskTransition.RemoveDesk( token = transition, displayId = disconnectedDisplayId, deskId = deskId, tasks = emptySet(), onDeskRemovedListener = onDeskRemovedListener, ) ) desksTransitionObserver.addPendingTransition( DeskTransition.RemoveDisplay(transition, disconnectedDisplayId) ) } val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null) for (transitStartRunnable in transitStartRunnables) { transitStartRunnable?.invoke(transition) } } return wct } /** * Handle desk operations when disconnecting a display and all desks on that display are moving Loading @@ -664,6 +697,7 @@ class DesktopTasksController( @VisibleForTesting fun updateDesksActivationOnDisconnection( disconnectedDisplayActiveDesk: Int, destinationDisplayId: Int, wct: WindowContainerTransaction, toTop: Boolean, ): RunOnTransitStart? { Loading @@ -671,7 +705,11 @@ class DesktopTasksController( if (toTop) { // The disconnected display's active desk was reparented to the top, activate it // here. addDeskActivationChanges(disconnectedDisplayActiveDesk, wct) addDeskActivationChanges( deskId = disconnectedDisplayActiveDesk, wct = wct, displayId = destinationDisplayId, ) } else { // The disconnected display's active desk was reparented to the back, ensure it is // no longer an active launch root. Loading Loading @@ -932,9 +970,9 @@ class DesktopTasksController( // |moveHomeTask| is also called in |bringDesktopAppsToFrontBeforeShowingNewTask|, so // this shouldn't be necessary at all. if (ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY.isTrue) { moveHomeTask(taskInfo.displayId, wct) moveHomeTaskToTop(taskInfo.displayId, wct) } else { moveHomeTask(context.displayId, wct) moveHomeTaskToTop(context.displayId, wct) } } val runOnTransitStart = addDeskActivationWithMovingTaskChanges(deskId, wct, taskInfo) Loading Loading @@ -1260,7 +1298,7 @@ class DesktopTasksController( // We are moving a freeform task to fullscreen, put the home task under the fullscreen task. if (!forceEnterDesktop(displayId)) { moveHomeTask(displayId, wct) moveHomeTaskToTop(displayId, wct) wct.reorder(task.token, /* onTop= */ true) } Loading Loading @@ -2085,7 +2123,10 @@ class DesktopTasksController( val useParamDisplayId = DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue || ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY.isTrue moveHomeTask(displayId = if (useParamDisplayId) displayId else context.displayId, wct = wct) moveHomeTaskToTop( displayId = if (useParamDisplayId) displayId else context.displayId, wct = wct, ) // Currently, we only handle the desktop on the default display really. if ( (displayId == DEFAULT_DISPLAY || Loading Loading @@ -2143,12 +2184,22 @@ class DesktopTasksController( return taskIdToMinimize } private fun moveHomeTask(displayId: Int, wct: WindowContainerTransaction) { logV("moveHomeTask in displayId=%d", displayId) shellTaskOrganizer .getRunningTasks(displayId) .firstOrNull { task -> task.activityType == ACTIVITY_TYPE_HOME } ?.let { homeTask -> wct.reorder(homeTask.getToken(), /* onTop= */ true) } private fun moveHomeTaskToTop(displayId: Int, wct: WindowContainerTransaction) { logV("moveHomeTaskToTop in displayId=%d", displayId) getHomeTask(displayId)?.let { homeTask -> wct.reorder(homeTask.getToken(), /* onTop= */ true) } } private fun removeHomeTask(wct: WindowContainerTransaction, displayId: Int) { logV("removeHomeTask in displayId=%d", displayId) getHomeTask(displayId)?.let { homeTask -> wct.removeRootTask(homeTask.getToken()) } } private fun getHomeTask(displayId: Int): RunningTaskInfo? { return shellTaskOrganizer.getRunningTasks(displayId).firstOrNull { task -> task.activityType == ACTIVITY_TYPE_HOME } } private fun addLaunchHomePendingIntent(wct: WindowContainerTransaction, displayId: Int) { Loading @@ -2157,7 +2208,7 @@ class DesktopTasksController( private fun addWallpaperActivity(displayId: Int, wct: WindowContainerTransaction) { logV("addWallpaperActivity") if (ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER.isTrue()) { if (ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER.isTrue) { // If the wallpaper activity for this display already exists, let's reorder it to top. val wallpaperActivityToken = desktopWallpaperActivityTokenProvider.getToken(displayId) Loading @@ -2165,7 +2216,6 @@ class DesktopTasksController( wct.reorder(wallpaperActivityToken, /* onTop= */ true) return } val intent = Intent(context, DesktopWallpaperActivity::class.java) if (ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY.isTrue) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) Loading Loading @@ -2222,15 +2272,18 @@ class DesktopTasksController( } } private fun removeWallpaperActivity(wct: WindowContainerTransaction, displayId: Int) { private fun moveWallpaperActivityToBack(wct: WindowContainerTransaction, displayId: Int) { desktopWallpaperActivityTokenProvider.getToken(displayId)?.let { token -> logV("removeWallpaperActivity") if (ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER.isTrue()) { logV("moveWallpaperActivityToBack") wct.reorder(token, /* onTop= */ false) } else { wct.removeTask(token) } } private fun removeWallpaperTask(wct: WindowContainerTransaction, displayId: Int) { desktopWallpaperActivityTokenProvider.getToken(displayId)?.let { token -> logV("removeWallpaperTask") wct.removeTask(token) } } private fun willExitDesktop( Loading Loading @@ -2295,7 +2348,11 @@ class DesktopTasksController( !skipWallpaperAndHomeOrdering || !DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue ) { removeWallpaperActivity(wct, displayId) if (ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER.isTrue) { moveWallpaperActivityToBack(wct, displayId) } else { removeWallpaperTask(wct, displayId) } if (shouldEndUpAtHome) { // If the transition should end up with user going to home, launch home with a // pending intent. Loading Loading @@ -2333,6 +2390,19 @@ class DesktopTasksController( request: TransitionRequestInfo, ): WindowContainerTransaction? { logV("handleRequest request=%s", request) // First, check if this is a display disconnect request. val displayChange = request.displayChange if ( DesktopExperienceFlags.ENABLE_DISPLAY_DISCONNECT_INTERACTION.isTrue && displayChange != null && displayChange.disconnectReparentDisplay != INVALID_DISPLAY ) { return onDisplayDisconnect( displayChange.displayId, displayChange.disconnectReparentDisplay, transition, ) } // Check if we should skip handling this transition var reason = "" val triggerTask = request.triggerTask Loading Loading @@ -3356,9 +3426,9 @@ class DesktopTasksController( // TODO: b/362720497 - should this be true in other places? Can it be calculated locally // without having to specify the value? addPendingLaunchTransition: Boolean = false, displayId: Int = taskRepository.getDisplayForDesk(deskId), ): RunOnTransitStart { val newTaskIdInFront = newTask?.taskId val displayId = taskRepository.getDisplayForDesk(deskId) logV( "addDeskActivationChanges newTaskId=%d deskId=%d displayId=%d", newTask?.taskId, Loading Loading @@ -3600,9 +3670,9 @@ class DesktopTasksController( taskRepository.getDefaultDeskId(displayId) ?: createDeskSuspending(displayId, userId) /** Removes the given desk. */ fun removeDesk(deskId: Int) { val displayId = taskRepository.getDisplayForDesk(deskId) removeDesk(displayId = displayId, deskId = deskId) fun removeDesk(deskId: Int, desktopRepository: DesktopRepository = taskRepository) { val displayId = desktopRepository.getDisplayForDesk(deskId) removeDesk(displayId = displayId, deskId = deskId, desktopRepository = desktopRepository) } /** Removes all the available desks on all displays. */ Loading @@ -3610,17 +3680,21 @@ class DesktopTasksController( taskRepository.getAllDeskIds().forEach { deskId -> removeDesk(deskId) } } private fun removeDesk(displayId: Int, deskId: Int) { private fun removeDesk( displayId: Int, deskId: Int, desktopRepository: DesktopRepository = taskRepository, ) { if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue()) return logV("removeDesk deskId=%d from displayId=%d", deskId, displayId) val tasksToRemove = if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { taskRepository.getActiveTaskIdsInDesk(deskId) desktopRepository.getActiveTaskIdsInDesk(deskId) } else { // TODO: 362720497 - make sure minimized windows are also removed in WM // and the repository. taskRepository.removeDesk(deskId) desktopRepository.removeDesk(deskId) } val wct = WindowContainerTransaction() Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopUserRepositories.kt +4 −0 Original line number Diff line number Diff line Loading @@ -158,6 +158,10 @@ class DesktopUserRepositories( } } /** Execute the provided callback for all repositories. */ fun forAllRepositories(repositoryCallback: (DesktopRepository) -> Unit) = desktopRepoByUserId.forEach { _, repository -> repositoryCallback(repository) } private fun logD(msg: String, vararg arguments: Any?) { ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) } Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +3 −2 Original line number Diff line number Diff line Loading @@ -785,10 +785,11 @@ public abstract class WMShellModule { @NonNull ShellInit shellInit, @NonNull ShellCommandHandler shellCommandHandler, @NonNull ShellTaskOrganizer shellTaskOrganizer, @NonNull LaunchAdjacentController launchAdjacentController @NonNull LaunchAdjacentController launchAdjacentController, @NonNull RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer ) { return new RootTaskDesksOrganizer(shellInit, shellCommandHandler, shellTaskOrganizer, launchAdjacentController); launchAdjacentController, rootTaskDisplayAreaOrganizer); } @WMSingleton Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt +1 −13 Original line number Diff line number Diff line Loading @@ -34,7 +34,6 @@ import com.android.wm.shell.desktopmode.desktopfirst.DesktopDisplayModeControlle import com.android.wm.shell.desktopmode.desktopfirst.isDisplayDesktopFirst import com.android.wm.shell.desktopmode.multidesks.DesksOrganizer import com.android.wm.shell.desktopmode.multidesks.DesksTransitionObserver import com.android.wm.shell.desktopmode.multidesks.OnDeskDisplayChangeListener 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 Loading @@ -60,7 +59,7 @@ class DesktopDisplayEventHandler( private val desktopDisplayModeController: DesktopDisplayModeController, private val desksTransitionObserver: DesksTransitionObserver, private val desktopState: DesktopState, ) : OnDisplaysChangedListener, OnDeskRemovedListener, OnDeskDisplayChangeListener { ) : OnDisplaysChangedListener, OnDeskRemovedListener { private val onDisplayAreaChangeListener = OnDisplayAreaChangeListener { displayId -> logV("displayAreaChanged in displayId=%d", displayId) Loading @@ -85,10 +84,6 @@ class DesktopDisplayEventHandler( } } ) if (DesktopExperienceFlags.ENABLE_DISPLAY_DISCONNECT_INTERACTION.isTrue) { desksTransitionObserver.deskDisplayChangeListener = this } } } Loading Loading @@ -173,13 +168,6 @@ class DesktopDisplayEventHandler( } } override fun onDeskDisplayChange( deskDisplayChanges: Set<OnDeskDisplayChangeListener.DeskDisplayChange> ) { if (!DesktopExperienceFlags.ENABLE_DISPLAY_DISCONNECT_INTERACTION.isTrue()) return desktopTasksController.onDeskDisconnectTransition(deskDisplayChanges) } private fun shouldCreateOrWarmUpDesk(displayId: Int, repository: DesktopRepository): Boolean { if (displayId == Display.INVALID_DISPLAY) { logV("shouldCreateOrWarmUpDesk skipping reason: invalid display") Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt +20 −2 Original line number Diff line number Diff line Loading @@ -234,8 +234,15 @@ class DesktopRepository( } } /** Removes any references to the removed display. */ fun removeDisplay(displayId: Int) { val deskIdsToRemove = getAllDeskIds().filter { deskId -> getDisplayForDesk(deskId) == displayId } deskIdsToRemove.forEach { deskId -> removeDesk(deskId) } desktopData.removeDisplay(displayId) } /** Returns the ids of the existing desks in the given display. */ @VisibleForTesting fun getDeskIds(displayId: Int): Set<Int> = desktopData.desksSequence(displayId).map { desk -> desk.deskId }.toSet() Loading Loading @@ -579,7 +586,7 @@ class DesktopRepository( /** Whether the display has only one visible desktop task. */ fun hasOnlyOneVisibleTask(displayId: Int): Boolean = getVisibleTaskCount(displayId) == 1 @VisibleForTesting /** Get all taskIds of the active desktop tasks in the given display. */ fun getActiveTasks(displayId: Int): ArraySet<Int> = ArraySet(desktopData.getActiveDesk(displayId)?.activeTasks) Loading Loading @@ -1234,6 +1241,9 @@ class DesktopRepository( /** Returns the id of the display where the given desk is located. */ fun getDisplayForDesk(deskId: Int): Int /** Perform needed cleanup when a display is removed. */ fun removeDisplay(displayId: Int) } /** Loading Loading @@ -1319,6 +1329,10 @@ class DesktopRepository( } override fun getDisplayForDesk(deskId: Int): Int = deskId override fun removeDisplay(displayId: Int) { deskByDisplayId.remove(displayId) } } /** A [DesktopData] implementation that supports multiple desks. */ Loading Loading @@ -1438,6 +1452,10 @@ class DesktopRepository( override fun getDisplayForDesk(deskId: Int): Int = desksSequence().find { it.deskId == deskId }?.displayId ?: error("Display for desk=$deskId not found") override fun removeDisplay(displayId: Int) { desktopDisplays.remove(displayId) } } private fun logD(msg: String, vararg arguments: Any?) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +127 −53 Original line number Diff line number Diff line Loading @@ -121,7 +121,6 @@ import com.android.wm.shell.desktopmode.minimize.DesktopWindowLimitRemoteHandler import com.android.wm.shell.desktopmode.multidesks.DeskTransition import com.android.wm.shell.desktopmode.multidesks.DesksOrganizer import com.android.wm.shell.desktopmode.multidesks.DesksTransitionObserver import com.android.wm.shell.desktopmode.multidesks.OnDeskDisplayChangeListener import com.android.wm.shell.desktopmode.multidesks.OnDeskRemovedListener import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer.DeskRecreationFactory Loading Loading @@ -622,36 +621,70 @@ class DesktopTasksController( createDeskRoot(displayId, userId) { deskId -> cont.resumeWith(Result.success(deskId)) } } /** * Handle desk operations resulting from a display disconnect transition. Forks to two separate * methods depending on whether the destination display supports desktop mode. * * @param deskDisconnectChanges the individual changes resulting from the disconnect */ fun onDeskDisconnectTransition( deskDisconnectChanges: Set<OnDeskDisplayChangeListener.DeskDisplayChange> ) { private fun onDisplayDisconnect( disconnectedDisplayId: Int, destinationDisplayId: Int, transition: IBinder, ): WindowContainerTransaction { // TODO: b/406320371 - Verify this works with non-system users once the underlying bug is // resolved. val wct = WindowContainerTransaction() // TODO(b/391652399): Remove the wallpaper of the disconnected display. val transitStartRunnables = mutableSetOf<RunOnTransitStart?>() for (change in deskDisconnectChanges) { if (desktopState.isDesktopModeSupportedOnDisplay(change.destinationDisplayId)) { transitStartRunnables.add( updateDesksActivationOnDisconnection( disconnectedDisplayActiveDesk = change.deskId, wct = wct, change.toTop, ) // TODO: b/391652399 - Investigate why sometimes disconnect results in a black background. // Additionally, investigate why wallpaper goes to front for inactive users. removeWallpaperTask(wct, disconnectedDisplayId) removeHomeTask(wct, disconnectedDisplayId) userRepositories.forAllRepositories { desktopRepository -> val deskIds = desktopRepository.getDeskIds(disconnectedDisplayId).toList() if (desktopState.isDesktopModeSupportedOnDisplay(destinationDisplayId)) { // Desktop supported on display; reparent desks, focused desk on top. for (deskId in deskIds) { val toTop = desktopRepository .getActiveTasks(disconnectedDisplayId) .contains(focusTransitionObserver.globallyFocusedTaskId) desksOrganizer.moveDeskToDisplay(wct, deskId, destinationDisplayId, toTop) desksTransitionObserver.addPendingTransition( DeskTransition.ChangeDeskDisplay(transition, deskId, destinationDisplayId) ) updateDesksActivationOnDisconnection(deskId, destinationDisplayId, wct, toTop) ?.invoke(transition) } } else { // TODO(b/391652399): Implement desktop-not-supported case. // Desktop not supported on display; reparent tasks to display area, remove desk. val tdaInfo = checkNotNull( rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(destinationDisplayId) ) { "Expected to find displayAreaInfo for displayId=$destinationDisplayId" } for (deskId in deskIds) { val taskIds = desktopRepository.getActiveTaskIdsInDesk(deskId) for (taskId in taskIds) { val task = shellTaskOrganizer.getRunningTaskInfo(taskId) ?: continue wct.reparent( task.token, tdaInfo.token, focusTransitionObserver.globallyFocusedTaskId == task.taskId, ) } desksOrganizer.removeDesk(wct, deskId, userId) desksTransitionObserver.addPendingTransition( DeskTransition.RemoveDesk( token = transition, displayId = disconnectedDisplayId, deskId = deskId, tasks = emptySet(), onDeskRemovedListener = onDeskRemovedListener, ) ) desksTransitionObserver.addPendingTransition( DeskTransition.RemoveDisplay(transition, disconnectedDisplayId) ) } val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null) for (transitStartRunnable in transitStartRunnables) { transitStartRunnable?.invoke(transition) } } return wct } /** * Handle desk operations when disconnecting a display and all desks on that display are moving Loading @@ -664,6 +697,7 @@ class DesktopTasksController( @VisibleForTesting fun updateDesksActivationOnDisconnection( disconnectedDisplayActiveDesk: Int, destinationDisplayId: Int, wct: WindowContainerTransaction, toTop: Boolean, ): RunOnTransitStart? { Loading @@ -671,7 +705,11 @@ class DesktopTasksController( if (toTop) { // The disconnected display's active desk was reparented to the top, activate it // here. addDeskActivationChanges(disconnectedDisplayActiveDesk, wct) addDeskActivationChanges( deskId = disconnectedDisplayActiveDesk, wct = wct, displayId = destinationDisplayId, ) } else { // The disconnected display's active desk was reparented to the back, ensure it is // no longer an active launch root. Loading Loading @@ -932,9 +970,9 @@ class DesktopTasksController( // |moveHomeTask| is also called in |bringDesktopAppsToFrontBeforeShowingNewTask|, so // this shouldn't be necessary at all. if (ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY.isTrue) { moveHomeTask(taskInfo.displayId, wct) moveHomeTaskToTop(taskInfo.displayId, wct) } else { moveHomeTask(context.displayId, wct) moveHomeTaskToTop(context.displayId, wct) } } val runOnTransitStart = addDeskActivationWithMovingTaskChanges(deskId, wct, taskInfo) Loading Loading @@ -1260,7 +1298,7 @@ class DesktopTasksController( // We are moving a freeform task to fullscreen, put the home task under the fullscreen task. if (!forceEnterDesktop(displayId)) { moveHomeTask(displayId, wct) moveHomeTaskToTop(displayId, wct) wct.reorder(task.token, /* onTop= */ true) } Loading Loading @@ -2085,7 +2123,10 @@ class DesktopTasksController( val useParamDisplayId = DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue || ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY.isTrue moveHomeTask(displayId = if (useParamDisplayId) displayId else context.displayId, wct = wct) moveHomeTaskToTop( displayId = if (useParamDisplayId) displayId else context.displayId, wct = wct, ) // Currently, we only handle the desktop on the default display really. if ( (displayId == DEFAULT_DISPLAY || Loading Loading @@ -2143,12 +2184,22 @@ class DesktopTasksController( return taskIdToMinimize } private fun moveHomeTask(displayId: Int, wct: WindowContainerTransaction) { logV("moveHomeTask in displayId=%d", displayId) shellTaskOrganizer .getRunningTasks(displayId) .firstOrNull { task -> task.activityType == ACTIVITY_TYPE_HOME } ?.let { homeTask -> wct.reorder(homeTask.getToken(), /* onTop= */ true) } private fun moveHomeTaskToTop(displayId: Int, wct: WindowContainerTransaction) { logV("moveHomeTaskToTop in displayId=%d", displayId) getHomeTask(displayId)?.let { homeTask -> wct.reorder(homeTask.getToken(), /* onTop= */ true) } } private fun removeHomeTask(wct: WindowContainerTransaction, displayId: Int) { logV("removeHomeTask in displayId=%d", displayId) getHomeTask(displayId)?.let { homeTask -> wct.removeRootTask(homeTask.getToken()) } } private fun getHomeTask(displayId: Int): RunningTaskInfo? { return shellTaskOrganizer.getRunningTasks(displayId).firstOrNull { task -> task.activityType == ACTIVITY_TYPE_HOME } } private fun addLaunchHomePendingIntent(wct: WindowContainerTransaction, displayId: Int) { Loading @@ -2157,7 +2208,7 @@ class DesktopTasksController( private fun addWallpaperActivity(displayId: Int, wct: WindowContainerTransaction) { logV("addWallpaperActivity") if (ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER.isTrue()) { if (ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER.isTrue) { // If the wallpaper activity for this display already exists, let's reorder it to top. val wallpaperActivityToken = desktopWallpaperActivityTokenProvider.getToken(displayId) Loading @@ -2165,7 +2216,6 @@ class DesktopTasksController( wct.reorder(wallpaperActivityToken, /* onTop= */ true) return } val intent = Intent(context, DesktopWallpaperActivity::class.java) if (ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY.isTrue) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) Loading Loading @@ -2222,15 +2272,18 @@ class DesktopTasksController( } } private fun removeWallpaperActivity(wct: WindowContainerTransaction, displayId: Int) { private fun moveWallpaperActivityToBack(wct: WindowContainerTransaction, displayId: Int) { desktopWallpaperActivityTokenProvider.getToken(displayId)?.let { token -> logV("removeWallpaperActivity") if (ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER.isTrue()) { logV("moveWallpaperActivityToBack") wct.reorder(token, /* onTop= */ false) } else { wct.removeTask(token) } } private fun removeWallpaperTask(wct: WindowContainerTransaction, displayId: Int) { desktopWallpaperActivityTokenProvider.getToken(displayId)?.let { token -> logV("removeWallpaperTask") wct.removeTask(token) } } private fun willExitDesktop( Loading Loading @@ -2295,7 +2348,11 @@ class DesktopTasksController( !skipWallpaperAndHomeOrdering || !DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue ) { removeWallpaperActivity(wct, displayId) if (ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER.isTrue) { moveWallpaperActivityToBack(wct, displayId) } else { removeWallpaperTask(wct, displayId) } if (shouldEndUpAtHome) { // If the transition should end up with user going to home, launch home with a // pending intent. Loading Loading @@ -2333,6 +2390,19 @@ class DesktopTasksController( request: TransitionRequestInfo, ): WindowContainerTransaction? { logV("handleRequest request=%s", request) // First, check if this is a display disconnect request. val displayChange = request.displayChange if ( DesktopExperienceFlags.ENABLE_DISPLAY_DISCONNECT_INTERACTION.isTrue && displayChange != null && displayChange.disconnectReparentDisplay != INVALID_DISPLAY ) { return onDisplayDisconnect( displayChange.displayId, displayChange.disconnectReparentDisplay, transition, ) } // Check if we should skip handling this transition var reason = "" val triggerTask = request.triggerTask Loading Loading @@ -3356,9 +3426,9 @@ class DesktopTasksController( // TODO: b/362720497 - should this be true in other places? Can it be calculated locally // without having to specify the value? addPendingLaunchTransition: Boolean = false, displayId: Int = taskRepository.getDisplayForDesk(deskId), ): RunOnTransitStart { val newTaskIdInFront = newTask?.taskId val displayId = taskRepository.getDisplayForDesk(deskId) logV( "addDeskActivationChanges newTaskId=%d deskId=%d displayId=%d", newTask?.taskId, Loading Loading @@ -3600,9 +3670,9 @@ class DesktopTasksController( taskRepository.getDefaultDeskId(displayId) ?: createDeskSuspending(displayId, userId) /** Removes the given desk. */ fun removeDesk(deskId: Int) { val displayId = taskRepository.getDisplayForDesk(deskId) removeDesk(displayId = displayId, deskId = deskId) fun removeDesk(deskId: Int, desktopRepository: DesktopRepository = taskRepository) { val displayId = desktopRepository.getDisplayForDesk(deskId) removeDesk(displayId = displayId, deskId = deskId, desktopRepository = desktopRepository) } /** Removes all the available desks on all displays. */ Loading @@ -3610,17 +3680,21 @@ class DesktopTasksController( taskRepository.getAllDeskIds().forEach { deskId -> removeDesk(deskId) } } private fun removeDesk(displayId: Int, deskId: Int) { private fun removeDesk( displayId: Int, deskId: Int, desktopRepository: DesktopRepository = taskRepository, ) { if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue()) return logV("removeDesk deskId=%d from displayId=%d", deskId, displayId) val tasksToRemove = if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { taskRepository.getActiveTaskIdsInDesk(deskId) desktopRepository.getActiveTaskIdsInDesk(deskId) } else { // TODO: 362720497 - make sure minimized windows are also removed in WM // and the repository. taskRepository.removeDesk(deskId) desktopRepository.removeDesk(deskId) } val wct = WindowContainerTransaction() Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopUserRepositories.kt +4 −0 Original line number Diff line number Diff line Loading @@ -158,6 +158,10 @@ class DesktopUserRepositories( } } /** Execute the provided callback for all repositories. */ fun forAllRepositories(repositoryCallback: (DesktopRepository) -> Unit) = desktopRepoByUserId.forEach { _, repository -> repositoryCallback(repository) } private fun logD(msg: String, vararg arguments: Any?) { ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) } Loading