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

Commit 2e35ee42 authored by Matt Sziklay's avatar Matt Sziklay
Browse files

Prevent restored display tasks from showing on keyguard.

No-ops restoreDisplay events that occur when keyguard is present. To
ensure the display is eventually restored, adds DesktopTasksController
as a KeyguardChangeListener to perform needed display restorations when
keyguard is removed.

Bug: 433640030
Test: Manual
Flag: com.android.window.flags.enable_display_reconnect_interaction
Change-Id: I5eb80a0a0b03d30db26ffbf17660458baaa8de25
parent 0036f991
Loading
Loading
Loading
Loading
+25 −1
Original line number Diff line number Diff line
@@ -165,6 +165,7 @@ 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
@@ -256,7 +257,8 @@ class DesktopTasksController(
    RemoteCallable<DesktopTasksController>,
    Transitions.TransitionHandler,
    DragAndDropController.DragAndDropListener,
    UserChangeListener {
    UserChangeListener,
    KeyguardChangeListener {

    private val desktopMode: DesktopModeImpl
    private var visualIndicator: DesktopModeVisualIndicator? = null
@@ -354,6 +356,7 @@ class DesktopTasksController(
            }
        )
        dragAndDropController.addListener(this)
        shellController.addKeyguardChangeListener(this)
    }

    @VisibleForTesting
@@ -810,6 +813,25 @@ class DesktopTasksController(
        }
    }

    override fun onKeyguardVisibilityChanged(
        visible: Boolean,
        occluded: Boolean,
        animatingDismiss: Boolean,
    ) {
        if (visible) return
        val displaysByUniqueId = displayController.allDisplaysByUniqueId ?: return
        for (displayIdByUniqueId in displaysByUniqueId) {
            val taskRepository = userRepositories.current
            if (taskRepository.hasPreservedDisplayForUniqueDisplayId(displayIdByUniqueId.key)) {
                restoreDisplay(
                    displayIdByUniqueId.value,
                    displayIdByUniqueId.key,
                    taskRepository.userId,
                )
            }
        }
    }

    private fun handleExtendedModeDisconnect(
        desktopRepository: DesktopRepository,
        wct: WindowContainerTransaction,
@@ -948,6 +970,8 @@ class DesktopTasksController(
        )
        // 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)
+108 −0
Original line number Diff line number Diff line
@@ -11051,6 +11051,114 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
            verify(desksOrganizer).moveTaskToDesk(any(), anyInt(), eq(secondTask), eq(false))
        }

    @Test
    @EnableFlags(
        Flags.FLAG_ENABLE_DISPLAY_DISCONNECT_INTERACTION,
        Flags.FLAG_ENABLE_DISPLAY_RECONNECT_INTERACTION,
        Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
    )
    fun restoreDisplay_keyguardLocked_noOp() =
        testScope.runTest {
            taskRepository.addDesk(SECOND_DISPLAY, DISCONNECTED_DESK_ID, SECOND_DISPLAY_UNIQUE_ID)
            taskRepository.setActiveDesk(displayId = SECOND_DISPLAY, deskId = DISCONNECTED_DESK_ID)
            val firstTaskBounds = Rect(100, 300, 1000, 1200)
            val firstTask =
                setUpFreeformTask(
                    displayId = SECOND_DISPLAY,
                    deskId = DISCONNECTED_DESK_ID,
                    bounds = firstTaskBounds,
                )
            val secondTaskBounds = Rect(400, 400, 1600, 900)
            val secondTask =
                setUpFreeformTask(
                    displayId = SECOND_DISPLAY,
                    deskId = DISCONNECTED_DESK_ID,
                    bounds = secondTaskBounds,
                )
            val wctCaptor = argumentCaptor<WindowContainerTransaction>()
            taskRepository.preserveDisplay(SECOND_DISPLAY, SECOND_DISPLAY_UNIQUE_ID)
            taskRepository.onDeskDisplayChanged(
                DISCONNECTED_DESK_ID,
                DEFAULT_DISPLAY,
                DEFAULT_DISPLAY_UNIQUE_ID,
            )
            whenever(desksOrganizer.createDesk(eq(SECOND_DISPLAY_ON_RECONNECT), any(), any()))
                .thenAnswer { invocation ->
                    (invocation.arguments[2] as DesksOrganizer.OnCreateCallback).onCreated(
                        deskId = 5
                    )
                }
            whenever(keyguardManager.isKeyguardLocked).thenReturn(true)

            controller.restoreDisplay(
                SECOND_DISPLAY_ON_RECONNECT,
                SECOND_DISPLAY_UNIQUE_ID,
                DEFAULT_USER_ID,
            )
            runCurrent()

            verify(transitions, never()).startTransition(anyInt(), any(), anyOrNull())
        }

    @Test
    @EnableFlags(
        Flags.FLAG_ENABLE_DISPLAY_DISCONNECT_INTERACTION,
        Flags.FLAG_ENABLE_DISPLAY_RECONNECT_INTERACTION,
        Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
    )
    fun keyguardUnlocked_displayToRestore_restoresDisplay() =
        testScope.runTest {
            taskRepository.addDesk(SECOND_DISPLAY, DISCONNECTED_DESK_ID, SECOND_DISPLAY_UNIQUE_ID)
            taskRepository.setActiveDesk(displayId = SECOND_DISPLAY, deskId = DISCONNECTED_DESK_ID)
            val firstTaskBounds = Rect(100, 300, 1000, 1200)
            val firstTask =
                setUpFreeformTask(
                    displayId = SECOND_DISPLAY,
                    deskId = DISCONNECTED_DESK_ID,
                    bounds = firstTaskBounds,
                )
            val secondTaskBounds = Rect(400, 400, 1600, 900)
            val secondTask =
                setUpFreeformTask(
                    displayId = SECOND_DISPLAY,
                    deskId = DISCONNECTED_DESK_ID,
                    bounds = secondTaskBounds,
                )
            val wctCaptor = argumentCaptor<WindowContainerTransaction>()
            taskRepository.preserveDisplay(SECOND_DISPLAY, SECOND_DISPLAY_UNIQUE_ID)
            taskRepository.onDeskDisplayChanged(
                DISCONNECTED_DESK_ID,
                DEFAULT_DISPLAY,
                DEFAULT_DISPLAY_UNIQUE_ID,
            )
            whenever(desksOrganizer.createDesk(eq(SECOND_DISPLAY_ON_RECONNECT), any(), any()))
                .thenAnswer { invocation ->
                    (invocation.arguments[2] as DesksOrganizer.OnCreateCallback).onCreated(
                        deskId = 5
                    )
                }
            whenever(displayController.allDisplaysByUniqueId)
                .thenReturn(
                    mutableMapOf(
                        DEFAULT_DISPLAY_UNIQUE_ID to DEFAULT_DISPLAY,
                        SECOND_DISPLAY_UNIQUE_ID to SECOND_DISPLAY_ON_RECONNECT,
                    )
                )
            whenever(keyguardManager.isKeyguardLocked).thenReturn(false)

            controller.onKeyguardVisibilityChanged(false, false, false)
            runCurrent()

            verify(transitions).startTransition(anyInt(), wctCaptor.capture(), anyOrNull())
            val wct = wctCaptor.firstValue
            assertThat(findBoundsChange(wct, firstTask)).isEqualTo(firstTaskBounds)
            assertThat(findBoundsChange(wct, secondTask)).isEqualTo(secondTaskBounds)
            wct.assertReorder(task = firstTask, toTop = true, includingParents = true)
            wct.assertReorder(task = secondTask, toTop = true, includingParents = true)
            verify(desksOrganizer).moveTaskToDesk(any(), anyInt(), eq(firstTask), eq(false))
            verify(desksOrganizer).moveTaskToDesk(any(), anyInt(), eq(secondTask), eq(false))
        }

    @Test
    @EnableFlags(
        Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,