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

Commit a39bea6b authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Treat eligibility changes as potential disconnect/reconnect." into main

parents 5a077e1a d9ebd679
Loading
Loading
Loading
Loading
+44 −16
Original line number Original line Diff line number Diff line
@@ -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.
@@ -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) {
+1 −0
Original line number Original line Diff line number Diff line
@@ -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
+63 −30
Original line number Original line Diff line number Diff line
@@ -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 =
@@ -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,
@@ -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 " +
@@ -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,
@@ -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 {
@@ -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,
@@ -808,7 +836,12 @@ class DesktopTasksController(
                    }
                    }
                }
                }
            }
            }
        return wct
        }
        return { transition ->
            for (runOnTransitStart in runOnTransitStartSet) {
                runOnTransitStart(transition)
            }
        }
    }
    }


    /**
    /**
+24 −0
Original line number Original line Diff line number Diff line
@@ -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
@@ -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
@@ -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) {
@@ -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"
    }
    }
}
}