Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a867d0e5 authored by Toshiki Kikuchi's avatar Toshiki Kikuchi
Browse files

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
parent 01883486
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -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()
        }
    }

+31 −12
Original line number Diff line number Diff line
@@ -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)
+5 −3
Original line number Diff line number Diff line
@@ -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 {
+19 −2
Original line number Diff line number Diff line
@@ -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<Display>()
    private val externalDisplay = mock<Display>()
@@ -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<WindowContainerTransaction>()
        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) {