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

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

Merge "[PiP2 on Desktop] Don't exit Desktop Mode when PiP is active." into main

parents 1faa6dfb f4ae6bf4
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ import com.android.wm.shell.compatui.impl.DefaultComponentIdGenerator;
import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.desktopmode.DesktopUserRepositories;
import com.android.wm.shell.desktopmode.desktopwallpaperactivity.DesktopWallpaperActivityTokenProvider;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
import com.android.wm.shell.displayareahelper.DisplayAreaHelperController;
import com.android.wm.shell.freeform.FreeformComponents;
@@ -1031,6 +1032,24 @@ public abstract class WMShellBaseModule {
        });
    }

    @WMSingleton
    @Provides
    static DesktopWallpaperActivityTokenProvider provideDesktopWallpaperActivityTokenProvider() {
        return new DesktopWallpaperActivityTokenProvider();
    }

    @WMSingleton
    @Provides
    static Optional<DesktopWallpaperActivityTokenProvider>
            provideOptionalDesktopWallpaperActivityTokenProvider(
            Context context,
            DesktopWallpaperActivityTokenProvider desktopWallpaperActivityTokenProvider) {
        if (DesktopModeStatus.canEnterDesktopMode(context)) {
            return Optional.of(desktopWallpaperActivityTokenProvider);
        }
        return Optional.empty();
    }

    //
    // Task Stack
    //
+0 −6
Original line number Diff line number Diff line
@@ -1312,12 +1312,6 @@ public abstract class WMShellModule {
        return new DesktopModeUiEventLogger(uiEventLogger, packageManager);
    }

    @WMSingleton
    @Provides
    static DesktopWallpaperActivityTokenProvider provideDesktopWallpaperActivityTokenProvider() {
        return new DesktopWallpaperActivityTokenProvider();
    }

    //
    // Drag and drop
    //
+10 −3
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import com.android.wm.shell.common.pip.SizeSpecSource;
import com.android.wm.shell.dagger.WMShellBaseModule;
import com.android.wm.shell.dagger.WMSingleton;
import com.android.wm.shell.desktopmode.DesktopUserRepositories;
import com.android.wm.shell.desktopmode.desktopwallpaperactivity.DesktopWallpaperActivityTokenProvider;
import com.android.wm.shell.pip2.phone.PhonePipMenuController;
import com.android.wm.shell.pip2.phone.PipController;
import com.android.wm.shell.pip2.phone.PipMotionHelper;
@@ -82,11 +83,14 @@ public abstract class Pip2Module {
            @NonNull PipTransitionState pipStackListenerController,
            @NonNull PipDisplayLayoutState pipDisplayLayoutState,
            @NonNull PipUiStateChangeController pipUiStateChangeController,
            Optional<DesktopUserRepositories> desktopUserRepositoriesOptional) {
            Optional<DesktopUserRepositories> desktopUserRepositoriesOptional,
            Optional<DesktopWallpaperActivityTokenProvider>
                    desktopWallpaperActivityTokenProviderOptional) {
        return new PipTransition(context, shellInit, shellTaskOrganizer, transitions,
                pipBoundsState, null, pipBoundsAlgorithm, pipTaskListener,
                pipScheduler, pipStackListenerController, pipDisplayLayoutState,
                pipUiStateChangeController, desktopUserRepositoriesOptional);
                pipUiStateChangeController, desktopUserRepositoriesOptional,
                desktopWallpaperActivityTokenProviderOptional);
    }

    @WMSingleton
@@ -138,9 +142,12 @@ public abstract class Pip2Module {
            @ShellMainThread ShellExecutor mainExecutor,
            PipTransitionState pipTransitionState,
            Optional<DesktopUserRepositories> desktopUserRepositoriesOptional,
            Optional<DesktopWallpaperActivityTokenProvider>
                    desktopWallpaperActivityTokenProviderOptional,
            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
        return new PipScheduler(context, pipBoundsState, mainExecutor, pipTransitionState,
                desktopUserRepositoriesOptional, rootTaskDisplayAreaOrganizer);
                desktopUserRepositoriesOptional, desktopWallpaperActivityTokenProviderOptional,
                rootTaskDisplayAreaOrganizer);
    }

    @WMSingleton
