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

Commit 8854b91f authored by Merissa Mitchell's avatar Merissa Mitchell
Browse files

[PiP on Desktop] Fix multi-activity PiP switching in and out of Desktop

When switching in and out of Desktop session, multi-activity PiP
expanding is misbehaving. This CL adds the following changes:
- If PiP is entered while in Desktop then expanded in fullscreen, the
  wct needs to be updated with addMoveToFullscreenChanges so that
Desktop cleanup and changes is performed
- If PiP is entered while in fullscreen then expanded in Desktop, the
  parent needs to be moved to the Desk. If no Desk is active, Desk
activation changes need to be added as well (only applicable for empty
desks scenario).

Bug: 423087090
Test: atest DesktopPipTransitionControllerTest
Test: atest WMShellUnitTests:com.android.wm.shell.pip2
Test: atest WMShellUnitTests:com.android.wm.shell.common.pip
Test: Manual - enter multi-activity PiP from fullscreen, enter Desktop
session then expand PiP. Verify PiP expands to Desktop task and Desktop
is WAI. Enter PiP via minimize, exit Desktop session then expand PiP.
Verify PiP expands to fullscreen.
Flag: com.android.window.flags.enable_desktop_windowing_pip

Change-Id: I9436e2dfd156cd440d93f8077a9b540047bb466a
parent 2cfb785d
Loading
Loading
Loading
Loading
+87 −24
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@

package com.android.wm.shell.desktopmode

