Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +4 −2 Original line number Diff line number Diff line Loading @@ -1734,7 +1734,8 @@ public abstract class WMShellModule { DesktopRepositoryInitializer desktopRepositoryInitializer, Optional<DesksTransitionObserver> desksTransitionObserver, DesktopState desktopState, Transitions transitions Transitions transitions, KeyguardManager keyguardManager ) { if (!desktopState.canEnterDesktopMode()) { return Optional.empty(); Loading @@ -1753,7 +1754,8 @@ public abstract class WMShellModule { desktopDisplayModeController.get(), desksTransitionObserver.get(), desktopState, transitions)); transitions, keyguardManager)); } @WMSingleton Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt +51 −41 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.wm.shell.desktopmode import android.app.KeyguardManager import android.content.Context import android.content.res.Configuration import android.graphics.Rect Loading @@ -23,7 +24,6 @@ import android.os.IBinder import android.os.Trace import android.os.UserHandle import android.os.UserManager import android.util.ArraySet import android.view.Display import android.view.Display.DEFAULT_DISPLAY import android.view.SurfaceControl Loading @@ -34,7 +34,6 @@ import android.window.DesktopModeFlags import android.window.DisplayAreaInfo import android.window.TransitionInfo import com.android.app.tracing.traceSection import com.android.internal.annotations.VisibleForTesting import com.android.internal.protolog.ProtoLog import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.RootTaskDisplayAreaOrganizer.RootTaskDisplayAreaListener Loading @@ -52,6 +51,7 @@ import com.android.wm.shell.desktopmode.multidesks.OnDeskRemovedListener import com.android.wm.shell.desktopmode.multidesks.PreserveDisplayRequestHandler import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.shared.desktopmode.DesktopState import com.android.wm.shell.sysui.KeyguardChangeListener import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.sysui.UserChangeListener Loading @@ -75,15 +75,23 @@ class DesktopDisplayEventHandler( private val desksTransitionObserver: DesksTransitionObserver, private val desktopState: DesktopState, private val transitions: Transitions, private val keyguardManager: KeyguardManager, ) : OnDisplaysChangedListener, OnDeskRemovedListener, PreserveDisplayRequestHandler, Transitions.TransitionObserver { Transitions.TransitionObserver, KeyguardChangeListener { private val onDisplayAreaChangeListener = OnDisplayAreaChangeListener { displayId -> logV("displayAreaChanged in displayId=%d", displayId) if (!handlePotentialReconnect(displayId)) { val keyguardLocked = keyguardManager.isKeyguardLocked logV( "displayAreaChanged in displayId=%d, keyguardLocked=%b", displayId, keyguardLocked ) // Do not create default desk if keyguard is locked. It will be handled on unlock. if (!handlePotentialReconnect(displayId) && !keyguardLocked) { createDefaultDesksIfNeeded(displayIds = listOf(displayId), userId = null) } } Loading @@ -96,9 +104,6 @@ class DesktopDisplayEventHandler( private val boundsChangedByDisplayId = mutableSetOf<Int>() private val stableBoundsChangedByDisplayId = mutableSetOf<Int>() private val displayConfigById = mutableMapOf<Int, Configuration>() // All uniqueDisplayIds that are currently being restored; any further requests // to restore them will no-op. @VisibleForTesting val displaysMidRestoration = ArraySet<String>() init { shellInit.addInitCallback({ onInit() }, this) Loading @@ -120,6 +125,7 @@ class DesktopDisplayEventHandler( ) if (DesktopExperienceFlags.ENABLE_DISPLAY_RECONNECT_INTERACTION.isTrue) { desktopTasksController.preserveDisplayRequestHandler = this shellController.addKeyguardChangeListener(this) } } } Loading Loading @@ -284,13 +290,6 @@ class DesktopDisplayEventHandler( desktopDisplayModeController.updateDefaultDisplayWindowingMode() } val uniqueDisplayId = uniqueIdByDisplayId[displayId] if (uniqueDisplayId != null && uniqueDisplayId in displaysMidRestoration) { logW( "onDisplayRemoved: Found display mid-restoration that did not finish: " + "displayId=$displayId, uniqueDisplayId=$uniqueDisplayId" ) displaysMidRestoration.remove(uniqueDisplayId) } uniqueIdByDisplayId.remove(displayId) } Loading @@ -317,12 +316,15 @@ class DesktopDisplayEventHandler( private fun handlePotentialDeskDisplayChange(displayId: Int) { if (desktopState.isDesktopModeSupportedOnDisplay(displayId)) { // A display has become desktop eligible. Treat this as a potential reconnect. val uniqueId = displayController.getDisplay(displayId)?.uniqueId ?: return val keyguardLocked = keyguardManager.isKeyguardLocked logV( "onDesktopModeEligibleChanged: displayId=%d has become desktop eligible", "onDesktopModeEligibleChanged: keyguardLocked=%b, " + "displayId=%d has become desktop eligible", displayId, keyguardLocked ) if (!handlePotentialReconnect(displayId)) { // Do not create default desk if keyguard is locked. It will be handled on unlock. if (!handlePotentialReconnect(displayId) && !keyguardLocked) { createDefaultDesksIfNeeded(displayIds = listOf(displayId), userId = null) } } else { Loading @@ -335,7 +337,26 @@ class DesktopDisplayEventHandler( } } override fun onKeyguardVisibilityChanged( visible: Boolean, occluded: Boolean, animatingDismiss: Boolean, ) { if (visible) return val displaysByUniqueId = displayController.allDisplaysByUniqueId ?: return val defaultDeskDisplayIds = mutableSetOf<Int>() for (displayIdByUniqueId in displaysByUniqueId) { val displayId = displayIdByUniqueId.value if (displayId != DEFAULT_DISPLAY && !handlePotentialReconnect(displayId)) { defaultDeskDisplayIds.add(displayIdByUniqueId.value) } } createDefaultDesksIfNeeded(defaultDeskDisplayIds, null) } private fun handlePotentialReconnect(displayId: Int): Boolean { // Do not handle restoration while locked; it will be handled when keyguard is gone. if (keyguardManager.isKeyguardLocked) return false val uniqueDisplayId = displayController.getDisplay(displayId)?.uniqueId ?: return false uniqueIdByDisplayId[displayId] = uniqueDisplayId val currentUserRepository = desktopUserRepositories.current Loading @@ -343,21 +364,17 @@ class DesktopDisplayEventHandler( logV("handlePotentialReconnect: Reconnect not supported; aborting.") return false } if (uniqueDisplayId in displaysMidRestoration) { logV( "handlePotentialReconnect: uniqueDisplay=$uniqueDisplayId " + "mid-restoration; aborting." ) return false } if (!currentUserRepository.hasPreservedDisplayForUniqueDisplayId(uniqueDisplayId)) { // To ensure only one restoreDisplay is actually called, remove the preserved display. val preservedDisplay = currentUserRepository.removePreservedDisplay(uniqueDisplayId) if (preservedDisplay == null) { logV( "handlePotentialReconnect: No preserved display found for " + "uniqueDisplayId=$uniqueDisplayId; aborting." ) return false } val preservedTasks = currentUserRepository.getPreservedTasks(uniqueDisplayId).toMutableList() currentUserRepository.getPreservedTasks(preservedDisplay).toMutableList() // Projected mode: Do not move anything focused on the internal display. if (!desktopState.isDesktopModeSupportedOnDisplay(DEFAULT_DISPLAY)) { val focusedDefaultDisplayTaskIds = Loading @@ -367,22 +384,15 @@ class DesktopDisplayEventHandler( preservedTasks.removeAll { taskId -> focusedDefaultDisplayTaskIds.contains(taskId) } } if (preservedTasks.isEmpty()) { // The preserved display is normally removed at the end of restoreDisplay. // If we don't restore anything, remove it here instead. currentUserRepository.removePreservedDisplay(uniqueDisplayId) // If we don't restore anything, skip the restoration and return false so we // create a default desk. return false } displaysMidRestoration.add(uniqueDisplayId) mainScope.launch { // If the display has been removed by the time this executes, restore nothing. if (uniqueDisplayId !in displaysMidRestoration) return@launch desktopTasksController.restoreDisplay( displayId = displayId, uniqueDisplayId = uniqueDisplayId, preservedDisplay = preservedDisplay, userId = desktopUserRepositories.current.userId, ) displaysMidRestoration.remove(uniqueDisplayId) } return true } Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +17 −44 Original line number Diff line number Diff line Loading @@ -131,6 +131,7 @@ import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.Companion import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.DragToDesktopStateListener import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler.FULLSCREEN_ANIMATION_DURATION import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction import com.android.wm.shell.desktopmode.data.DesktopDisplay import com.android.wm.shell.desktopmode.data.DesktopRepository import com.android.wm.shell.desktopmode.data.DesktopRepository.Companion.INVALID_DESK_ID import com.android.wm.shell.desktopmode.data.DesktopRepository.DeskChangeListener Loading Loading @@ -171,7 +172,6 @@ import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOT import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT import com.android.wm.shell.splitscreen.SplitScreenController import com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DESKTOP_MODE import com.android.wm.shell.sysui.KeyguardChangeListener import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit Loading Loading @@ -266,8 +266,7 @@ class DesktopTasksController( RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler, DragAndDropController.DragAndDropListener, UserChangeListener, KeyguardChangeListener { UserChangeListener { private val desktopMode: DesktopModeImpl private var visualIndicator: DesktopModeVisualIndicator? = null Loading Loading @@ -365,7 +364,6 @@ class DesktopTasksController( } ) dragAndDropController.addListener(this) shellController.addKeyguardChangeListener(this) desksOrganizer.addOnDesktopTaskInfoChangedListener { taskInfo -> onTaskInfoChanged(taskInfo) } Loading Loading @@ -870,31 +868,6 @@ class DesktopTasksController( } } override fun onKeyguardVisibilityChanged( visible: Boolean, occluded: Boolean, animatingDismiss: Boolean, ) { logD( "onKeyguardVisibilityChanged visible=%b, occluded=%b, animatingDismiss=%b", visible, occluded, animatingDismiss, ) if (visible) return val displaysByUniqueId = displayController.allDisplaysByUniqueId ?: return for (displayIdByUniqueId in displaysByUniqueId) { val taskRepository = userRepositories.current if (taskRepository.hasPreservedDisplayForUniqueDisplayId(displayIdByUniqueId.key)) { restoreDisplay( displayId = displayIdByUniqueId.value, uniqueDisplayId = displayIdByUniqueId.key, userId = taskRepository.userId, ) } } } private fun handleExtendedModeDisconnect( desktopRepository: DesktopRepository, wct: WindowContainerTransaction, Loading Loading @@ -1121,21 +1094,20 @@ class DesktopTasksController( * * TODO: b/365873835 - Restore for all users, not just current. */ fun restoreDisplay(displayId: Int, uniqueDisplayId: String, userId: Int) { fun restoreDisplay(displayId: Int, preservedDisplay: DesktopDisplay, userId: Int) { logD( "restoreDisplay: displayId=%d, uniqueDisplayId=%d userId=%d", "restoreDisplay: displayId=%d former displayId=%d userId=%d", displayId, uniqueDisplayId, preservedDisplay.displayId, userId, ) // TODO: b/365873835 - Utilize DesktopTask data class once it is // implemented in DesktopRepository. // Do not handle restoration while locked; it will be handled when keyguard is gone. if (keyguardManager.isKeyguardLocked) return val repository = userRepositories.getProfile(userId) val preservedTaskIdsByDeskId = repository.getPreservedTasksByDeskIdInZOrder(uniqueDisplayId) val boundsByTaskId = repository.getPreservedTaskBounds(uniqueDisplayId) val activeDeskId = repository.getPreservedActiveDesk(uniqueDisplayId) val preservedTaskIdsByDeskId = repository.getPreservedTasksByDeskIdInZOrder(preservedDisplay) val boundsByTaskId = repository.getPreservedTaskBounds(preservedDisplay) val activeDeskId = preservedDisplay.activeDeskId val wct = WindowContainerTransaction() var runOnTransitStartList = mutableListOf<RunOnTransitStart>() val tilingReconnectHandler = Loading Loading @@ -1177,7 +1149,7 @@ class DesktopTasksController( taskId = taskId, userId = userId, displayId = displayId, uniqueDisplayId = uniqueDisplayId, preservedDisplay = preservedDisplay, taskBounds = boundsByTaskId[taskId], ) ?.let { runOnTransitStartList.add(it) } Loading @@ -1185,7 +1157,7 @@ class DesktopTasksController( } val preservedTilingData = repository.getPreservedTilingData(uniqueDisplayId, preservedDeskId) repository.getPreservedTilingData(preservedDisplay, preservedDeskId) if (preservedTilingData != null) { tilingReconnectHandler.addTilingDisplayReconnectSession( TilingDisplayReconnectEventHandler.TilingDisplayReconnectSession( Loading @@ -1203,7 +1175,6 @@ class DesktopTasksController( val transition = transitions.startTransition(TRANSIT_CHANGE, wct, null) tilingReconnectHandler.activationBinder = transition runOnTransitStartList.forEach { it.invoke(transition) } repository.removePreservedDisplay(uniqueDisplayId) } } Loading @@ -1213,16 +1184,18 @@ class DesktopTasksController( taskId: Int, userId: Int, displayId: Int, uniqueDisplayId: String, preservedDisplay: DesktopDisplay, taskBounds: Rect?, ): RunOnTransitStart? { logD( "addRestoreTaskToDeskChanges: taskId=$taskId; deskId=$deskId; userId=$userId; " + "taskBounds=$taskBounds; uniqueDisplayId=$uniqueDisplayId" "taskBounds=$taskBounds." ) val repository = userRepositories.getProfile(userId) val minimized = repository.isPreservedTaskMinimized(uniqueDisplayId, taskId) val minimized = preservedDisplay.orderedDesks.any { desk -> taskId in desk.minimizedTasks } val task = shellTaskOrganizer.getRunningTaskInfo(taskId) ?: recentTasksController?.findTaskInBackground(taskId) Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/data/DesktopRepository.kt +12 −28 Original line number Diff line number Diff line Loading @@ -162,20 +162,13 @@ class DesktopRepository( } /** Removes the specified preserved display. */ fun removePreservedDisplay(uniqueDisplayId: String) { fun removePreservedDisplay(uniqueDisplayId: String) = preservedDisplaysByUniqueId.remove(uniqueDisplayId) } /** Whether or not the given uniqueDisplayId matches a display that is being preserved. */ fun hasPreservedDisplayForUniqueDisplayId(uniqueDisplayId: String): Boolean = preservedDisplaysByUniqueId.containsKey(uniqueDisplayId) /** Returns all active tasks on the preserved display separated by desk. */ fun getPreservedTasksByDeskIdInZOrder(uniqueDisplayId: String): Map<Int, List<Int>> { val preservedDesks = preservedDisplaysByUniqueId[uniqueDisplayId]?.orderedDesks ?: emptySet() fun getPreservedTasksByDeskIdInZOrder(preservedDisplay: DesktopDisplay): Map<Int, List<Int>> { val tasksByDeskId = mutableMapOf<Int, List<Int>>() for (desk in preservedDesks) { for (desk in preservedDisplay.orderedDesks) { tasksByDeskId[desk.deskId] = desk.freeformTasksInZOrder } return tasksByDeskId Loading @@ -184,28 +177,21 @@ class DesktopRepository( /** * Returns all preserved tasks for the preserved display regardless of what desk they appear in. */ fun getPreservedTasks(uniqueDisplayId: String): List<Int> { val preservedDesks = preservedDisplaysByUniqueId[uniqueDisplayId]?.orderedDesks ?: emptySet() fun getPreservedTasks(preservedDisplay: DesktopDisplay): List<Int> { val preservedTasks = mutableListOf<Int>() for (desk in preservedDesks) { for (desk in preservedDisplay.orderedDesks) { desk.freeformTasksInZOrder.forEach { taskId -> preservedTasks.add(taskId) } } return preservedTasks } /** Returns the active desk on the preserved display for the specified unique display id. */ fun getPreservedActiveDesk(uniqueDisplayId: String): Int? = preservedDisplaysByUniqueId[uniqueDisplayId]?.activeDeskId /** Returns a preserved desk data post a display reconnect event. */ fun getPreservedTilingData( uniqueDisplayId: String, preservedDisplay: DesktopDisplay, preservedDeskId: Int?, ): PreservedTiledAppData? = preservedDisplaysByUniqueId[uniqueDisplayId] ?.orderedDesks ?.firstOrNull { desk -> desk.deskId == preservedDeskId } preservedDisplay.orderedDesks .firstOrNull { desk -> desk.deskId == preservedDeskId } ?.let { PreservedTiledAppData(it.leftTiledTaskId, it.rightTiledTaskId) } ?.takeIf { it.leftTiledTask != null || it.rightTiledTask != null } Loading @@ -219,19 +205,17 @@ class DesktopRepository( } ?: false /** Returns the bounds of all tasks in all desks of the preserved display. */ fun getPreservedTaskBounds(uniqueDisplayId: String): Map<Int, Rect> { fun getPreservedTaskBounds(preservedDisplay: DesktopDisplay): Map<Int, Rect> { val combinedBoundsMap = mutableMapOf<Int, Rect>() val orderedDesks = preservedDisplaysByUniqueId[uniqueDisplayId]?.orderedDesks ?: return emptyMap() for (desk in orderedDesks) { for (desk in preservedDisplay.orderedDesks) { combinedBoundsMap.putAll(desk.boundsByTaskId) } return combinedBoundsMap } @VisibleForTesting fun getPreservedDeskIds(uniqueDisplayId: String): List<Int> = preservedDisplaysByUniqueId[uniqueDisplayId]?.orderedDesks?.map { it.deskId } ?: emptyList() fun getPreservedDeskIds(preservedDisplay: DesktopDisplay): List<Int> = preservedDisplay.orderedDesks.map { it.deskId } /** Returns a list of all [Desk]s in the repository. */ private fun desksSequence(): Sequence<Desk> = desktopData.desksSequence() Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt +61 −21 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +4 −2 Original line number Diff line number Diff line Loading @@ -1734,7 +1734,8 @@ public abstract class WMShellModule { DesktopRepositoryInitializer desktopRepositoryInitializer, Optional<DesksTransitionObserver> desksTransitionObserver, DesktopState desktopState, Transitions transitions Transitions transitions, KeyguardManager keyguardManager ) { if (!desktopState.canEnterDesktopMode()) { return Optional.empty(); Loading @@ -1753,7 +1754,8 @@ public abstract class WMShellModule { desktopDisplayModeController.get(), desksTransitionObserver.get(), desktopState, transitions)); transitions, keyguardManager)); } @WMSingleton Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt +51 −41 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.wm.shell.desktopmode import android.app.KeyguardManager import android.content.Context import android.content.res.Configuration import android.graphics.Rect Loading @@ -23,7 +24,6 @@ import android.os.IBinder import android.os.Trace import android.os.UserHandle import android.os.UserManager import android.util.ArraySet import android.view.Display import android.view.Display.DEFAULT_DISPLAY import android.view.SurfaceControl Loading @@ -34,7 +34,6 @@ import android.window.DesktopModeFlags import android.window.DisplayAreaInfo import android.window.TransitionInfo import com.android.app.tracing.traceSection import com.android.internal.annotations.VisibleForTesting import com.android.internal.protolog.ProtoLog import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.RootTaskDisplayAreaOrganizer.RootTaskDisplayAreaListener Loading @@ -52,6 +51,7 @@ import com.android.wm.shell.desktopmode.multidesks.OnDeskRemovedListener import com.android.wm.shell.desktopmode.multidesks.PreserveDisplayRequestHandler import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.shared.desktopmode.DesktopState import com.android.wm.shell.sysui.KeyguardChangeListener import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.sysui.UserChangeListener Loading @@ -75,15 +75,23 @@ class DesktopDisplayEventHandler( private val desksTransitionObserver: DesksTransitionObserver, private val desktopState: DesktopState, private val transitions: Transitions, private val keyguardManager: KeyguardManager, ) : OnDisplaysChangedListener, OnDeskRemovedListener, PreserveDisplayRequestHandler, Transitions.TransitionObserver { Transitions.TransitionObserver, KeyguardChangeListener { private val onDisplayAreaChangeListener = OnDisplayAreaChangeListener { displayId -> logV("displayAreaChanged in displayId=%d", displayId) if (!handlePotentialReconnect(displayId)) { val keyguardLocked = keyguardManager.isKeyguardLocked logV( "displayAreaChanged in displayId=%d, keyguardLocked=%b", displayId, keyguardLocked ) // Do not create default desk if keyguard is locked. It will be handled on unlock. if (!handlePotentialReconnect(displayId) && !keyguardLocked) { createDefaultDesksIfNeeded(displayIds = listOf(displayId), userId = null) } } Loading @@ -96,9 +104,6 @@ class DesktopDisplayEventHandler( private val boundsChangedByDisplayId = mutableSetOf<Int>() private val stableBoundsChangedByDisplayId = mutableSetOf<Int>() private val displayConfigById = mutableMapOf<Int, Configuration>() // All uniqueDisplayIds that are currently being restored; any further requests // to restore them will no-op. @VisibleForTesting val displaysMidRestoration = ArraySet<String>() init { shellInit.addInitCallback({ onInit() }, this) Loading @@ -120,6 +125,7 @@ class DesktopDisplayEventHandler( ) if (DesktopExperienceFlags.ENABLE_DISPLAY_RECONNECT_INTERACTION.isTrue) { desktopTasksController.preserveDisplayRequestHandler = this shellController.addKeyguardChangeListener(this) } } } Loading Loading @@ -284,13 +290,6 @@ class DesktopDisplayEventHandler( desktopDisplayModeController.updateDefaultDisplayWindowingMode() } val uniqueDisplayId = uniqueIdByDisplayId[displayId] if (uniqueDisplayId != null && uniqueDisplayId in displaysMidRestoration) { logW( "onDisplayRemoved: Found display mid-restoration that did not finish: " + "displayId=$displayId, uniqueDisplayId=$uniqueDisplayId" ) displaysMidRestoration.remove(uniqueDisplayId) } uniqueIdByDisplayId.remove(displayId) } Loading @@ -317,12 +316,15 @@ class DesktopDisplayEventHandler( private fun handlePotentialDeskDisplayChange(displayId: Int) { if (desktopState.isDesktopModeSupportedOnDisplay(displayId)) { // A display has become desktop eligible. Treat this as a potential reconnect. val uniqueId = displayController.getDisplay(displayId)?.uniqueId ?: return val keyguardLocked = keyguardManager.isKeyguardLocked logV( "onDesktopModeEligibleChanged: displayId=%d has become desktop eligible", "onDesktopModeEligibleChanged: keyguardLocked=%b, " + "displayId=%d has become desktop eligible", displayId, keyguardLocked ) if (!handlePotentialReconnect(displayId)) { // Do not create default desk if keyguard is locked. It will be handled on unlock. if (!handlePotentialReconnect(displayId) && !keyguardLocked) { createDefaultDesksIfNeeded(displayIds = listOf(displayId), userId = null) } } else { Loading @@ -335,7 +337,26 @@ class DesktopDisplayEventHandler( } } override fun onKeyguardVisibilityChanged( visible: Boolean, occluded: Boolean, animatingDismiss: Boolean, ) { if (visible) return val displaysByUniqueId = displayController.allDisplaysByUniqueId ?: return val defaultDeskDisplayIds = mutableSetOf<Int>() for (displayIdByUniqueId in displaysByUniqueId) { val displayId = displayIdByUniqueId.value if (displayId != DEFAULT_DISPLAY && !handlePotentialReconnect(displayId)) { defaultDeskDisplayIds.add(displayIdByUniqueId.value) } } createDefaultDesksIfNeeded(defaultDeskDisplayIds, null) } private fun handlePotentialReconnect(displayId: Int): Boolean { // Do not handle restoration while locked; it will be handled when keyguard is gone. if (keyguardManager.isKeyguardLocked) return false val uniqueDisplayId = displayController.getDisplay(displayId)?.uniqueId ?: return false uniqueIdByDisplayId[displayId] = uniqueDisplayId val currentUserRepository = desktopUserRepositories.current Loading @@ -343,21 +364,17 @@ class DesktopDisplayEventHandler( logV("handlePotentialReconnect: Reconnect not supported; aborting.") return false } if (uniqueDisplayId in displaysMidRestoration) { logV( "handlePotentialReconnect: uniqueDisplay=$uniqueDisplayId " + "mid-restoration; aborting." ) return false } if (!currentUserRepository.hasPreservedDisplayForUniqueDisplayId(uniqueDisplayId)) { // To ensure only one restoreDisplay is actually called, remove the preserved display. val preservedDisplay = currentUserRepository.removePreservedDisplay(uniqueDisplayId) if (preservedDisplay == null) { logV( "handlePotentialReconnect: No preserved display found for " + "uniqueDisplayId=$uniqueDisplayId; aborting." ) return false } val preservedTasks = currentUserRepository.getPreservedTasks(uniqueDisplayId).toMutableList() currentUserRepository.getPreservedTasks(preservedDisplay).toMutableList() // Projected mode: Do not move anything focused on the internal display. if (!desktopState.isDesktopModeSupportedOnDisplay(DEFAULT_DISPLAY)) { val focusedDefaultDisplayTaskIds = Loading @@ -367,22 +384,15 @@ class DesktopDisplayEventHandler( preservedTasks.removeAll { taskId -> focusedDefaultDisplayTaskIds.contains(taskId) } } if (preservedTasks.isEmpty()) { // The preserved display is normally removed at the end of restoreDisplay. // If we don't restore anything, remove it here instead. currentUserRepository.removePreservedDisplay(uniqueDisplayId) // If we don't restore anything, skip the restoration and return false so we // create a default desk. return false } displaysMidRestoration.add(uniqueDisplayId) mainScope.launch { // If the display has been removed by the time this executes, restore nothing. if (uniqueDisplayId !in displaysMidRestoration) return@launch desktopTasksController.restoreDisplay( displayId = displayId, uniqueDisplayId = uniqueDisplayId, preservedDisplay = preservedDisplay, userId = desktopUserRepositories.current.userId, ) displaysMidRestoration.remove(uniqueDisplayId) } return true } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +17 −44 Original line number Diff line number Diff line Loading @@ -131,6 +131,7 @@ import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.Companion import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.DragToDesktopStateListener import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler.FULLSCREEN_ANIMATION_DURATION import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction import com.android.wm.shell.desktopmode.data.DesktopDisplay import com.android.wm.shell.desktopmode.data.DesktopRepository import com.android.wm.shell.desktopmode.data.DesktopRepository.Companion.INVALID_DESK_ID import com.android.wm.shell.desktopmode.data.DesktopRepository.DeskChangeListener Loading Loading @@ -171,7 +172,6 @@ import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOT import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT import com.android.wm.shell.splitscreen.SplitScreenController import com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DESKTOP_MODE import com.android.wm.shell.sysui.KeyguardChangeListener import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit Loading Loading @@ -266,8 +266,7 @@ class DesktopTasksController( RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler, DragAndDropController.DragAndDropListener, UserChangeListener, KeyguardChangeListener { UserChangeListener { private val desktopMode: DesktopModeImpl private var visualIndicator: DesktopModeVisualIndicator? = null Loading Loading @@ -365,7 +364,6 @@ class DesktopTasksController( } ) dragAndDropController.addListener(this) shellController.addKeyguardChangeListener(this) desksOrganizer.addOnDesktopTaskInfoChangedListener { taskInfo -> onTaskInfoChanged(taskInfo) } Loading Loading @@ -870,31 +868,6 @@ class DesktopTasksController( } } override fun onKeyguardVisibilityChanged( visible: Boolean, occluded: Boolean, animatingDismiss: Boolean, ) { logD( "onKeyguardVisibilityChanged visible=%b, occluded=%b, animatingDismiss=%b", visible, occluded, animatingDismiss, ) if (visible) return val displaysByUniqueId = displayController.allDisplaysByUniqueId ?: return for (displayIdByUniqueId in displaysByUniqueId) { val taskRepository = userRepositories.current if (taskRepository.hasPreservedDisplayForUniqueDisplayId(displayIdByUniqueId.key)) { restoreDisplay( displayId = displayIdByUniqueId.value, uniqueDisplayId = displayIdByUniqueId.key, userId = taskRepository.userId, ) } } } private fun handleExtendedModeDisconnect( desktopRepository: DesktopRepository, wct: WindowContainerTransaction, Loading Loading @@ -1121,21 +1094,20 @@ class DesktopTasksController( * * TODO: b/365873835 - Restore for all users, not just current. */ fun restoreDisplay(displayId: Int, uniqueDisplayId: String, userId: Int) { fun restoreDisplay(displayId: Int, preservedDisplay: DesktopDisplay, userId: Int) { logD( "restoreDisplay: displayId=%d, uniqueDisplayId=%d userId=%d", "restoreDisplay: displayId=%d former displayId=%d userId=%d", displayId, uniqueDisplayId, preservedDisplay.displayId, userId, ) // TODO: b/365873835 - Utilize DesktopTask data class once it is // implemented in DesktopRepository. // Do not handle restoration while locked; it will be handled when keyguard is gone. if (keyguardManager.isKeyguardLocked) return val repository = userRepositories.getProfile(userId) val preservedTaskIdsByDeskId = repository.getPreservedTasksByDeskIdInZOrder(uniqueDisplayId) val boundsByTaskId = repository.getPreservedTaskBounds(uniqueDisplayId) val activeDeskId = repository.getPreservedActiveDesk(uniqueDisplayId) val preservedTaskIdsByDeskId = repository.getPreservedTasksByDeskIdInZOrder(preservedDisplay) val boundsByTaskId = repository.getPreservedTaskBounds(preservedDisplay) val activeDeskId = preservedDisplay.activeDeskId val wct = WindowContainerTransaction() var runOnTransitStartList = mutableListOf<RunOnTransitStart>() val tilingReconnectHandler = Loading Loading @@ -1177,7 +1149,7 @@ class DesktopTasksController( taskId = taskId, userId = userId, displayId = displayId, uniqueDisplayId = uniqueDisplayId, preservedDisplay = preservedDisplay, taskBounds = boundsByTaskId[taskId], ) ?.let { runOnTransitStartList.add(it) } Loading @@ -1185,7 +1157,7 @@ class DesktopTasksController( } val preservedTilingData = repository.getPreservedTilingData(uniqueDisplayId, preservedDeskId) repository.getPreservedTilingData(preservedDisplay, preservedDeskId) if (preservedTilingData != null) { tilingReconnectHandler.addTilingDisplayReconnectSession( TilingDisplayReconnectEventHandler.TilingDisplayReconnectSession( Loading @@ -1203,7 +1175,6 @@ class DesktopTasksController( val transition = transitions.startTransition(TRANSIT_CHANGE, wct, null) tilingReconnectHandler.activationBinder = transition runOnTransitStartList.forEach { it.invoke(transition) } repository.removePreservedDisplay(uniqueDisplayId) } } Loading @@ -1213,16 +1184,18 @@ class DesktopTasksController( taskId: Int, userId: Int, displayId: Int, uniqueDisplayId: String, preservedDisplay: DesktopDisplay, taskBounds: Rect?, ): RunOnTransitStart? { logD( "addRestoreTaskToDeskChanges: taskId=$taskId; deskId=$deskId; userId=$userId; " + "taskBounds=$taskBounds; uniqueDisplayId=$uniqueDisplayId" "taskBounds=$taskBounds." ) val repository = userRepositories.getProfile(userId) val minimized = repository.isPreservedTaskMinimized(uniqueDisplayId, taskId) val minimized = preservedDisplay.orderedDesks.any { desk -> taskId in desk.minimizedTasks } val task = shellTaskOrganizer.getRunningTaskInfo(taskId) ?: recentTasksController?.findTaskInBackground(taskId) Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/data/DesktopRepository.kt +12 −28 Original line number Diff line number Diff line Loading @@ -162,20 +162,13 @@ class DesktopRepository( } /** Removes the specified preserved display. */ fun removePreservedDisplay(uniqueDisplayId: String) { fun removePreservedDisplay(uniqueDisplayId: String) = preservedDisplaysByUniqueId.remove(uniqueDisplayId) } /** Whether or not the given uniqueDisplayId matches a display that is being preserved. */ fun hasPreservedDisplayForUniqueDisplayId(uniqueDisplayId: String): Boolean = preservedDisplaysByUniqueId.containsKey(uniqueDisplayId) /** Returns all active tasks on the preserved display separated by desk. */ fun getPreservedTasksByDeskIdInZOrder(uniqueDisplayId: String): Map<Int, List<Int>> { val preservedDesks = preservedDisplaysByUniqueId[uniqueDisplayId]?.orderedDesks ?: emptySet() fun getPreservedTasksByDeskIdInZOrder(preservedDisplay: DesktopDisplay): Map<Int, List<Int>> { val tasksByDeskId = mutableMapOf<Int, List<Int>>() for (desk in preservedDesks) { for (desk in preservedDisplay.orderedDesks) { tasksByDeskId[desk.deskId] = desk.freeformTasksInZOrder } return tasksByDeskId Loading @@ -184,28 +177,21 @@ class DesktopRepository( /** * Returns all preserved tasks for the preserved display regardless of what desk they appear in. */ fun getPreservedTasks(uniqueDisplayId: String): List<Int> { val preservedDesks = preservedDisplaysByUniqueId[uniqueDisplayId]?.orderedDesks ?: emptySet() fun getPreservedTasks(preservedDisplay: DesktopDisplay): List<Int> { val preservedTasks = mutableListOf<Int>() for (desk in preservedDesks) { for (desk in preservedDisplay.orderedDesks) { desk.freeformTasksInZOrder.forEach { taskId -> preservedTasks.add(taskId) } } return preservedTasks } /** Returns the active desk on the preserved display for the specified unique display id. */ fun getPreservedActiveDesk(uniqueDisplayId: String): Int? = preservedDisplaysByUniqueId[uniqueDisplayId]?.activeDeskId /** Returns a preserved desk data post a display reconnect event. */ fun getPreservedTilingData( uniqueDisplayId: String, preservedDisplay: DesktopDisplay, preservedDeskId: Int?, ): PreservedTiledAppData? = preservedDisplaysByUniqueId[uniqueDisplayId] ?.orderedDesks ?.firstOrNull { desk -> desk.deskId == preservedDeskId } preservedDisplay.orderedDesks .firstOrNull { desk -> desk.deskId == preservedDeskId } ?.let { PreservedTiledAppData(it.leftTiledTaskId, it.rightTiledTaskId) } ?.takeIf { it.leftTiledTask != null || it.rightTiledTask != null } Loading @@ -219,19 +205,17 @@ class DesktopRepository( } ?: false /** Returns the bounds of all tasks in all desks of the preserved display. */ fun getPreservedTaskBounds(uniqueDisplayId: String): Map<Int, Rect> { fun getPreservedTaskBounds(preservedDisplay: DesktopDisplay): Map<Int, Rect> { val combinedBoundsMap = mutableMapOf<Int, Rect>() val orderedDesks = preservedDisplaysByUniqueId[uniqueDisplayId]?.orderedDesks ?: return emptyMap() for (desk in orderedDesks) { for (desk in preservedDisplay.orderedDesks) { combinedBoundsMap.putAll(desk.boundsByTaskId) } return combinedBoundsMap } @VisibleForTesting fun getPreservedDeskIds(uniqueDisplayId: String): List<Int> = preservedDisplaysByUniqueId[uniqueDisplayId]?.orderedDesks?.map { it.deskId } ?: emptyList() fun getPreservedDeskIds(preservedDisplay: DesktopDisplay): List<Int> = preservedDisplay.orderedDesks.map { it.deskId } /** Returns a list of all [Desk]s in the repository. */ private fun desksSequence(): Sequence<Desk> = desktopData.desksSequence() Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt +61 −21 File changed.Preview size limit exceeded, changes collapsed. Show changes