+67 −1
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import androidx.core.util.forEach
import androidx.core.util.keyIterator
import androidx.core.util.valueIterator
import com.android.internal.protolog.ProtoLog
import com.android.window.flags.Flags
import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
import com.android.wm.shell.shared.annotations.ShellMainThread
@@ -56,6 +57,10 @@ class DesktopRepository(
     * @property topTransparentFullscreenTaskId the task id of any current top transparent
     *   fullscreen task launched on top of Desktop Mode. Cleared when the transparent task is
     *   closed or sent to back. (top is at index 0).
     * @property pipTaskId the task id of PiP task entered while in Desktop Mode.
     * @property pipShouldKeepDesktopActive whether an active PiP window should keep the Desktop
     *   Mode session active. Only false when we are explicitly exiting Desktop Mode (via user
     *   action) while there is an active PiP window.
     */
    private data class DesktopTaskData(
        val activeTasks: ArraySet<Int> = ArraySet(),
@@ -66,6 +71,8 @@ class DesktopRepository(
        val freeformTasksInZOrder: ArrayList<Int> = ArrayList(),
        var fullImmersiveTaskId: Int? = null,
        var topTransparentFullscreenTaskId: Int? = null,
        var pipTaskId: Int? = null,
        var pipShouldKeepDesktopActive: Boolean = true,
    ) {
        fun deepCopy(): DesktopTaskData =
            DesktopTaskData(
@@ -76,6 +83,8 @@ class DesktopRepository(
                freeformTasksInZOrder = ArrayList(freeformTasksInZOrder),
                fullImmersiveTaskId = fullImmersiveTaskId,
                topTransparentFullscreenTaskId = topTransparentFullscreenTaskId,
                pipTaskId = pipTaskId,
                pipShouldKeepDesktopActive = pipShouldKeepDesktopActive,
            )

        fun clear() {
@@ -86,6 +95,8 @@ class DesktopRepository(
            freeformTasksInZOrder.clear()
            fullImmersiveTaskId = null
            topTransparentFullscreenTaskId = null
            pipTaskId = null
            pipShouldKeepDesktopActive = true
        }
    }

@@ -104,6 +115,9 @@ class DesktopRepository(
    /* Tracks last bounds of task before toggled to immersive state. */
    private val boundsBeforeFullImmersiveByTaskId = SparseArray<Rect>()

    /* Callback for when a pending PiP transition has been aborted. */
    private var onPipAbortedCallback: ((Int, Int) -> Unit)? = null

    private var desktopGestureExclusionListener: Consumer<Region>? = null
    private var desktopGestureExclusionExecutor: Executor? = null

@@ -302,6 +316,54 @@ class DesktopRepository(
        }
    }

    /** Set whether the given task is the Desktop-entered PiP task in this display. */
    fun setTaskInPip(displayId: Int, taskId: Int, enterPip: Boolean) {
        val desktopData = desktopTaskDataByDisplayId.getOrCreate(displayId)
        if (enterPip) {
            desktopData.pipTaskId = taskId
            desktopData.pipShouldKeepDesktopActive = true
        } else {
            desktopData.pipTaskId =
                if (desktopData.pipTaskId == taskId) null
                else {
                    logW(
                        "setTaskInPip: taskId=$taskId did not match saved taskId=${desktopData.pipTaskId}"
                    )
                    desktopData.pipTaskId
                }
        }
        notifyVisibleTaskListeners(displayId, getVisibleTaskCount(displayId))
    }

    /** Returns whether there is a PiP that was entered/minimized from Desktop in this display. */
    fun isMinimizedPipPresentInDisplay(displayId: Int): Boolean =
        desktopTaskDataByDisplayId.getOrCreate(displayId).pipTaskId != null

    /** Returns whether the given task is the Desktop-entered PiP task in this display. */
    fun isTaskMinimizedPipInDisplay(displayId: Int, taskId: Int): Boolean =
        desktopTaskDataByDisplayId.getOrCreate(displayId).pipTaskId == taskId

    /** Returns whether Desktop session should be active in this display due to active PiP. */
    fun shouldDesktopBeActiveForPip(displayId: Int): Boolean =
        Flags.enableDesktopWindowingPip() &&
            isMinimizedPipPresentInDisplay(displayId) &&
            desktopTaskDataByDisplayId.getOrCreate(displayId).pipShouldKeepDesktopActive

    /** Saves whether a PiP window should keep Desktop session active in this display. */
    fun setPipShouldKeepDesktopActive(displayId: Int, keepActive: Boolean) {
        desktopTaskDataByDisplayId.getOrCreate(displayId).pipShouldKeepDesktopActive = keepActive
    }

    /** Saves callback to handle a pending PiP transition being aborted. */
    fun setOnPipAbortedCallback(callbackIfPipAborted: ((Int, Int) -> Unit)?) {
        onPipAbortedCallback = callbackIfPipAborted
    }

    /** Invokes callback to handle a pending PiP transition with the given task id being aborted. */
    fun onPipAborted(displayId: Int, pipTaskId: Int) {
        onPipAbortedCallback?.invoke(displayId, pipTaskId)
    }

    /** Set whether the given task is the full-immersive task in this display. */
    fun setTaskInFullImmersiveState(displayId: Int, taskId: Int, immersive: Boolean) {
        val desktopData = desktopTaskDataByDisplayId.getOrCreate(displayId)
@@ -338,8 +400,12 @@ class DesktopRepository(
    }

    private fun notifyVisibleTaskListeners(displayId: Int, visibleTasksCount: Int) {
        val visibleAndPipTasksCount =
            if (shouldDesktopBeActiveForPip(displayId)) visibleTasksCount + 1 else visibleTasksCount
        visibleTasksListeners.forEach { (listener, executor) ->
            executor.execute { listener.onTasksVisibilityChanged(displayId, visibleTasksCount) }
            executor.execute {
                listener.onTasksVisibilityChanged(displayId, visibleAndPipTasksCount)
            }
        }
    }

+56 −29
Original line number Diff line number Diff line
@@ -225,7 +225,6 @@ class DesktopTasksController(
    // Launch cookie used to identify a drag and drop transition to fullscreen after it has begun.
    // Used to prevent handleRequest from moving the new fullscreen task to freeform.
    private var dragAndDropFullscreenCookie: Binder? = null
    private var pendingPipTransitionAndTask: Pair<IBinder, Int>? = null

    init {
        desktopMode = DesktopModeImpl()
@@ -321,18 +320,29 @@ class DesktopTasksController(
    fun visibleTaskCount(displayId: Int): Int = taskRepository.getVisibleTaskCount(displayId)

    /**
     * Returns true if any freeform tasks are visible or if a transparent fullscreen task exists on
     * top in Desktop Mode.
     * Returns true if any of the following is true:
     * - Any freeform tasks are visible
     * - A transparent fullscreen task exists on top in Desktop Mode
     * - PiP on Desktop Windowing is enabled, there is an active PiP window and the desktop
     *   wallpaper is visible.
     */
    fun isDesktopModeShowing(displayId: Int): Boolean {
        val hasVisibleTasks = visibleTaskCount(displayId) > 0
        val hasTopTransparentFullscreenTask =
            taskRepository.getTopTransparentFullscreenTaskId(displayId) != null
        val hasMinimizedPip =
            Flags.enableDesktopWindowingPip() &&
                taskRepository.isMinimizedPipPresentInDisplay(displayId) &&
                desktopWallpaperActivityTokenProvider.isWallpaperActivityVisible(displayId)
        if (
            DesktopModeFlags.INCLUDE_TOP_TRANSPARENT_FULLSCREEN_TASK_IN_DESKTOP_HEURISTIC
                .isTrue() && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODALS_POLICY.isTrue()
        ) {
            return visibleTaskCount(displayId) > 0 ||
                taskRepository.getTopTransparentFullscreenTaskId(displayId) != null
            return hasVisibleTasks || hasTopTransparentFullscreenTask || hasMinimizedPip
        } else if (Flags.enableDesktopWindowingPip()) {
            return hasVisibleTasks || hasMinimizedPip
        }
        return visibleTaskCount(displayId) > 0
        return hasVisibleTasks
    }

    /** Moves focused task to desktop mode for given [displayId]. */
@@ -592,7 +602,7 @@ class DesktopTasksController(
    ): ((IBinder) -> Unit)? {
        val taskId = taskInfo.taskId
        desktopTilingDecorViewModel.removeTaskIfTiled(displayId, taskId)
        performDesktopExitCleanupIfNeeded(taskId, displayId, wct)
        performDesktopExitCleanupIfNeeded(taskId, displayId, wct, forceToFullscreen = false)
        taskRepository.addClosingTask(displayId, taskId)
        taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(
            doesAnyTaskRequireTaskbarRounding(displayId, taskId)
@@ -624,8 +634,12 @@ class DesktopTasksController(
                )
            val requestRes = transitions.dispatchRequest(Binder(), requestInfo, /* skip= */ null)
            wct.merge(requestRes.second, true)
            pendingPipTransitionAndTask =
                freeformTaskTransitionStarter.startPipTransition(wct) to taskInfo.taskId
            freeformTaskTransitionStarter.startPipTransition(wct)
            taskRepository.setTaskInPip(taskInfo.displayId, taskInfo.taskId, enterPip = true)
            taskRepository.setOnPipAbortedCallback { displayId, taskId ->
                minimizeTaskInner(shellTaskOrganizer.getRunningTaskInfo(taskId)!!)
                taskRepository.setTaskInPip(displayId, taskId, enterPip = false)
            }
            return
        }

@@ -636,7 +650,7 @@ class DesktopTasksController(
        val taskId = taskInfo.taskId
        val displayId = taskInfo.displayId
        val wct = WindowContainerTransaction()
        performDesktopExitCleanupIfNeeded(taskId, displayId, wct)
        performDesktopExitCleanupIfNeeded(taskId, displayId, wct, forceToFullscreen = false)
        // Notify immersive handler as it might need to exit immersive state.
        val exitResult =
            desktopImmersiveController.exitImmersiveIfApplicable(
@@ -898,7 +912,12 @@ class DesktopTasksController(
        }

        if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
            performDesktopExitCleanupIfNeeded(task.taskId, task.displayId, wct)
            performDesktopExitCleanupIfNeeded(
                task.taskId,
                task.displayId,
                wct,
                forceToFullscreen = false,
            )
        }

        transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null)
@@ -1414,7 +1433,9 @@ class DesktopTasksController(
        taskId: Int,
        displayId: Int,
        wct: WindowContainerTransaction,
        forceToFullscreen: Boolean,
    ) {
        taskRepository.setPipShouldKeepDesktopActive(displayId, !forceToFullscreen)
        if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
            if (!taskRepository.isOnlyVisibleNonClosingTask(taskId, displayId)) {
                return
@@ -1422,6 +1443,12 @@ class DesktopTasksController(
            if (displayId != DEFAULT_DISPLAY) {
                return
            }
        } else if (
            Flags.enableDesktopWindowingPip() &&
                taskRepository.isMinimizedPipPresentInDisplay(displayId) &&
                !forceToFullscreen
        ) {
            return
        } else {
            if (!taskRepository.isOnlyVisibleNonClosingTask(taskId)) {
                return
@@ -1462,21 +1489,6 @@ class DesktopTasksController(
        return false
    }

    override fun onTransitionConsumed(
        transition: IBinder,
        aborted: Boolean,
        finishT: Transaction?,
    ) {
        pendingPipTransitionAndTask?.let { (pipTransition, taskId) ->
            if (transition == pipTransition) {
                if (aborted) {
                    shellTaskOrganizer.getRunningTaskInfo(taskId)?.let { minimizeTaskInner(it) }
                }
                pendingPipTransitionAndTask = null
            }
        }
    }

    override fun handleRequest(
        transition: IBinder,
        request: TransitionRequestInfo,
@@ -1926,7 +1938,12 @@ class DesktopTasksController(
        if (!isDesktopModeShowing(task.displayId)) return null

        val wct = WindowContainerTransaction()
        performDesktopExitCleanupIfNeeded(task.taskId, task.displayId, wct)
        performDesktopExitCleanupIfNeeded(
            task.taskId,
            task.displayId,
            wct,
            forceToFullscreen = false,
        )

        if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue()) {
            taskRepository.addClosingTask(task.displayId, task.taskId)
@@ -2053,7 +2070,12 @@ class DesktopTasksController(
            wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi())
        }

        performDesktopExitCleanupIfNeeded(taskInfo.taskId, taskInfo.displayId, wct)
        performDesktopExitCleanupIfNeeded(
            taskInfo.taskId,
            taskInfo.displayId,
            wct,
            forceToFullscreen = true,
        )
    }

    private fun cascadeWindow(bounds: Rect, displayLayout: DisplayLayout, displayId: Int) {
@@ -2087,7 +2109,12 @@ class DesktopTasksController(
        // want it overridden in multi-window.
        wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi())

        performDesktopExitCleanupIfNeeded(taskInfo.taskId, taskInfo.displayId, wct)
        performDesktopExitCleanupIfNeeded(
            taskInfo.taskId,
            taskInfo.displayId,
            wct,
            forceToFullscreen = false,
        )
    }

    /** Returns the ID of the Task that will be minimized, or null if no task will be minimized. */
Loading