From a867d0e593f2020f79b8a3d4250e6a555ddc4782 Mon Sep 17 00:00:00 2001 From: Toshiki Kikuchi Date: Thu, 20 Mar 2025 21:37:59 +0900 Subject: Ensure external display to be freeform display This CL ensures that an external display is always a freeform display when the desktop mode is supported. As enableDisplayContentModeManagement flag deprecated DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, which previously affected the windowing mode of external displays. DesktopDisplayModeController should be responsible for it instead now. Flag: com.android.server.display.feature.flags.enable_display_content_mode_management Bug: 404724976 Test: DesktopDisplayModeControllerTest Test: DesktopDisplayEventHandlerTest Change-Id: I9284a20f7de49a6cfc0a61f96b0fd793984dab38 --- .../desktopmode/DesktopDisplayEventHandler.kt | 12 ++++-- .../desktopmode/DesktopDisplayModeController.kt | 43 ++++++++++++++++------ .../desktopmode/DesktopDisplayEventHandlerTest.kt | 8 ++-- .../DesktopDisplayModeControllerTest.kt | 21 ++++++++++- 4 files changed, 64 insertions(+), 20 deletions(-) (limited to 'libs') diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt index 25737c4950d6..771736565ba1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt @@ -75,7 +75,10 @@ class DesktopDisplayEventHandler( override fun onDisplayAdded(displayId: Int) { if (displayId != DEFAULT_DISPLAY) { - desktopDisplayModeController.refreshDisplayWindowingMode() + desktopDisplayModeController.updateExternalDisplayWindowingMode(displayId) + // The default display's windowing mode depends on the availability of the external + // display. So updating the default display's windowing mode here. + desktopDisplayModeController.updateDefaultDisplayWindowingMode() } createDefaultDesksIfNeeded(displayIds = setOf(displayId)) @@ -83,7 +86,7 @@ class DesktopDisplayEventHandler( override fun onDisplayRemoved(displayId: Int) { if (displayId != DEFAULT_DISPLAY) { - desktopDisplayModeController.refreshDisplayWindowingMode() + desktopDisplayModeController.updateDefaultDisplayWindowingMode() } // TODO: b/362720497 - move desks in closing display to the remaining desk. @@ -94,7 +97,10 @@ class DesktopDisplayEventHandler( DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue && displayId != DEFAULT_DISPLAY ) { - desktopDisplayModeController.refreshDisplayWindowingMode() + desktopDisplayModeController.updateExternalDisplayWindowingMode(displayId) + // The default display's windowing mode depends on the desktop eligibility of the + // external display. So updating the default display's windowing mode here. + desktopDisplayModeController.updateDefaultDisplayWindowingMode() } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayModeController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayModeController.kt index 0a3e2cc3b434..dec489e8fc63 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayModeController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayModeController.kt @@ -59,15 +59,15 @@ class DesktopDisplayModeController( private val inputDeviceListener = object : InputManager.InputDeviceListener { override fun onInputDeviceAdded(deviceId: Int) { - refreshDisplayWindowingMode() + updateDefaultDisplayWindowingMode() } override fun onInputDeviceChanged(deviceId: Int) { - refreshDisplayWindowingMode() + updateDefaultDisplayWindowingMode() } override fun onInputDeviceRemoved(deviceId: Int) { - refreshDisplayWindowingMode() + updateDefaultDisplayWindowingMode() } } @@ -77,12 +77,30 @@ class DesktopDisplayModeController( } } - fun refreshDisplayWindowingMode() { + fun updateExternalDisplayWindowingMode(displayId: Int) { + if (!DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue) return + + val desktopModeSupported = + displayController.getDisplay(displayId)?.let { display -> + DesktopModeStatus.isDesktopModeSupportedOnDisplay(context, display) + } ?: false + if (!desktopModeSupported) return + + // An external display should always be a freeform display when desktop mode is enabled. + updateDisplayWindowingMode(displayId, WINDOWING_MODE_FREEFORM) + } + + fun updateDefaultDisplayWindowingMode() { if (!DesktopExperienceFlags.ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING.isTrue) return - val targetDisplayWindowingMode = getTargetWindowingModeForDefaultDisplay() - val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY) - requireNotNull(tdaInfo) { "DisplayAreaInfo of DEFAULT_DISPLAY must be non-null." } + updateDisplayWindowingMode(DEFAULT_DISPLAY, getTargetWindowingModeForDefaultDisplay()) + } + + private fun updateDisplayWindowingMode(displayId: Int, targetDisplayWindowingMode: Int) { + val tdaInfo = + requireNotNull(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId)) { + "DisplayAreaInfo of display#$displayId must be non-null." + } val currentDisplayWindowingMode = tdaInfo.configuration.windowConfiguration.windowingMode if (currentDisplayWindowingMode == targetDisplayWindowingMode) { // Already in the target mode. @@ -90,15 +108,16 @@ class DesktopDisplayModeController( } logV( - "As an external display is connected, changing default display's windowing mode from" + - " ${windowingModeToString(currentDisplayWindowingMode)}" + - " to ${windowingModeToString(targetDisplayWindowingMode)}" + "Changing display#%d's windowing mode from %s to %s", + displayId, + windowingModeToString(currentDisplayWindowingMode), + windowingModeToString(targetDisplayWindowingMode), ) val wct = WindowContainerTransaction() wct.setWindowingMode(tdaInfo.token, targetDisplayWindowingMode) shellTaskOrganizer - .getRunningTasks(DEFAULT_DISPLAY) + .getRunningTasks(displayId) .filter { it.activityType == ACTIVITY_TYPE_STANDARD } .forEach { // TODO: b/391965153 - Reconsider the logic under multi-desk window hierarchy @@ -114,7 +133,7 @@ class DesktopDisplayModeController( // The override windowing mode of DesktopWallpaper can be UNDEFINED on fullscreen-display // right after the first launch while its resolved windowing mode is FULLSCREEN. We here // it has the FULLSCREEN override windowing mode. - desktopWallpaperActivityTokenProvider.getToken(DEFAULT_DISPLAY)?.let { token -> + desktopWallpaperActivityTokenProvider.getToken(displayId)?.let { token -> wct.setWindowingMode(token, WINDOWING_MODE_FULLSCREEN) } transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt index 85a431be8e8b..7eb6c4833961 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt @@ -238,20 +238,22 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { @Test fun testConnectExternalDisplay() { onDisplaysChangedListenerCaptor.lastValue.onDisplayAdded(externalDisplayId) - verify(desktopDisplayModeController).refreshDisplayWindowingMode() + verify(desktopDisplayModeController).updateExternalDisplayWindowingMode(externalDisplayId) + verify(desktopDisplayModeController).updateDefaultDisplayWindowingMode() } @Test fun testDisconnectExternalDisplay() { onDisplaysChangedListenerCaptor.lastValue.onDisplayRemoved(externalDisplayId) - verify(desktopDisplayModeController).refreshDisplayWindowingMode() + verify(desktopDisplayModeController).updateDefaultDisplayWindowingMode() } @Test @EnableFlags(DisplayFlags.FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT) fun testDesktopModeEligibleChanged() { onDisplaysChangedListenerCaptor.lastValue.onDesktopModeEligibleChanged(externalDisplayId) - verify(desktopDisplayModeController).refreshDisplayWindowingMode() + verify(desktopDisplayModeController).updateExternalDisplayWindowingMode(externalDisplayId) + verify(desktopDisplayModeController).updateDefaultDisplayWindowingMode() } private class FakeDesktopRepositoryInitializer : DesktopRepositoryInitializer { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayModeControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayModeControllerTest.kt index 488025a3d754..7e9ee34c8f68 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayModeControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayModeControllerTest.kt @@ -101,6 +101,7 @@ class DesktopDisplayModeControllerTest( private val fullscreenTask = TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FULLSCREEN).build() private val defaultTDA = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0) + private val externalTDA = DisplayAreaInfo(MockToken().token(), EXTERNAL_DISPLAY_ID, 0) private val wallpaperToken = MockToken().token() private val defaultDisplay = mock() private val externalDisplay = mock() @@ -129,6 +130,8 @@ class DesktopDisplayModeControllerTest( whenever(transitions.startTransition(anyInt(), any(), isNull())).thenReturn(Binder()) whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)) .thenReturn(defaultTDA) + whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(EXTERNAL_DISPLAY_ID)) + .thenReturn(externalTDA) controller = DesktopDisplayModeController( context, @@ -292,16 +295,30 @@ class DesktopDisplayModeControllerTest( .isEqualTo(WINDOWING_MODE_UNDEFINED) } + @Test + @EnableFlags(DisplayFlags.FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT) + fun externalDisplayWindowingMode() { + externalTDA.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN + setExtendedMode(true) + + controller.updateExternalDisplayWindowingMode(EXTERNAL_DISPLAY_ID) + + val arg = argumentCaptor() + verify(transitions, times(1)).startTransition(eq(TRANSIT_CHANGE), arg.capture(), isNull()) + assertThat(arg.firstValue.changes[externalTDA.token.asBinder()]?.windowingMode) + .isEqualTo(WINDOWING_MODE_FREEFORM) + } + private fun connectExternalDisplay() { whenever(rootTaskDisplayAreaOrganizer.getDisplayIds()) .thenReturn(intArrayOf(DEFAULT_DISPLAY, EXTERNAL_DISPLAY_ID)) - controller.refreshDisplayWindowingMode() + controller.updateDefaultDisplayWindowingMode() } private fun disconnectExternalDisplay() { whenever(rootTaskDisplayAreaOrganizer.getDisplayIds()) .thenReturn(intArrayOf(DEFAULT_DISPLAY)) - controller.refreshDisplayWindowingMode() + controller.updateDefaultDisplayWindowingMode() } private fun setExtendedMode(enabled: Boolean) { -- cgit v1.2.3-59-g8ed1b