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

Commit 84627d98 authored by Merissa Mitchell's avatar Merissa Mitchell
Browse files

[PIP on Desktop] Restore task to freeform bounds when exiting PiP.

Recall: http://recall/clips/47a38bbe-1ef7-469d-8afd-f9e4a6fadbe6

On Desktop Windowing, PiP should exit/expand to the windowing mode that
it entered PiP with. This CL adds handling for PiP to exit to freeform
windowing mode and bounds, when PiP is minimized either via user action
or task limit while in Desktop Windowing.

Bug: 376875483
Bug: 372170748
Test: atest PipTaskOrganizerTest DesktopTasksLimiterTest
DesktopRepositoryTest
Flag: com.android.window.flags.enable_desktop_windowing_pip

Change-Id: I13006f479868f731550b9c75d8f9927bda2592fe
parent 892faa99
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.wm.shell.dagger.pip;
import android.content.Context;
import android.os.Handler;

import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
@@ -41,6 +42,7 @@ import com.android.wm.shell.common.pip.PipUiEventLogger;
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.DesktopRepository;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipParamsChangedForwarder;
@@ -169,6 +171,8 @@ public abstract class Pip1Module {
            PipParamsChangedForwarder pipParamsChangedForwarder,
            Optional<SplitScreenController> splitScreenControllerOptional,
            Optional<PipPerfHintController> pipPerfHintControllerOptional,
            Optional<DesktopRepository> desktopRepositoryOptional,
            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
            DisplayController displayController,
            PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
            @ShellMainThread ShellExecutor mainExecutor) {
@@ -176,7 +180,8 @@ public abstract class Pip1Module {
                syncTransactionQueue, pipTransitionState, pipBoundsState, pipDisplayLayoutState,
                pipBoundsAlgorithm, menuPhoneController, pipAnimationController,
                pipSurfaceTransactionHelper, pipTransitionController, pipParamsChangedForwarder,
                splitScreenControllerOptional, pipPerfHintControllerOptional, displayController,
                splitScreenControllerOptional, pipPerfHintControllerOptional,
                desktopRepositoryOptional, rootTaskDisplayAreaOrganizer, displayController,
                pipUiEventLogger, shellTaskOrganizer, mainExecutor);
    }

+5 −2
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.os.SystemClock;

import androidx.annotation.NonNull;

import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
@@ -214,6 +215,7 @@ public abstract class TvPipModule {
            PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
            Optional<SplitScreenController> splitScreenControllerOptional,
            Optional<PipPerfHintController> pipPerfHintControllerOptional,
            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
            DisplayController displayController,
            PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
            @ShellMainThread ShellExecutor mainExecutor) {
@@ -221,8 +223,9 @@ public abstract class TvPipModule {
                syncTransactionQueue, pipTransitionState, tvPipBoundsState, pipDisplayLayoutState,
                tvPipBoundsAlgorithm, tvPipMenuController, pipAnimationController,
                pipSurfaceTransactionHelper, tvPipTransition, pipParamsChangedForwarder,
                splitScreenControllerOptional, pipPerfHintControllerOptional, displayController,
                pipUiEventLogger, shellTaskOrganizer, mainExecutor);
                splitScreenControllerOptional, pipPerfHintControllerOptional,
                rootTaskDisplayAreaOrganizer, displayController, pipUiEventLogger,
                shellTaskOrganizer, mainExecutor);
    }

    @WMSingleton