import android.app.ActivityManager
import android.app.ActivityManager.RunningTaskInfo
import android.app.ActivityTaskManager
import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
@@ -71,6 +71,12 @@ class DesktopPipTransitionController(
            if (pipDesktopState.isPipInDesktopMode()) WINDOWING_MODE_FREEFORM
            else WINDOWING_MODE_FULLSCREEN

        logD(
            "maybeUpdateParentInWct: parentTaskId=%d parentWinMode=%d resolvedWinMode=%d",
            parentTask.taskId,
            parentTask.windowingMode,
            resolvedWinMode,
        )
        if (resolvedWinMode != parentTask.windowingMode) {
            wct.setWindowingMode(parentTask.token, resolvedWinMode)
            wct.setBounds(
@@ -78,6 +84,42 @@ class DesktopPipTransitionController(
                if (resolvedWinMode == WINDOWING_MODE_FREEFORM) defaultFreeformBounds else Rect(),
            )
        }
        if (resolvedWinMode == WINDOWING_MODE_FULLSCREEN) {
            maybeAddMoveToFullscreenChanges(wct, parentTask)
        }
    }

    /**
     * In multi-activity PiP case, if the task entering PiP was previously active in a Desk and is
     * now expanding to fullscreen, call [DesktopTasksController#addMoveToFullscreenChanges] for the
     * parent task to properly move the task to fullscreen.
     *
     * @param wct WindowContainerTransaction that will apply these changes
     * @param parentTask the multi-activity PiP parent
     */
    private fun maybeAddMoveToFullscreenChanges(
        wct: WindowContainerTransaction,
        parentTask: RunningTaskInfo,
    ) {
        val desktopRepository = desktopUserRepositories.getProfile(parentTask.userId)
        if (!desktopRepository.isActiveTask(parentTask.taskId)) {
            logW(
                "maybeAddMoveToFullscreenChanges: parentTask with id=%d is not active in any desk",
                parentTask.taskId,
            )
            return
        }

        logD(
            "maybeAddMoveToFullscreenChanges: addMoveToFullscreenChanges, taskId=%d displayId=%d",
            parentTask.taskId,
            parentTask.displayId,
        )
        desktopTasksController.addMoveToFullscreenChanges(
            wct = wct,
            taskInfo = parentTask,
            willExitDesktop = true,
        )
    }

    /**
@@ -118,58 +160,79 @@ class DesktopPipTransitionController(
        if (deskId == INVALID_DESK_ID) return

        val parentTaskId = runningTaskInfo.lastParentTaskIdBeforePip
        var parentTask: RunningTaskInfo? = null
        var shouldAddParentToDesk = false

        // If PiP is multi-activity, we should use the parent task for the rest of this method
        if (parentTaskId != ActivityTaskManager.INVALID_TASK_ID) {
            parentTask = shellTaskOrganizer.getRunningTaskInfo(parentTaskId)
            if (parentTask == null) {
                logW(
                    "maybeReparentTaskToDesk: Failed to find RunningTaskInfo for parentTaskId %d",
                    parentTaskId,
                )
                return
            }
            if (desktopRepository.isActiveTask(parentTaskId)) {
                logD(
                "maybeReparentTaskToDesk: Multi-activity PiP, unminimize parent task in Desk" +
                    " instead of moving PiP task to Desk"
                    "maybeReparentTaskToDesk: Multi-activity PiP with parent taskId=%d already " +
                        "in the Desk, move parent task to front",
                    parentTaskId,
                )
            unminimizeParentInDesk(wct, parentTaskId, deskId)
                moveParentTaskToFront(wct, parentTask, deskId)
                return
            } else {
                logD(
                    "maybeReparentTaskToDesk: Multi-activity PiP with parent taskId=%d not " +
                        "already in the Desk, should add parent to the desk",
                    parentTaskId,
                )
                shouldAddParentToDesk = true
            }
        }

        if (!desktopRepository.isDeskActive(deskId)) {
            logD(
                "maybeReparentTaskToDesk: addDeskActivationChanges, taskId=%d deskId=%d, " +
                    "displayId=%d",
                runningTaskInfo.taskId,
                if (shouldAddParentToDesk) parentTaskId else runningTaskInfo.taskId,
                deskId,
                displayId,
            )
            desktopTasksController.addDeskActivationChanges(
                deskId = deskId,
                wct = wct,
                newTask = runningTaskInfo,
                newTask = if (shouldAddParentToDesk) parentTask!! else runningTaskInfo,
                displayId = displayId,
            )
        }

        logD(
            "maybeReparentTaskToDesk: addMoveToDeskTaskChanges, taskId=%d deskId=%d",
            runningTaskInfo.taskId,
            if (shouldAddParentToDesk) parentTaskId else runningTaskInfo.taskId,
            deskId,
        )
        desktopTasksController.addMoveToDeskTaskChanges(
            wct = wct,
            task = runningTaskInfo,
            task = if (shouldAddParentToDesk) parentTask!! else runningTaskInfo,
            deskId = deskId,
        )
    }

    private fun unminimizeParentInDesk(
    /**
     * In multi-activity PiP case, call [DesktopTasksController#addMoveTaskToFrontChanges] to move
     * the parent task to front within the desk.
     *
     * @param wct WindowContainerTransaction that will apply these changes
     * @param parentTask the parent task
     * @param deskId desk id that the multi-activity PiP parent is in
     */
    private fun moveParentTaskToFront(
        wct: WindowContainerTransaction,
        parentTaskId: Int,
        parentTask: RunningTaskInfo,
        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)
        logD("moveParentTaskToFront: parentTaskId=%d deskId=%d", parentTask.taskId, deskId)
        desktopTasksController.addMoveTaskToFrontChanges(
            wct = wct,
            deskId = deskId,
@@ -187,7 +250,7 @@ class DesktopPipTransitionController(
    fun handlePipTransition(
        wct: WindowContainerTransaction,
        transition: IBinder,
        taskInfo: ActivityManager.RunningTaskInfo,
        taskInfo: RunningTaskInfo,
    ) {
        if (!pipDesktopState.isDesktopWindowingPipEnabled()) {
            return
+1 −1
Original line number Diff line number Diff line
@@ -3564,7 +3564,7 @@ class DesktopTasksController(
    }

    /** Applies the changes needed to enter fullscreen and clean up the desktop if needed. */
    private fun addMoveToFullscreenChanges(
    fun addMoveToFullscreenChanges(
        wct: WindowContainerTransaction,
        taskInfo: TaskInfo,
        willExitDesktop: Boolean,
+21 −5
Original line number Diff line number Diff line
@@ -174,14 +174,16 @@ class DesktopPipTransitionControllerTest(flags: FlagsParameterization) : ShellTe
        controller.maybeReparentTaskToDesk(wct, taskInfo.taskId)

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

    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    @Test
    fun maybeReparentTaskToDesk_multiActivity_addMoveTaskToFrontChanges() {
    fun maybeReparentTaskToDesk_multiActivity_parentInDesk_addMoveTaskToFrontChanges() {
        val wct = WindowContainerTransaction()
        taskInfo.lastParentTaskIdBeforePip = freeformParentTask.taskId
        val parentTaskId = freeformParentTask.taskId
        taskInfo.lastParentTaskIdBeforePip = parentTaskId
        whenever(mockDesktopRepository.isActiveTask(parentTaskId)).thenReturn(true)

        controller.maybeReparentTaskToDesk(wct, taskInfo.taskId)

@@ -189,6 +191,20 @@ class DesktopPipTransitionControllerTest(flags: FlagsParameterization) : ShellTe
            .addMoveTaskToFrontChanges(wct = wct, deskId = DESK_ID, taskInfo = freeformParentTask)
    }

    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    @Test
    fun maybeReparentTaskToDesk_multiActivity_parentNotInDesk_addMoveToDeskTaskChanges() {
        val wct = WindowContainerTransaction()
        val parentTaskId = freeformParentTask.taskId
        taskInfo.lastParentTaskIdBeforePip = parentTaskId
        whenever(mockDesktopRepository.isActiveTask(parentTaskId)).thenReturn(false)

        controller.maybeReparentTaskToDesk(wct, taskInfo.taskId)

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

    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    @Test
    fun maybeReparentTaskToDesk_noDeskActive_noAddMoveToDeskTaskChanges() {
@@ -198,7 +214,7 @@ class DesktopPipTransitionControllerTest(flags: FlagsParameterization) : ShellTe
        controller.maybeReparentTaskToDesk(wct, taskInfo.taskId)

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

    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
@@ -214,7 +230,7 @@ class DesktopPipTransitionControllerTest(flags: FlagsParameterization) : ShellTe

    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    @Test
    fun maybeReparentTaskToDesk_desktopFirstDisplay_addDeskActivationChanges() {
    fun maybeReparentTaskToDesk_noDeskActive_desktopFirstDisplay_addDeskActivationChanges() {
        val wct = WindowContainerTransaction()
        whenever(mockDesktopRepository.getActiveDeskId(any())).thenReturn(null)
        whenever(mockPipDesktopState.isDisplayDesktopFirst(any())).thenReturn(true)