Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt +44 −16 Original line number Original line Diff line number Diff line Loading @@ -66,19 +66,10 @@ class DesktopDisplayEventHandler( private val onDisplayAreaChangeListener = OnDisplayAreaChangeListener { displayId -> private val onDisplayAreaChangeListener = OnDisplayAreaChangeListener { displayId -> logV("displayAreaChanged in displayId=%d", displayId) logV("displayAreaChanged in displayId=%d", displayId) val uniqueDisplayId = displayController.getDisplay(displayId)?.uniqueId if (!handlePotentialReconnect(displayId)) { uniqueDisplayId?.let { uniqueIdByDisplayId[displayId] = it if ( DesktopExperienceFlags.ENABLE_DISPLAY_RECONNECT_INTERACTION.isTrue && desktopUserRepositories.current.hasPreservedDisplayForUniqueDisplayId(it) ) { desktopTasksController.restoreDisplay(displayId, it) return@OnDisplayAreaChangeListener } } createDefaultDesksIfNeeded(displayIds = listOf(displayId), userId = null) createDefaultDesksIfNeeded(displayIds = listOf(displayId), userId = null) } } } // Mapping of display uniqueIds to displayId. Used to match a disconnected // Mapping of display uniqueIds to displayId. Used to match a disconnected // displayId to its uniqueId since we will not be able to fetch it after disconnect. // displayId to its uniqueId since we will not be able to fetch it after disconnect. Loading Loading @@ -153,21 +144,58 @@ class DesktopDisplayEventHandler( override fun requestPreserveDisplay(displayId: Int) { override fun requestPreserveDisplay(displayId: Int) { logV("requestPreserveDisplay displayId=%d", displayId) logV("requestPreserveDisplay displayId=%d", displayId) val uniqueId = uniqueIdByDisplayId.remove(displayId) ?: return val uniqueId = uniqueIdByDisplayId[displayId] ?: return // TODO: b/365873835 - Preserve/restore bounds for other repositories. // TODO: b/365873835 - Preserve/restore bounds for other repositories. desktopUserRepositories.current.preserveDisplay(displayId, uniqueId) desktopUserRepositories.current.preserveDisplay(displayId, uniqueId) } } override fun onDesktopModeEligibleChanged(displayId: Int) { override fun onDesktopModeEligibleChanged(displayId: Int) { if ( if (displayId == DEFAULT_DISPLAY) return DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue && if (DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue) { displayId != DEFAULT_DISPLAY ) { desktopDisplayModeController.updateExternalDisplayWindowingMode(displayId) desktopDisplayModeController.updateExternalDisplayWindowingMode(displayId) // The default display's windowing mode depends on the desktop eligibility of the // The default display's windowing mode depends on the desktop eligibility of the // external display. So updating the default display's windowing mode here. // external display. So updating the default display's windowing mode here. desktopDisplayModeController.updateDefaultDisplayWindowingMode() desktopDisplayModeController.updateDefaultDisplayWindowingMode() } } if (DesktopExperienceFlags.ENABLE_DISPLAY_DISCONNECT_INTERACTION.isTrue()) { handlePotentialDeskDisplayChange(displayId) } } 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 logV( "onDesktopModeEligibleChanged: displayId=%d has become desktop eligible", displayId, ) if (!handlePotentialReconnect(displayId)) { createDefaultDesksIfNeeded(displayIds = listOf(displayId), userId = null) } } else { // A display has become desktop ineligible. Treat this as a potential disconnect. logV( "onDesktopModeEligibleChanged: displayId=%d has become desktop ineligible", displayId, ) desktopTasksController.disconnectDisplay(displayId) } } private fun handlePotentialReconnect(displayId: Int): Boolean { val uniqueDisplayId = displayController.getDisplay(displayId)?.uniqueId uniqueDisplayId?.let { uniqueIdByDisplayId[displayId] = it if ( DesktopExperienceFlags.ENABLE_DISPLAY_RECONNECT_INTERACTION.isTrue && desktopUserRepositories.current.hasPreservedDisplayForUniqueDisplayId(it) ) { desktopTasksController.restoreDisplay(displayId, it) return true } } return false } } override fun onDeskRemoved(lastDisplayId: Int, deskId: Int) { override fun onDeskRemoved(lastDisplayId: Int, deskId: Int) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -120,6 +120,7 @@ class DesktopRepository( /** Stores the last state of the given display, along with the bounds of the tasks on it. */ /** Stores the last state of the given display, along with the bounds of the tasks on it. */ fun preserveDisplay(displayId: Int, uniqueId: String) { fun preserveDisplay(displayId: Int, uniqueId: String) { logD("preserveDisplay for displayId=%d, uniqueId=%s", displayId, uniqueId) val orderedDesks = desktopData.getOrderedDesks(displayId) val orderedDesks = desktopData.getOrderedDesks(displayId) // Do not preserve the display if there are no active tasks on it. // Do not preserve the display if there are no active tasks on it. if (!orderedDesks.any { it.activeTasks.isNotEmpty() }) return if (!orderedDesks.any { it.activeTasks.isNotEmpty() }) return Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +63 −30 Original line number Original line Diff line number Diff line Loading @@ -691,19 +691,42 @@ class DesktopTasksController( createDeskRoot(displayId, userId) { deskId -> cont.resumeWith(Result.success(deskId)) } createDeskRoot(displayId, userId) { deskId -> cont.resumeWith(Result.success(deskId)) } } } /** Start a disconnect transition directly in Shell. */ fun disconnectDisplay(disconnectedDisplayId: Int) { logD("disconnectDisplay: disconnectedDisplayId=$disconnectedDisplayId") val disconnectReparentDisplay = UserManager.get(userProfileContexts.userContext).mainDisplayIdAssignedToUser val wct = WindowContainerTransaction() val runOnTransitStart = addOnDisplayDisconnectChanges(wct, disconnectedDisplayId, disconnectReparentDisplay) val transition = transitions.startTransition(TRANSIT_CLOSE, wct, null) runOnTransitStart(transition) } private fun onDisplayDisconnect( private fun onDisplayDisconnect( disconnectedDisplayId: Int, disconnectedDisplayId: Int, destinationDisplayId: Int, destinationDisplayId: Int, transition: IBinder, transition: IBinder, ): WindowContainerTransaction { ): WindowContainerTransaction { val wct = WindowContainerTransaction() addOnDisplayDisconnectChanges(wct, disconnectedDisplayId, destinationDisplayId) .invoke(transition) return wct } private fun addOnDisplayDisconnectChanges( wct: WindowContainerTransaction, disconnectedDisplayId: Int, destinationDisplayId: Int, ): RunOnTransitStart { logD( logD( "onDisplayDisconnect: disconnectedDisplayId=$disconnectedDisplayId, " + "onDisplayDisconnect: disconnectedDisplayId=$disconnectedDisplayId, " + "destinationDisplayId=$destinationDisplayId" "destinationDisplayId=$destinationDisplayId" ) ) val runOnTransitStartSet = mutableListOf<RunOnTransitStart>() preserveDisplayRequestHandler?.requestPreserveDisplay(disconnectedDisplayId) preserveDisplayRequestHandler?.requestPreserveDisplay(disconnectedDisplayId) // TODO: b/406320371 - Verify this works with non-system users once the underlying bug is // TODO: b/406320371 - Verify this works with non-system users once the underlying bug is // resolved. // resolved. val wct = WindowContainerTransaction() // TODO: b/391652399 - Investigate why sometimes disconnect results in a black background. // TODO: b/391652399 - Investigate why sometimes disconnect results in a black background. // Additionally, investigate why wallpaper goes to front for inactive users. // Additionally, investigate why wallpaper goes to front for inactive users. val desktopModeSupportedOnDisplay = val desktopModeSupportedOnDisplay = Loading @@ -728,6 +751,7 @@ class DesktopTasksController( if (deskTasks.isEmpty()) { if (deskTasks.isEmpty()) { logD("onDisplayDisconnect: removing empty desk=$deskId") logD("onDisplayDisconnect: removing empty desk=$deskId") desksOrganizer.removeDesk(wct, deskId, desktopRepository.userId) desksOrganizer.removeDesk(wct, deskId, desktopRepository.userId) runOnTransitStartSet.add { transition -> desksTransitionObserver.addPendingTransition( desksTransitionObserver.addPendingTransition( DeskTransition.RemoveDesk( DeskTransition.RemoveDesk( token = transition, token = transition, Loading @@ -738,6 +762,7 @@ class DesktopTasksController( runOnTransitEnd = { snapEventHandler.onDeskRemoved(deskId) }, runOnTransitEnd = { snapEventHandler.onDeskRemoved(deskId) }, ) ) ) ) } } else { } else { logD( logD( "onDisplayDisconnect: reparenting desk=$deskId to " + "onDisplayDisconnect: reparenting desk=$deskId to " + Loading @@ -755,6 +780,7 @@ class DesktopTasksController( } } applyFreeformDisplayChange(wct, task, destinationDisplayId, deskId) applyFreeformDisplayChange(wct, task, destinationDisplayId, deskId) } } runOnTransitStartSet.add { transition -> desksTransitionObserver.addPendingTransition( desksTransitionObserver.addPendingTransition( DeskTransition.ChangeDeskDisplay( DeskTransition.ChangeDeskDisplay( transition, transition, Loading @@ -762,13 +788,14 @@ class DesktopTasksController( destinationDisplayId, destinationDisplayId, ) ) ) ) } updateDesksActivationOnDisconnection( updateDesksActivationOnDisconnection( deskId, deskId, destinationDisplayId, destinationDisplayId, wct, wct, toTop, toTop, ) ) ?.invoke(transition) ?.let { runOnTransitStartSet.add(it) } } } } } } else { } else { Loading @@ -792,6 +819,7 @@ class DesktopTasksController( destDisplayLayout?.densityDpi()?.let { wct.setDensityDpi(task.token, it) } destDisplayLayout?.densityDpi()?.let { wct.setDensityDpi(task.token, it) } } } desksOrganizer.removeDesk(wct, deskId, userId) desksOrganizer.removeDesk(wct, deskId, userId) runOnTransitStartSet.add { transition -> desksTransitionObserver.addPendingTransition( desksTransitionObserver.addPendingTransition( DeskTransition.RemoveDesk( DeskTransition.RemoveDesk( token = transition, token = transition, Loading @@ -808,7 +836,12 @@ class DesktopTasksController( } } } } } } return wct } return { transition -> for (runOnTransitStart in runOnTransitStartSet) { runOnTransitStart(transition) } } } } /** /** Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt +24 −0 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.wm.shell.desktopmode import android.platform.test.annotations.EnableFlags import android.platform.test.annotations.EnableFlags import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner import android.view.Display import android.view.Display.DEFAULT_DISPLAY import android.view.Display.DEFAULT_DISPLAY import android.window.DisplayAreaInfo import android.window.DisplayAreaInfo import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest Loading Loading @@ -114,6 +115,9 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { shellInit.init() shellInit.init() verify(displayController) verify(displayController) .addDisplayWindowListener(onDisplaysChangedListenerCaptor.capture()) .addDisplayWindowListener(onDisplaysChangedListenerCaptor.capture()) val mockDisplay = mock<Display>() whenever(mockDisplay.uniqueId).thenReturn(UNIQUE_DISPLAY_ID) whenever(displayController.getDisplay(externalDisplayId)).thenReturn(mockDisplay) } } @After @After Loading Loading @@ -422,6 +426,25 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { verify(mockDesktopDisplayModeController).updateDefaultDisplayWindowingMode() verify(mockDesktopDisplayModeController).updateDefaultDisplayWindowingMode() } } @Test @EnableFlags(Flags.FLAG_ENABLE_DISPLAY_DISCONNECT_INTERACTION) fun testDesktopModeEligibleChanged_performsDisconnect() { desktopState.overrideDesktopModeSupportPerDisplay[externalDisplayId] = false onDisplaysChangedListenerCaptor.lastValue.onDesktopModeEligibleChanged(externalDisplayId) verify(mockDesktopTasksController).disconnectDisplay(externalDisplayId) } @Test @EnableFlags(Flags.FLAG_ENABLE_DISPLAY_RECONNECT_INTERACTION) fun testDesktopModeEligibleChanged_performsReconnect() { desktopState.overrideDesktopModeSupportPerDisplay[externalDisplayId] = true whenever(mockDesktopRepository.hasPreservedDisplayForUniqueDisplayId(UNIQUE_DISPLAY_ID)) .thenReturn(true) onDisplaysChangedListenerCaptor.lastValue.onDesktopModeEligibleChanged(externalDisplayId) verify(mockDesktopTasksController) .restoreDisplay(eq(externalDisplayId), eq(UNIQUE_DISPLAY_ID)) } private fun addDisplay(displayId: Int, withTda: Boolean = false) { private fun addDisplay(displayId: Int, withTda: Boolean = false) { onDisplaysChangedListenerCaptor.lastValue.onDisplayAdded(displayId) onDisplaysChangedListenerCaptor.lastValue.onDisplayAdded(displayId) if (withTda) { if (withTda) { Loading Loading @@ -469,5 +492,6 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { companion object { companion object { private const val SECOND_DISPLAY = 2 private const val SECOND_DISPLAY = 2 private const val PRIMARY_USER_ID = 10 private const val PRIMARY_USER_ID = 10 private const val UNIQUE_DISPLAY_ID = "unique_id" } } } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt +44 −16 Original line number Original line Diff line number Diff line Loading @@ -66,19 +66,10 @@ class DesktopDisplayEventHandler( private val onDisplayAreaChangeListener = OnDisplayAreaChangeListener { displayId -> private val onDisplayAreaChangeListener = OnDisplayAreaChangeListener { displayId -> logV("displayAreaChanged in displayId=%d", displayId) logV("displayAreaChanged in displayId=%d", displayId) val uniqueDisplayId = displayController.getDisplay(displayId)?.uniqueId if (!handlePotentialReconnect(displayId)) { uniqueDisplayId?.let { uniqueIdByDisplayId[displayId] = it if ( DesktopExperienceFlags.ENABLE_DISPLAY_RECONNECT_INTERACTION.isTrue && desktopUserRepositories.current.hasPreservedDisplayForUniqueDisplayId(it) ) { desktopTasksController.restoreDisplay(displayId, it) return@OnDisplayAreaChangeListener } } createDefaultDesksIfNeeded(displayIds = listOf(displayId), userId = null) createDefaultDesksIfNeeded(displayIds = listOf(displayId), userId = null) } } } // Mapping of display uniqueIds to displayId. Used to match a disconnected // Mapping of display uniqueIds to displayId. Used to match a disconnected // displayId to its uniqueId since we will not be able to fetch it after disconnect. // displayId to its uniqueId since we will not be able to fetch it after disconnect. Loading Loading @@ -153,21 +144,58 @@ class DesktopDisplayEventHandler( override fun requestPreserveDisplay(displayId: Int) { override fun requestPreserveDisplay(displayId: Int) { logV("requestPreserveDisplay displayId=%d", displayId) logV("requestPreserveDisplay displayId=%d", displayId) val uniqueId = uniqueIdByDisplayId.remove(displayId) ?: return val uniqueId = uniqueIdByDisplayId[displayId] ?: return // TODO: b/365873835 - Preserve/restore bounds for other repositories. // TODO: b/365873835 - Preserve/restore bounds for other repositories. desktopUserRepositories.current.preserveDisplay(displayId, uniqueId) desktopUserRepositories.current.preserveDisplay(displayId, uniqueId) } } override fun onDesktopModeEligibleChanged(displayId: Int) { override fun onDesktopModeEligibleChanged(displayId: Int) { if ( if (displayId == DEFAULT_DISPLAY) return DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue && if (DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue) { displayId != DEFAULT_DISPLAY ) { desktopDisplayModeController.updateExternalDisplayWindowingMode(displayId) desktopDisplayModeController.updateExternalDisplayWindowingMode(displayId) // The default display's windowing mode depends on the desktop eligibility of the // The default display's windowing mode depends on the desktop eligibility of the // external display. So updating the default display's windowing mode here. // external display. So updating the default display's windowing mode here. desktopDisplayModeController.updateDefaultDisplayWindowingMode() desktopDisplayModeController.updateDefaultDisplayWindowingMode() } } if (DesktopExperienceFlags.ENABLE_DISPLAY_DISCONNECT_INTERACTION.isTrue()) { handlePotentialDeskDisplayChange(displayId) } } 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 logV( "onDesktopModeEligibleChanged: displayId=%d has become desktop eligible", displayId, ) if (!handlePotentialReconnect(displayId)) { createDefaultDesksIfNeeded(displayIds = listOf(displayId), userId = null) } } else { // A display has become desktop ineligible. Treat this as a potential disconnect. logV( "onDesktopModeEligibleChanged: displayId=%d has become desktop ineligible", displayId, ) desktopTasksController.disconnectDisplay(displayId) } } private fun handlePotentialReconnect(displayId: Int): Boolean { val uniqueDisplayId = displayController.getDisplay(displayId)?.uniqueId uniqueDisplayId?.let { uniqueIdByDisplayId[displayId] = it if ( DesktopExperienceFlags.ENABLE_DISPLAY_RECONNECT_INTERACTION.isTrue && desktopUserRepositories.current.hasPreservedDisplayForUniqueDisplayId(it) ) { desktopTasksController.restoreDisplay(displayId, it) return true } } return false } } override fun onDeskRemoved(lastDisplayId: Int, deskId: Int) { override fun onDeskRemoved(lastDisplayId: Int, deskId: Int) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt +1 −0 Original line number Original line Diff line number Diff line Loading @@ -120,6 +120,7 @@ class DesktopRepository( /** Stores the last state of the given display, along with the bounds of the tasks on it. */ /** Stores the last state of the given display, along with the bounds of the tasks on it. */ fun preserveDisplay(displayId: Int, uniqueId: String) { fun preserveDisplay(displayId: Int, uniqueId: String) { logD("preserveDisplay for displayId=%d, uniqueId=%s", displayId, uniqueId) val orderedDesks = desktopData.getOrderedDesks(displayId) val orderedDesks = desktopData.getOrderedDesks(displayId) // Do not preserve the display if there are no active tasks on it. // Do not preserve the display if there are no active tasks on it. if (!orderedDesks.any { it.activeTasks.isNotEmpty() }) return if (!orderedDesks.any { it.activeTasks.isNotEmpty() }) return Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +63 −30 Original line number Original line Diff line number Diff line Loading @@ -691,19 +691,42 @@ class DesktopTasksController( createDeskRoot(displayId, userId) { deskId -> cont.resumeWith(Result.success(deskId)) } createDeskRoot(displayId, userId) { deskId -> cont.resumeWith(Result.success(deskId)) } } } /** Start a disconnect transition directly in Shell. */ fun disconnectDisplay(disconnectedDisplayId: Int) { logD("disconnectDisplay: disconnectedDisplayId=$disconnectedDisplayId") val disconnectReparentDisplay = UserManager.get(userProfileContexts.userContext).mainDisplayIdAssignedToUser val wct = WindowContainerTransaction() val runOnTransitStart = addOnDisplayDisconnectChanges(wct, disconnectedDisplayId, disconnectReparentDisplay) val transition = transitions.startTransition(TRANSIT_CLOSE, wct, null) runOnTransitStart(transition) } private fun onDisplayDisconnect( private fun onDisplayDisconnect( disconnectedDisplayId: Int, disconnectedDisplayId: Int, destinationDisplayId: Int, destinationDisplayId: Int, transition: IBinder, transition: IBinder, ): WindowContainerTransaction { ): WindowContainerTransaction { val wct = WindowContainerTransaction() addOnDisplayDisconnectChanges(wct, disconnectedDisplayId, destinationDisplayId) .invoke(transition) return wct } private fun addOnDisplayDisconnectChanges( wct: WindowContainerTransaction, disconnectedDisplayId: Int, destinationDisplayId: Int, ): RunOnTransitStart { logD( logD( "onDisplayDisconnect: disconnectedDisplayId=$disconnectedDisplayId, " + "onDisplayDisconnect: disconnectedDisplayId=$disconnectedDisplayId, " + "destinationDisplayId=$destinationDisplayId" "destinationDisplayId=$destinationDisplayId" ) ) val runOnTransitStartSet = mutableListOf<RunOnTransitStart>() preserveDisplayRequestHandler?.requestPreserveDisplay(disconnectedDisplayId) preserveDisplayRequestHandler?.requestPreserveDisplay(disconnectedDisplayId) // TODO: b/406320371 - Verify this works with non-system users once the underlying bug is // TODO: b/406320371 - Verify this works with non-system users once the underlying bug is // resolved. // resolved. val wct = WindowContainerTransaction() // TODO: b/391652399 - Investigate why sometimes disconnect results in a black background. // TODO: b/391652399 - Investigate why sometimes disconnect results in a black background. // Additionally, investigate why wallpaper goes to front for inactive users. // Additionally, investigate why wallpaper goes to front for inactive users. val desktopModeSupportedOnDisplay = val desktopModeSupportedOnDisplay = Loading @@ -728,6 +751,7 @@ class DesktopTasksController( if (deskTasks.isEmpty()) { if (deskTasks.isEmpty()) { logD("onDisplayDisconnect: removing empty desk=$deskId") logD("onDisplayDisconnect: removing empty desk=$deskId") desksOrganizer.removeDesk(wct, deskId, desktopRepository.userId) desksOrganizer.removeDesk(wct, deskId, desktopRepository.userId) runOnTransitStartSet.add { transition -> desksTransitionObserver.addPendingTransition( desksTransitionObserver.addPendingTransition( DeskTransition.RemoveDesk( DeskTransition.RemoveDesk( token = transition, token = transition, Loading @@ -738,6 +762,7 @@ class DesktopTasksController( runOnTransitEnd = { snapEventHandler.onDeskRemoved(deskId) }, runOnTransitEnd = { snapEventHandler.onDeskRemoved(deskId) }, ) ) ) ) } } else { } else { logD( logD( "onDisplayDisconnect: reparenting desk=$deskId to " + "onDisplayDisconnect: reparenting desk=$deskId to " + Loading @@ -755,6 +780,7 @@ class DesktopTasksController( } } applyFreeformDisplayChange(wct, task, destinationDisplayId, deskId) applyFreeformDisplayChange(wct, task, destinationDisplayId, deskId) } } runOnTransitStartSet.add { transition -> desksTransitionObserver.addPendingTransition( desksTransitionObserver.addPendingTransition( DeskTransition.ChangeDeskDisplay( DeskTransition.ChangeDeskDisplay( transition, transition, Loading @@ -762,13 +788,14 @@ class DesktopTasksController( destinationDisplayId, destinationDisplayId, ) ) ) ) } updateDesksActivationOnDisconnection( updateDesksActivationOnDisconnection( deskId, deskId, destinationDisplayId, destinationDisplayId, wct, wct, toTop, toTop, ) ) ?.invoke(transition) ?.let { runOnTransitStartSet.add(it) } } } } } } else { } else { Loading @@ -792,6 +819,7 @@ class DesktopTasksController( destDisplayLayout?.densityDpi()?.let { wct.setDensityDpi(task.token, it) } destDisplayLayout?.densityDpi()?.let { wct.setDensityDpi(task.token, it) } } } desksOrganizer.removeDesk(wct, deskId, userId) desksOrganizer.removeDesk(wct, deskId, userId) runOnTransitStartSet.add { transition -> desksTransitionObserver.addPendingTransition( desksTransitionObserver.addPendingTransition( DeskTransition.RemoveDesk( DeskTransition.RemoveDesk( token = transition, token = transition, Loading @@ -808,7 +836,12 @@ class DesktopTasksController( } } } } } } return wct } return { transition -> for (runOnTransitStart in runOnTransitStartSet) { runOnTransitStart(transition) } } } } /** /** Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt +24 −0 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.wm.shell.desktopmode import android.platform.test.annotations.EnableFlags import android.platform.test.annotations.EnableFlags import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner import android.view.Display import android.view.Display.DEFAULT_DISPLAY import android.view.Display.DEFAULT_DISPLAY import android.window.DisplayAreaInfo import android.window.DisplayAreaInfo import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest Loading Loading @@ -114,6 +115,9 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { shellInit.init() shellInit.init() verify(displayController) verify(displayController) .addDisplayWindowListener(onDisplaysChangedListenerCaptor.capture()) .addDisplayWindowListener(onDisplaysChangedListenerCaptor.capture()) val mockDisplay = mock<Display>() whenever(mockDisplay.uniqueId).thenReturn(UNIQUE_DISPLAY_ID) whenever(displayController.getDisplay(externalDisplayId)).thenReturn(mockDisplay) } } @After @After Loading Loading @@ -422,6 +426,25 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { verify(mockDesktopDisplayModeController).updateDefaultDisplayWindowingMode() verify(mockDesktopDisplayModeController).updateDefaultDisplayWindowingMode() } } @Test @EnableFlags(Flags.FLAG_ENABLE_DISPLAY_DISCONNECT_INTERACTION) fun testDesktopModeEligibleChanged_performsDisconnect() { desktopState.overrideDesktopModeSupportPerDisplay[externalDisplayId] = false onDisplaysChangedListenerCaptor.lastValue.onDesktopModeEligibleChanged(externalDisplayId) verify(mockDesktopTasksController).disconnectDisplay(externalDisplayId) } @Test @EnableFlags(Flags.FLAG_ENABLE_DISPLAY_RECONNECT_INTERACTION) fun testDesktopModeEligibleChanged_performsReconnect() { desktopState.overrideDesktopModeSupportPerDisplay[externalDisplayId] = true whenever(mockDesktopRepository.hasPreservedDisplayForUniqueDisplayId(UNIQUE_DISPLAY_ID)) .thenReturn(true) onDisplaysChangedListenerCaptor.lastValue.onDesktopModeEligibleChanged(externalDisplayId) verify(mockDesktopTasksController) .restoreDisplay(eq(externalDisplayId), eq(UNIQUE_DISPLAY_ID)) } private fun addDisplay(displayId: Int, withTda: Boolean = false) { private fun addDisplay(displayId: Int, withTda: Boolean = false) { onDisplaysChangedListenerCaptor.lastValue.onDisplayAdded(displayId) onDisplaysChangedListenerCaptor.lastValue.onDisplayAdded(displayId) if (withTda) { if (withTda) { Loading Loading @@ -469,5 +492,6 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { companion object { companion object { private const val SECOND_DISPLAY = 2 private const val SECOND_DISPLAY = 2 private const val PRIMARY_USER_ID = 10 private const val PRIMARY_USER_ID = 10 private const val UNIQUE_DISPLAY_ID = "unique_id" } } } }