+11 −0
Original line number Diff line number Diff line
@@ -102,6 +102,9 @@ class DesktopRepository (
    /* Tracks last bounds of task before toggled to stable bounds. */
    private val boundsBeforeMaximizeByTaskId = SparseArray<Rect>()

    /* Tracks last bounds of task before it is minimized. */
    private val boundsBeforeMinimizeByTaskId = SparseArray<Rect>()

    /* Tracks last bounds of task before toggled to immersive state. */
    private val boundsBeforeFullImmersiveByTaskId = SparseArray<Rect>()

@@ -462,6 +465,14 @@ class DesktopRepository (
    fun saveBoundsBeforeMaximize(taskId: Int, bounds: Rect) =
        boundsBeforeMaximizeByTaskId.set(taskId, Rect(bounds))

    /** Removes and returns the bounds saved before minimizing the given task. */
    fun removeBoundsBeforeMinimize(taskId: Int): Rect? =
        boundsBeforeMinimizeByTaskId.removeReturnOld(taskId)

    /** Saves the bounds of the given task before minimizing. */
    fun saveBoundsBeforeMinimize(taskId: Int, bounds: Rect?) =
        boundsBeforeMinimizeByTaskId.set(taskId, Rect(bounds))

    /** Removes and returns the bounds saved before entering immersive with the given task. */
    fun removeBoundsBeforeFullImmersive(taskId: Int): Rect? =
        boundsBeforeFullImmersiveByTaskId.removeReturnOld(taskId)
+6 −0
Original line number Diff line number Diff line
@@ -92,6 +92,12 @@ class DesktopTasksLimiter (
            }
            taskToMinimize.transitionInfo = info
            activeTransitionTokensAndTasks[transition] = taskToMinimize

            // Save current bounds before minimizing in case we need to restore to it later.
            val boundsBeforeMinimize = info.changes.find { change ->
                change.taskInfo?.taskId == taskToMinimize.taskId }?.startAbsBounds
            taskRepository.saveBoundsBeforeMinimize(taskToMinimize.taskId, boundsBeforeMinimize)

            this@DesktopTasksLimiter.minimizeTask(
                    taskToMinimize.displayId, taskToMinimize.taskId)
        }
+43 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.wm.shell.pip;

import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -67,6 +68,7 @@ import android.view.Choreographer;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceControl;
import android.window.DisplayAreaInfo;
import android.window.TaskOrganizer;
import android.window.TaskSnapshot;
import android.window.WindowContainerToken;
@@ -74,7 +76,9 @@ import android.window.WindowContainerTransaction;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;
import com.android.window.flags.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ScreenshotUtils;
@@ -87,6 +91,7 @@ import com.android.wm.shell.common.pip.PipMenuController;
import com.android.wm.shell.common.pip.PipPerfHintController;
import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.desktopmode.DesktopRepository;
import com.android.wm.shell.pip.phone.PipMotionHelper;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.animation.Interpolators;
@@ -145,6 +150,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
    private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
    private final Optional<SplitScreenController> mSplitScreenOptional;
    @Nullable private final PipPerfHintController mPipPerfHintController;
    private final Optional<DesktopRepository> mDesktopRepositoryOptional;
    private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
    protected final ShellTaskOrganizer mTaskOrganizer;
    protected final ShellExecutor mMainExecutor;

@@ -388,6 +395,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
            @NonNull PipParamsChangedForwarder pipParamsChangedForwarder,
            Optional<SplitScreenController> splitScreenOptional,
            Optional<PipPerfHintController> pipPerfHintControllerOptional,
            Optional<DesktopRepository> desktopRepositoryOptional,
            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
            @NonNull DisplayController displayController,
            @NonNull PipUiEventLogger pipUiEventLogger,
            @NonNull ShellTaskOrganizer shellTaskOrganizer,
@@ -414,6 +423,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
                new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
        mSplitScreenOptional = splitScreenOptional;
        mPipPerfHintController = pipPerfHintControllerOptional.orElse(null);
        mDesktopRepositoryOptional = desktopRepositoryOptional;
        mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
        mTaskOrganizer = shellTaskOrganizer;
        mMainExecutor = mainExecutor;

@@ -741,10 +752,23 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
    }

    /** Returns the bounds to restore to when exiting PIP mode. */
    // TODO(b/377581840): Instead of manually tracking bounds, use bounds from Core.
    public Rect getExitDestinationBounds() {
        if (isPipLaunchedInDesktopMode()) {
            final Rect freeformBounds = mDesktopRepositoryOptional.get().removeBoundsBeforeMinimize(
                    mTaskInfo.taskId);
            return Objects.requireNonNullElseGet(freeformBounds, mPipBoundsState::getDisplayBounds);
        }
        return mPipBoundsState.getDisplayBounds();
    }

    /** Returns whether PiP was launched while in desktop mode. */
    // TODO(377581840): Update this check to include non-minimized cases, e.g. split to PiP etc.
    private boolean isPipLaunchedInDesktopMode() {
        return Flags.enableDesktopWindowingPip() && mDesktopRepositoryOptional.isPresent()
                && mDesktopRepositoryOptional.get().isMinimizedTask(mTaskInfo.taskId);
    }

    private void exitLaunchIntoPipTask(WindowContainerTransaction wct) {
        wct.startTask(mTaskInfo.launchIntoPipHostTaskId, null /* ActivityOptions */);
        mTaskOrganizer.applyTransaction(wct);
@@ -1808,7 +1832,25 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
     * and can be overridden to restore to an alternate windowing mode.
     */
    public int getOutPipWindowingMode() {
        // By default, simply reset the windowing mode to undefined.
        final DisplayAreaInfo tdaInfo = mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(
                mTaskInfo.displayId);

        // If PiP was launched while in desktop mode (we should return the task to freeform
        // windowing mode):
        // 1) If the display windowing mode is freeform, set windowing mode to undefined so it will
        //    resolve the windowing mode to the display's windowing mode.
        // 2) If the display windowing mode is not freeform, set windowing mode to freeform.
        if (tdaInfo != null && isPipLaunchedInDesktopMode()) {
            final int displayWindowingMode =
                    tdaInfo.configuration.windowConfiguration.getWindowingMode();
            if (displayWindowingMode == WINDOWING_MODE_FREEFORM) {
                return WINDOWING_MODE_UNDEFINED;
            } else {
                return WINDOWING_MODE_FREEFORM;
            }
        }

        // By default, or if the task is going to fullscreen, reset the windowing mode to undefined.
        return WINDOWING_MODE_UNDEFINED;
    }

Loading