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

Commit 3740c6da authored by Merissa Mitchell's avatar Merissa Mitchell Committed by Android (Google) Code Review
Browse files

Merge changes Iba716113,I36971db0 into main

* changes:
  [PiP on Desktop] Don't reparent PiP task to Desk if mid-Recents
  [PiP on Desktop] Fix PiP issues with multiple_desktops_backend flag
parents 2ab4238b aceec04c
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -119,12 +119,16 @@ class PipDesktopState(
    fun isDisplayDesktopFirst(displayId: Int) =
        rootTaskDisplayAreaOrganizer.isDisplayDesktopFirst(displayId)

    /** Returns whether Recents is in the middle of animating. */
    fun isRecentsAnimating(): Boolean =
        RecentsTransitionStateListener.isAnimating(recentsTransitionState)

    /** Returns the windowing mode to restore to when resizing out of PIP direction. */
    fun getOutPipWindowingMode(): Int {
        val isInDesktop = isPipInDesktopMode()
        // Temporary workaround for b/409201669: Always expand to fullscreen if we're exiting PiP
        // in the middle of Recents animation from Desktop session.
        if (RecentsTransitionStateListener.isAnimating(recentsTransitionState) && isInDesktop) {
        if (isRecentsAnimating() && isInDesktop) {
            return WINDOWING_MODE_FULLSCREEN
        }

+40 −4
Original line number Diff line number Diff line
@@ -67,15 +67,15 @@ class DesktopPipTransitionController(
            parentTask.lastNonFullscreenBounds?.takeUnless { it.isEmpty }
                ?: calculateDefaultDesktopTaskBounds(pipDesktopState.getCurrentDisplayLayout())

        val newResolvedWinMode =
        val resolvedWinMode =
            if (pipDesktopState.isPipInDesktopMode()) WINDOWING_MODE_FREEFORM
            else WINDOWING_MODE_FULLSCREEN

        if (newResolvedWinMode != parentTask.windowingMode) {
            wct.setWindowingMode(parentTask.token, newResolvedWinMode)
        if (resolvedWinMode != parentTask.windowingMode) {
            wct.setWindowingMode(parentTask.token, resolvedWinMode)
            wct.setBounds(
                parentTask.token,
                if (newResolvedWinMode == WINDOWING_MODE_FREEFORM) defaultFreeformBounds else Rect()
                if (resolvedWinMode == WINDOWING_MODE_FREEFORM) defaultFreeformBounds else Rect(),
            )
        }
    }
@@ -91,8 +91,11 @@ class DesktopPipTransitionController(
     * @param taskId of the task that is exiting PiP
     */
    fun maybeReparentTaskToDesk(wct: WindowContainerTransaction, taskId: Int) {
        // Temporary workaround for b/409201669: We always expand to fullscreen if we're exiting PiP
        // in the middle of Recents animation from Desktop session, so don't reparent to the Desk.
        if (
            !pipDesktopState.isDesktopWindowingPipEnabled() ||
                pipDesktopState.isRecentsAnimating() ||
                !DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue
        ) {
            return
@@ -113,6 +116,17 @@ class DesktopPipTransitionController(

        val deskId = getDeskId(desktopRepository, displayId)
        if (deskId == INVALID_DESK_ID) return

        val parentTaskId = runningTaskInfo.lastParentTaskIdBeforePip
        if (parentTaskId != ActivityTaskManager.INVALID_TASK_ID) {
            logD(
                "maybeReparentTaskToDesk: Multi-activity PiP, unminimize parent task in Desk" +
                    " instead of moving PiP task to Desk"
            )
            unminimizeParentInDesk(wct, parentTaskId, deskId)
            return
        }

        if (!desktopRepository.isDeskActive(deskId)) {
            logD(
                "maybeReparentTaskToDesk: addDeskActivationChanges, taskId=%d deskId=%d, " +
@@ -141,6 +155,28 @@ class DesktopPipTransitionController(
        )
    }

    private fun unminimizeParentInDesk(
        wct: WindowContainerTransaction,
        parentTaskId: Int,
        deskId: Int,
    ) {
        val parentTask = shellTaskOrganizer.getRunningTaskInfo(parentTaskId)
        if (parentTask == null) {
            logW(
                "unminimizeParentInDesk: Failed to find RunningTaskInfo for parentTaskId %d",
                parentTaskId,
            )
            return
        }

        logD("unminimizeParentInDesk: parentTaskId=%d deskId=%d", parentTask.taskId, deskId)
        desktopTasksController.addMoveTaskToFrontChanges(
            wct = wct,
            deskId = deskId,
            taskInfo = parentTask,
        )
    }

    /**
     * This is called by [PipTransition#handleRequest] when a request for entering PiP is received.
     *
+44 −14
Original line number Diff line number Diff line
@@ -1245,11 +1245,21 @@ class DesktopTasksController(
                transitions.dispatchRequest(SYNTHETIC_TRANSITION, requestInfo, /* skip= */ null)
            wct.merge(requestRes.second, true)

            // In multi-activity case, we explicitly reorder the parent task to the back so that it
            // is not brought to the front and shown when the child task breaks off into PiP.
            if (taskInfo.numActivities > 1) {
            // In multi-activity case, we either explicitly minimize the parent task, or reorder the
            // parent task to the back so that it is not brought to the front and shown when the
            // child task breaks off into PiP.
            val isMultiActivityPip = taskInfo.numActivities > 1
            if (isMultiActivityPip) {
                if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
                    desksOrganizer.minimizeTask(
                        wct = wct,
                        deskId = checkNotNull(deskId) { "Expected non-null deskId" },
                        task = taskInfo,
                    )
                } else {
                    wct.reorder(taskInfo.token, /* onTop= */ false)
                }
            }

            // If the task minimizing to PiP is the last task, modify wct to perform Desktop cleanup
            var desktopExitRunnable: RunOnTransitStart? = null
@@ -1263,6 +1273,16 @@ class DesktopTasksController(
                    )
            }
            val transition = freeformTaskTransitionStarter.startPipTransition(wct)
            if (isMultiActivityPip) {
                desktopTasksLimiter.ifPresent {
                    it.addPendingMinimizeChange(
                        transition = transition,
                        displayId = displayId,
                        taskId = taskId,
                        minimizeReason = minimizeReason,
                    )
                }
            }
            desktopExitRunnable?.invoke(transition)
        } else {
            val willExitDesktop =
@@ -1562,12 +1582,31 @@ class DesktopTasksController(
    ) {
        val deskId = taskRepository.getDeskIdForTask(taskInfo.taskId)
        logV("moveTaskToFront taskId=%s deskId=%s", taskInfo.taskId, deskId)
        val wct = WindowContainerTransaction()
        addMoveTaskToFrontChanges(wct = wct, deskId = deskId, taskInfo = taskInfo)
        startLaunchTransition(
            transitionType = TRANSIT_TO_FRONT,
            wct = wct,
            launchingTaskId = taskInfo.taskId,
            remoteTransition = remoteTransition,
            deskId = deskId,
            displayId = taskInfo.displayId,
            unminimizeReason = unminimizeReason,
        )
    }

    /** Applies the necessary [wct] changes to move [taskInfo] to front. */
    fun addMoveTaskToFrontChanges(
        wct: WindowContainerTransaction,
        deskId: Int?,
        taskInfo: RunningTaskInfo,
    ) {
        logV("addMoveTaskToFrontChanges taskId=%s deskId=%s", taskInfo.taskId, deskId)
        // If a task is tiled, another task should be brought to foreground with it so let
        // tiling controller handle the request.
        if (snapEventHandler.moveTaskToFrontIfTiled(taskInfo)) {
            return
        }
        val wct = WindowContainerTransaction()
        if (deskId == null || !DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            // Not a desktop task, just move to the front.
            wct.reorder(taskInfo.token, /* onTop= */ true, /* includingParents= */ true)
@@ -1575,15 +1614,6 @@ class DesktopTasksController(
            // A desktop task with multiple desks enabled, reorder it within its desk.
            desksOrganizer.reorderTaskToFront(wct, deskId, taskInfo)
        }
        startLaunchTransition(
            transitionType = TRANSIT_TO_FRONT,
            wct = wct,
            launchingTaskId = taskInfo.taskId,
            remoteTransition = remoteTransition,
            deskId = deskId,
            displayId = taskInfo.displayId,
            unminimizeReason = unminimizeReason,
        )
    }

    /**
+33 −17
Original line number Diff line number Diff line
@@ -69,7 +69,10 @@ class DesktopPipTransitionControllerTest(flags: FlagsParameterization) : ShellTe

    private val transition = Binder()
    private val wct = WindowContainerTransaction()
    private val taskInfo = createFreeformTask()
    private val taskInfo =
        createFreeformTask().apply {
            lastParentTaskIdBeforePip = ActivityTaskManager.INVALID_TASK_ID
        }
    private val freeformParentTask =
        createFreeformTask().apply { lastNonFullscreenBounds = FREEFORM_BOUNDS }
    private val fullscreenParentTask =
@@ -84,8 +87,8 @@ class DesktopPipTransitionControllerTest(flags: FlagsParameterization) : ShellTe
        whenever(mockPipDesktopState.isDesktopWindowingPipEnabled()).thenReturn(true)
        whenever(mockPipDesktopState.isDisplayDesktopFirst(any())).thenReturn(false)
        whenever(mockPipDesktopState.isPipInDesktopMode()).thenReturn(true)
        whenever(mockPipDesktopState.isRecentsAnimating()).thenReturn(false)
        whenever(mockDesktopUserRepositories.getProfile(any())).thenReturn(mockDesktopRepository)
        whenever(mockDesktopRepository.isAnyDeskActive(any())).thenReturn(true)
        whenever(mockDesktopRepository.getActiveDeskId(any())).thenReturn(DESK_ID)
        whenever(mockShellTaskOrganizer.getRunningTaskInfo(taskInfo.taskId)).thenReturn(taskInfo)
        whenever(mockShellTaskOrganizer.getRunningTaskInfo(freeformParentTask.taskId))
@@ -165,20 +168,43 @@ class DesktopPipTransitionControllerTest(flags: FlagsParameterization) : ShellTe

    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    @Test
    fun maybeReparentTaskToDesk_noDeskActive_notDesktopFirstDisplay_noWctChanges() {
    fun maybeReparentTaskToDesk_recentsAnimating_noAddMoveToDeskTaskChanges() {
        whenever(mockPipDesktopState.isRecentsAnimating()).thenReturn(true)

        controller.maybeReparentTaskToDesk(wct, taskInfo.taskId)

        verify(mockDesktopTasksController, never())
            .addMoveToDeskTaskChanges(wct = wct, task = taskInfo, deskId = DESK_ID)
    }

    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    @Test
    fun maybeReparentTaskToDesk_multiActivity_addMoveTaskToFrontChanges() {
        val wct = WindowContainerTransaction()
        whenever(mockDesktopRepository.isAnyDeskActive(eq(taskInfo.displayId))).thenReturn(false)
        taskInfo.lastParentTaskIdBeforePip = freeformParentTask.taskId

        controller.maybeReparentTaskToDesk(wct, taskInfo.taskId)

        assertThat(wct.changes.isEmpty()).isTrue()
        verify(mockDesktopTasksController)
            .addMoveTaskToFrontChanges(wct = wct, deskId = DESK_ID, taskInfo = freeformParentTask)
    }

    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    @Test
    fun maybeReparentTaskToDesk_noDeskActive_noAddMoveToDeskTaskChanges() {
        val wct = WindowContainerTransaction()
        whenever(mockDesktopRepository.getActiveDeskId(any())).thenReturn(null)

        controller.maybeReparentTaskToDesk(wct, taskInfo.taskId)

        verify(mockDesktopTasksController, never())
            .addMoveToDeskTaskChanges(wct = wct, task = taskInfo, deskId = DESK_ID)
    }

    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    @Test
    fun maybeReparentTaskToDesk_deskActive_addMoveToDeskTaskChanges() {
        val wct = WindowContainerTransaction()
        whenever(mockDesktopRepository.isAnyDeskActive(eq(taskInfo.displayId))).thenReturn(true)

        controller.maybeReparentTaskToDesk(wct, taskInfo.taskId)

@@ -188,10 +214,9 @@ class DesktopPipTransitionControllerTest(flags: FlagsParameterization) : ShellTe

    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    @Test
    fun maybeReparentTaskToDesk_noDeskActive_desktopFirstDisplay_addDeskActivationChanges() {
    fun maybeReparentTaskToDesk_desktopFirstDisplay_addDeskActivationChanges() {
        val wct = WindowContainerTransaction()
        whenever(mockDesktopRepository.getActiveDeskId(any())).thenReturn(null)
        whenever(mockDesktopRepository.isAnyDeskActive(eq(taskInfo.displayId))).thenReturn(false)
        whenever(mockPipDesktopState.isDisplayDesktopFirst(any())).thenReturn(true)
        whenever(mockDesktopRepository.getDefaultDeskId(any())).thenReturn(DESK_ID)

@@ -208,15 +233,6 @@ class DesktopPipTransitionControllerTest(flags: FlagsParameterization) : ShellTe
            .addMoveToDeskTaskChanges(wct = wct, task = taskInfo, deskId = DESK_ID)
    }

    @Test
    fun handlePipTransition_noDeskActive_doesntPerformDesktopExitCleanup() {
        whenever(mockDesktopRepository.isAnyDeskActive(eq(taskInfo.displayId))).thenReturn(false)

        controller.handlePipTransition(wct, transition, taskInfo)

        verifyPerformDesktopExitCleanupAfterPip(isCalled = false)
    }

    @Test
    fun handlePipTransition_notLastTask_doesntPerformDesktopExitCleanup() {
        whenever(
+19 −0
Original line number Diff line number Diff line
@@ -4471,6 +4471,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PIP)
    @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    fun onPipTaskMinimize_multiActivity_reordersParentToBack() {
        val task = setUpPipTask(autoEnterEnabled = true).apply { numActivities = 2 }
        // Add a second task so that entering PiP does not trigger Desktop cleanup
@@ -4484,6 +4485,24 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        arg.lastValue.assertReorderAt(index = 0, task, toTop = false)
    }

    @Test
    @EnableFlags(
        Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PIP,
        Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
    )
    fun onPipTaskMinimize_multiActivity_minimizeParent() {
        val task = setUpPipTask(autoEnterEnabled = true).apply { numActivities = 2 }
        // Add a second task so that entering PiP does not trigger Desktop cleanup
        setUpFreeformTask(deskId = DEFAULT_DISPLAY)

        minimizePipTask(task)

        val arg = argumentCaptor<WindowContainerTransaction>()
        verify(freeformTaskTransitionStarter).startPipTransition(arg.capture())
        verify(desksOrganizer)
            .minimizeTask(wct = arg.lastValue, deskId = DEFAULT_DISPLAY, task = task)
    }

    @Test
    fun onDesktopWindowMinimize_singleActiveTask_noWallpaperActivityToken_doesntRemoveWallpaper() {
        val task = setUpFreeformTask(active = true)
Loading