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

Commit 7ce23bf4 authored by Vania Desmonda's avatar Vania Desmonda
Browse files

Make PiP snap to the target display upon releasing cross-displays drag.

Demo: https://drive.google.com/file/d/1Me14S8N0Vx59Cjslx27_i9PDF14Ah4In/view?usp=sharing

Bug: 383403514
Test: manual
Flag: com.android.window.flags.enable_dragging_pip_across_displays
Change-Id: Iae585a76dc02004a230c281f08b9bc0ed14c45e2
parent c582dc6a
Loading
Loading
Loading
Loading
+40 −4
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.view.Gravity;

import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.protolog.ShellProtoLogGroup;

import java.io.PrintWriter;
@@ -337,6 +338,14 @@ public class PipBoundsAlgorithm {
        outRect.set(mPipDisplayLayoutState.getInsetBounds());
    }

    /**
     * Populates the bounds on the screen that the PIP can be visible on a given
     * {@param displayLayout}.
     */
    public void getInsetBounds(Rect outRect, DisplayLayout displayLayout) {
        outRect.set(mPipDisplayLayoutState.getInsetBounds(displayLayout));
    }

    private int getOverrideMinEdgeSize() {
        return mSizeSpecSource.getOverrideMinEdgeSize();
    }
@@ -346,7 +355,8 @@ public class PipBoundsAlgorithm {
     *         controller.
     */
    public Rect getMovementBounds(Rect stackBounds) {
        return getMovementBounds(stackBounds, true /* adjustForIme */);
        return getMovementBounds(stackBounds, true /* adjustForIme */,
                mPipDisplayLayoutState.getDisplayLayout() /* displayLayout */);
    }

    /**
@@ -354,8 +364,27 @@ public class PipBoundsAlgorithm {
     *         controller.
     */
    public Rect getMovementBounds(Rect stackBounds, boolean adjustForIme) {
        return getMovementBounds(stackBounds, adjustForIme,
                mPipDisplayLayoutState.getDisplayLayout() /* displayLayout */);
    }

    /**
     * @return the movement bounds for the given stackBounds on a given displayLayout and the
     *         current state of the controller.
     */
    public Rect getMovementBounds(Rect stackBounds, DisplayLayout displayLayout) {
        return getMovementBounds(stackBounds, true /* adjustForIme */, displayLayout);
    }

    /**
     * @return the movement bounds for the given stackBounds on a given displayLayout and the
     *         current state of the controller.
     */
    public Rect getMovementBounds(Rect stackBounds, boolean adjustForIme,
            DisplayLayout displayLayout) {
        // TODO(b/415107549): Refactor and reduce the number of `getMovementBounds()` overrides
        final Rect movementBounds = new Rect();
        getInsetBounds(movementBounds);
        getInsetBounds(movementBounds, displayLayout);

        // Apply the movement bounds adjustments based on the current state.
        getMovementBounds(stackBounds, movementBounds, movementBounds,
@@ -464,8 +493,15 @@ public class PipBoundsAlgorithm {
     * Snaps PiP bounds to its movement bounds.
     */
    public void snapToMovementBoundsEdge(Rect bounds) {
        // Get the current movement bounds
        final Rect movementBounds = getMovementBounds(bounds);
        snapToMovementBoundsEdge(bounds, mPipDisplayLayoutState.getDisplayLayout());
    }

    /**
     * Snaps PiP bounds to its movement bounds on a given {@param displayLayout}.
     */
    public void snapToMovementBoundsEdge(Rect bounds, DisplayLayout displayLayout) {
        // Get the movement bounds of the display
        final Rect movementBounds = getMovementBounds(bounds, displayLayout);
        final int leftEdge = bounds.left;

        final int fromLeft = Math.abs(leftEdge - movementBounds.left);
+10 −3
Original line number Diff line number Diff line
@@ -89,14 +89,21 @@ public class PipDisplayLayoutState {
     * Returns the inset bounds the PIP window can be visible in.
     */
    public Rect getInsetBounds() {
        return getInsetBounds(getDisplayLayout());
    }

    /**
     * Returns the inset bounds the PIP window can be visible on a given {@param displayLayout}
     */
    public Rect getInsetBounds(DisplayLayout displayLayout) {
        final Rect insetBounds = new Rect();
        final Rect stableInsets = getDisplayLayout().stableInsets();
        final Rect stableInsets = displayLayout.stableInsets();
        final Point screenEdgeInsets = getScreenEdgeInsets();
        final int left = max(stableInsets.left, mNavigationBarsInsets.left) + screenEdgeInsets.x;
        final int top = max(stableInsets.top, mNavigationBarsInsets.top) + screenEdgeInsets.y;
        final int right = getDisplayLayout().width()
        final int right = displayLayout.width()
                - max(stableInsets.right, mNavigationBarsInsets.right) - screenEdgeInsets.x;
        final int bottom = getDisplayLayout().height()
        final int bottom = displayLayout.height()
                - max(stableInsets.bottom, mNavigationBarsInsets.bottom) - screenEdgeInsets.y;
        insetBounds.set(left, top, right, bottom);
        return insetBounds;
+8 −4
Original line number Diff line number Diff line
@@ -69,7 +69,7 @@ public class PipDisplayTransferHandler implements
    @VisibleForTesting boolean mWaitingForDisplayTransfer;
    @VisibleForTesting
    ArrayMap<Integer, SurfaceControl> mOnDragMirrorPerDisplayId = new ArrayMap<>();
    private int mTargetDisplayId;
    @VisibleForTesting int mTargetDisplayId;
    private PipResizeAnimatorSupplier mPipResizeAnimatorSupplier;

    public PipDisplayTransferHandler(Context context, PipTransitionState pipTransitionState,
@@ -145,7 +145,12 @@ public class PipDisplayTransferHandler implements
                        PIP_DESTINATION_BOUNDS, Rect.class);

                Rect finalBounds = new Rect(pipBounds);
                mPipBoundsAlgorithm.snapToMovementBoundsEdge(finalBounds);
                final DisplayLayout targetDisplayLayout = mDisplayController.getDisplayLayout(
                        mTargetDisplayId);
                // Snap to movement bounds edge of the target display ID on drag release.
                // The target display layout needs to be supplied since this happens before the PiP
                // is released and the display ID and layout are updated.
                mPipBoundsAlgorithm.snapToMovementBoundsEdge(finalBounds, targetDisplayLayout);

                mPipSurfaceTransactionHelper.round(startTx, pipLeash, true).shadow(startTx,
                        pipLeash, true /* applyShadowRadius */);
@@ -156,8 +161,7 @@ public class PipDisplayTransferHandler implements
                mPipTransitionState.setState(PipTransitionState.EXITED_PIP);

                mPipDisplayLayoutState.setDisplayId(mTargetDisplayId);
                mPipDisplayLayoutState.setDisplayLayout(mDisplayController.getDisplayLayout(
                        mTargetDisplayId));
                mPipDisplayLayoutState.setDisplayLayout(targetDisplayLayout);
                mPipTransitionState.setPinnedTaskLeash(pipLeash);
                mPipTransitionState.setPipTaskInfo(taskInfo);

+38 −0
Original line number Diff line number Diff line
@@ -511,6 +511,44 @@ public class PipBoundsAlgorithmTest extends ShellTestCase {
                bounds.top, originalBounds.top);
    }

    @Test
    public void snapToMovementBoundsEdge_customDisplayLayout_boundsSnappedToLeft() {
        final DisplayInfo displayInfo = new DisplayInfo();
        displayInfo.displayId = 2;
        displayInfo.logicalWidth = 500;
        displayInfo.logicalHeight = 500;
        final DisplayLayout displayLayout = new DisplayLayout(displayInfo,
                mContext.getResources(), true, true);
        final Rect bounds = new Rect(100, 100, 200, 200);
        final Rect originalBounds = new Rect(bounds);

        mPipBoundsAlgorithm.snapToMovementBoundsEdge(bounds, displayLayout);

        assertEquals("Bounds are snapped to left edge of movement bounds of custom display",
                bounds.left, mPipDisplayLayoutState.getInsetBounds(displayLayout).left);
        assertEquals("Bounds top edge is unchanged",
                bounds.top, originalBounds.top);
    }

    @Test
    public void snapToMovementBoundsEdge_customDisplayLayout_boundsSnappedToRight() {
        final DisplayInfo displayInfo = new DisplayInfo();
        displayInfo.displayId = 2;
        displayInfo.logicalWidth = 500;
        displayInfo.logicalHeight = 500;
        final DisplayLayout displayLayout = new DisplayLayout(displayInfo,
                mContext.getResources(), true, true);
        final Rect bounds = new Rect(300, 100, 400, 200);
        final Rect originalBounds = new Rect(bounds);

        mPipBoundsAlgorithm.snapToMovementBoundsEdge(bounds, displayLayout);

        assertEquals("Bounds are snapped to right edge of movement bounds of custom display",
                bounds.right, mPipDisplayLayoutState.getInsetBounds(displayLayout).right);
        assertEquals("Bounds top edge is unchanged",
                bounds.top, originalBounds.top);
    }

    private void overrideDefaultAspectRatio(float aspectRatio) {
        final TestableResources res = mContext.getOrCreateTestableResources();
        res.addOverride(
+5 −0
Original line number Diff line number Diff line
@@ -225,6 +225,7 @@ class PipDisplayTransferHandlerTest : ShellTestCase() {
        extra.putParcelable(PIP_START_TX, SurfaceControl.Transaction())
        extra.putParcelable(PIP_DESTINATION_BOUNDS, destinationBounds)
        pipDisplayTransferHandler.mWaitingForDisplayTransfer = true
        pipDisplayTransferHandler.mTargetDisplayId = TARGET_DISPLAY_ID

        pipDisplayTransferHandler.onPipTransitionStateChanged(
            UNDEFINED,
@@ -232,6 +233,10 @@ class PipDisplayTransferHandlerTest : ShellTestCase() {
            extra
        )

        verify(mockPipBoundsAlgorithm).snapToMovementBoundsEdge(
            eq(destinationBounds),
            eq(displayLayouts.get(TARGET_DISPLAY_ID))
        )
        verify(mockPipTransitionState).state = eq(EXITING_PIP)
        verify(mockPipTransitionState).state = eq(EXITED_PIP)
        verify(mockPipResizeAnimator).start()