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

Commit 9c003a1d authored by Hongwei Wang's avatar Hongwei Wang
Browse files

Add tabletop mode support to PiP2

Respect and respond to Tabletop / Flex mode change
- When Foldable in tabletop mode, defaults PiP position to the top-half
- When change Foldable to tabletop mode, moves PiP to top-half if
  applicable

Internally, it's implemented as KCA (Keep-Clear-Area).

Flag: com.android.wm.shell.enable_pip2
Bug: 411161949
Video: http://recall/-/aaaaaabFQoRHlzixHdtY/ejoA7C7s6Cwxfzt2LQQAPr
Test: Enter PiP while in Flex mode
Test: Enter Flex mode while PiP is present
Change-Id: I98a4b11bc29172a4217d691958447556753c7c82
parent c3708065
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -29,7 +29,9 @@ import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TabletopModeController;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.pip.PhonePipKeepClearAlgorithm;
import com.android.wm.shell.common.pip.PipAppOpsListener;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
@@ -138,6 +140,8 @@ public abstract class Pip2Module {
            PhonePipMenuController pipMenuController,
            PipUiEventLogger pipUiEventLogger,
            PipMediaController pipMediaController,
            TabletopModeController tabletopModeController,
            PhonePipKeepClearAlgorithm pipKeepClearAlgorithm,
            PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
            @ShellMainThread ShellExecutor mainExecutor) {
        if (!PipUtils.isPip2ExperimentEnabled()) {
@@ -148,8 +152,8 @@ public abstract class Pip2Module {
                    displayInsetsController, pipBoundsState, pipBoundsAlgorithm,
                    pipDisplayLayoutState, pipScheduler, taskStackListener, shellTaskOrganizer,
                    pipTransitionState, pipTouchHandler, pipAppOpsListener, pipMenuController,
                    pipUiEventLogger, pipMediaController, pipSurfaceTransactionHelper,
                    mainExecutor));
                    pipUiEventLogger, pipMediaController, tabletopModeController,
                    pipKeepClearAlgorithm, pipSurfaceTransactionHelper, mainExecutor));
        }
    }

+57 −2
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.Log;
@@ -56,6 +57,7 @@ import com.android.wm.shell.common.NavigationBarsListener;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SingleInstanceRemoteListener;
import com.android.wm.shell.common.TabletopModeController;
import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.pip.IPip;
@@ -64,6 +66,7 @@ import com.android.wm.shell.common.pip.PipAppOpsListener;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipDisplayLayoutState;
import com.android.wm.shell.common.pip.PipKeepClearAlgorithmInterface;
import com.android.wm.shell.common.pip.PipMediaController;
import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.PipUtils;
@@ -108,6 +111,8 @@ public class PipController implements ConfigurationChangeListener,
    private final PipTouchHandler mPipTouchHandler;
    private final PipAppOpsListener mPipAppOpsListener;
    private final PhonePipMenuController mPipMenuController;
    private final TabletopModeController mTabletopModeController;
    private final PipKeepClearAlgorithmInterface mPipKeepClearAlgorithm;
    private final PipUiEventLogger mPipUiEventLogger;
    private final ShellExecutor mMainExecutor;
    private final PipImpl mImpl;
@@ -161,6 +166,8 @@ public class PipController implements ConfigurationChangeListener,
            PhonePipMenuController pipMenuController,
            PipUiEventLogger pipUiEventLogger,
            PipMediaController pipMediaController,
            TabletopModeController tabletopModeController,
            PipKeepClearAlgorithmInterface pipKeepClearAlgorithm,
            PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
            ShellExecutor mainExecutor) {
        mContext = context;
@@ -181,6 +188,8 @@ public class PipController implements ConfigurationChangeListener,
        mPipMenuController = pipMenuController;
        mPipUiEventLogger = pipUiEventLogger;
        mMediaController = pipMediaController;
        mTabletopModeController = tabletopModeController;
        mPipKeepClearAlgorithm = pipKeepClearAlgorithm;
        mPipSurfaceTransactionHelper = pipSurfaceTransactionHelper;
        mMainExecutor = mainExecutor;
        mImpl = new PipImpl();
@@ -211,6 +220,8 @@ public class PipController implements ConfigurationChangeListener,
            PhonePipMenuController pipMenuController,
            PipUiEventLogger pipUiEventLogger,
            PipMediaController pipMediaController,
            TabletopModeController tabletopModeController,
            PipKeepClearAlgorithmInterface pipKeepClearAlgorithm,
            PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
            ShellExecutor mainExecutor) {
        if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
@@ -222,8 +233,8 @@ public class PipController implements ConfigurationChangeListener,
                displayController, displayInsetsController, pipBoundsState, pipBoundsAlgorithm,
                pipDisplayLayoutState, pipScheduler, taskStackListener, shellTaskOrganizer,
                pipTransitionState, pipTouchHandler, pipAppOpsListener, pipMenuController,
                pipUiEventLogger, pipMediaController, pipSurfaceTransactionHelper,
                mainExecutor);
                pipUiEventLogger, pipMediaController, tabletopModeController,
                pipKeepClearAlgorithm, pipSurfaceTransactionHelper, mainExecutor);
    }

    public PipImpl getPipImpl() {
@@ -276,6 +287,50 @@ public class PipController implements ConfigurationChangeListener,
            }
        });

        mTabletopModeController.registerOnTabletopModeChangedListener((isInTabletopMode) -> {
            if (!isInTabletopMode) {
                mPipBoundsState.setNamedUnrestrictedKeepClearArea(
                        PipBoundsState.NAMED_KCA_TABLETOP_MODE, null);
                return;
            }

            // To prepare for the entry bounds.
            final Rect displayBounds = mPipBoundsState.getDisplayBounds();
            if (mTabletopModeController.getPreferredHalfInTabletopMode()
                    == TabletopModeController.PREFERRED_TABLETOP_HALF_TOP) {
                // Prefer top, avoid the bottom half of the display.
                mPipBoundsState.setNamedUnrestrictedKeepClearArea(
                        PipBoundsState.NAMED_KCA_TABLETOP_MODE, new Rect(
                                displayBounds.left, displayBounds.centerY(),
                                displayBounds.right, displayBounds.bottom));
            } else {
                // Prefer bottom, avoid the top half of the display.
                mPipBoundsState.setNamedUnrestrictedKeepClearArea(
                        PipBoundsState.NAMED_KCA_TABLETOP_MODE, new Rect(
                                displayBounds.left, displayBounds.top,
                                displayBounds.right, displayBounds.centerY()));
            }

            // Try to move the PiP window if we have entered PiP mode.
            if (mPipTransitionState.isInPip()) {
                final Rect pipBounds = mPipBoundsState.getBounds();
                final Point edgeInsets = mPipDisplayLayoutState.getScreenEdgeInsets();
                if ((pipBounds.height() + 2 * edgeInsets.y) > (displayBounds.height() / 2)) {
                    // PiP bounds is too big to fit either half, bail early.
                    return;
                }
                Rect destBounds = mPipKeepClearAlgorithm.adjust(mPipBoundsState,
                        mPipBoundsAlgorithm);
                // only move if the bounds are actually different
                if (!destBounds.equals(mPipBoundsState.getBounds())) {
                    ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                            "Move PiP from %s to %s on tabletop mode change",
                            mPipBoundsState.getBounds(), destBounds);
                    mPipTouchHandler.getMotionHelper().moveToBounds(destBounds);
                }
            }
        });

        mPipAppOpsListener.setCallback(mPipTouchHandler.getMotionHelper());
    }