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

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

Merge "Don't allow moving tasks to displays that can't host desktop tasks." into main

parents 95e2b929 69f32290
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -69,7 +69,7 @@ class DesktopModeKeyGestureHandler(
                logV("Key gesture MOVE_TO_NEXT_DISPLAY is handled")
                getGloballyFocusedFreeformTask()?.let {
                    mainExecutor.execute {
                        desktopTasksController.get().moveToNextDisplay(it.taskId)
                        desktopTasksController.get().moveToNextDesktopDisplay(it.taskId)
                    }
                }
            }
+19 −15
Original line number Diff line number Diff line
@@ -1236,36 +1236,40 @@ class DesktopTasksController(
    /**
     * Move task to the next display.
     *
     * Queries all current known display ids and sorts them in ascending order. Then iterates
     * through the list and looks for the display id that is larger than the display id for the
     * passed in task. If a display with a higher id is not found, iterates through the list and
     * finds the first display id that is not the display id for the passed in task.
     * Queries all currently known display IDs and checks if they match the predicate. The check is
     * performed in an order such that display IDs greater than the passed task's displayId are
     * considered before display IDs less than or equal to the passed task's displayID. Within each
     * of these two groups, the check is performed in ascending order.
     *
     * If a display matching the above criteria is found, re-parents the task to that display. No-op
     * if no such display is found.
     * If a display ID matches predicate is found, re-parents the task to that display. No-op if no
     * such display is found.
     */
    fun moveToNextDisplay(taskId: Int) {
    fun moveToNextDisplay(taskId: Int, predicate: (Int) -> Boolean = { true }) {
        val task = shellTaskOrganizer.getRunningTaskInfo(taskId)
        if (task == null) {
            logW("moveToNextDisplay: taskId=%d not found", taskId)
            return
        }
        logV("moveToNextDisplay: taskId=%d displayId=%d", taskId, task.displayId)

        val displayIds = rootTaskDisplayAreaOrganizer.displayIds.sorted()
        // Get the first display id that is higher than current task display id
        var newDisplayId = displayIds.firstOrNull { displayId -> displayId > task.displayId }
        if (newDisplayId == null) {
            // No display with a higher id, get the first display id that is not the task display id
            newDisplayId = displayIds.firstOrNull { displayId -> displayId < task.displayId }
        }
        val newDisplayId =
            rootTaskDisplayAreaOrganizer.displayIds
                .sortedBy { (it - task.displayId - 1).mod(Int.MAX_VALUE) }
                .find(predicate)
        if (newDisplayId == null) {
            logW("moveToNextDisplay: next display not found")
            return
        }
        // moveToDisplay is no-op if newDisplayId is same with task.displayId.
        moveToDisplay(task, newDisplayId)
    }

    /** Move task to the next display which can host desktop tasks. */
    fun moveToNextDesktopDisplay(taskId: Int) =
        moveToNextDisplay(taskId) {
            val display = displayController.getDisplay(it) ?: return@moveToNextDisplay false
            DesktopModeStatus.isDesktopModeSupportedOnDisplay(context, display)
        }

    /**
     * Start an intent through a launch transition for starting tasks whose transition does not get
     * handled by [handleRequest]
+1 −1
Original line number Diff line number Diff line
@@ -178,7 +178,7 @@ class DesktopModeKeyGestureHandlerTest : ShellTestCase() {
        keyGestureEventHandler.handleKeyGestureEvent(event, null)
        testExecutor.flushAll()

        verify(desktopTasksController).moveToNextDisplay(task.taskId)
        verify(desktopTasksController).moveToNextDesktopDisplay(task.taskId)
    }

    @Test
+55 −0
Original line number Diff line number Diff line
@@ -371,6 +371,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        whenever(displayLayout.densityDpi()).thenReturn(160)
        whenever(runBlocking { persistentRepository.readDesktop(any(), any()) })
            .thenReturn(Desktop.getDefaultInstance())
        whenever(display.type).thenReturn(Display.TYPE_INTERNAL)
        doReturn(mockToast).`when` { Toast.makeText(any(), anyInt(), anyInt()) }

        val tda = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0)
@@ -3353,6 +3354,60 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        verify(taskbarDesktopTaskListener).onTaskbarCornerRoundingUpdate(anyBoolean())
    }

    private fun moveToNextDesktopDisplay_moveIifDesktopModeSupportedOnDestination(
        isDesktopModeSupportedOnDestination: Boolean
    ) {
        // Set up two display ids
        whenever(rootTaskDisplayAreaOrganizer.displayIds)
            .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY))

        // Add desk if destination support desktop
        if (isDesktopModeSupportedOnDestination) {
            taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = 2)
        }

        // Create a mock for the target display area: second display
        val secondDisplayArea = DisplayAreaInfo(MockToken().token(), SECOND_DISPLAY, 0)
        whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(SECOND_DISPLAY))
            .thenReturn(secondDisplayArea)

        // Set up external display content
        val secondaryDisplay = mock(Display::class.java)
        whenever(displayController.getDisplay(SECOND_DISPLAY)).thenReturn(secondaryDisplay)

        doReturn(isDesktopModeSupportedOnDestination).`when` {
            DesktopModeStatus.isDesktopModeSupportedOnDisplay(any<Context>(), eq(secondaryDisplay))
        }

        // Set up a task on the default display
        val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY)

        controller.moveToNextDesktopDisplay(task.taskId)

        val verificationMode =
            if (isDesktopModeSupportedOnDestination) {
                times(1)
            } else {
                never()
            }
        verify(transitions, verificationMode)
            .startTransition(
                eq(TRANSIT_CHANGE),
                any<WindowContainerTransaction>(),
                isA(DesktopModeMoveToDisplayTransitionHandler::class.java),
            )
    }

    @Test
    fun moveToNextDesktopDisplay_moveIfDesktopModeSupportedOnDestination() {
        moveToNextDesktopDisplay_moveIifDesktopModeSupportedOnDestination(true)
    }

    @Test
    fun moveToNextDesktopDisplay_dontMoveIfDesktopModeNotSupportedOnDestination() {
        moveToNextDesktopDisplay_moveIifDesktopModeSupportedOnDestination(false)
    }

    @Test
    fun getTaskWindowingMode() {
        val fullscreenTask = setUpFullscreenTask()