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

Commit 224ab6ca authored by Vania Desmonda's avatar Vania Desmonda
Browse files

Restrict PiP bounds to the display's min/max PiP size upon display transfer.

Since we're keeping the global dp size of the pip bounds constant while
moving pip across displays, it might be too big or small on the other
display. If this happens, snap the size to the allowed min/max size.

Fixes: 433285732
Test: atest PipDisplayTransferHandlerTest
Flag: com.android.window.flags.enable_dragging_pip_across_displays
Change-Id: I64771406a3c15bb6b4f4aa8a92d7be7e55a42567
parent 843a6f8d
Loading
Loading
Loading
Loading
+39 −5
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import static com.android.wm.shell.pip2.phone.PipTransition.PIP_DESTINATION_BOUN
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.TaskInfo;
import android.app.TaskInfo;
import android.content.Context;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.RectF;
import android.os.Bundle;
import android.os.Bundle;
@@ -97,6 +98,10 @@ public class PipDisplayTransferHandler implements
            Rect boundsOnRelease) {
            Rect boundsOnRelease) {
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                "%s scheduleMovePipToDisplay from=%d to=%d", TAG, originDisplayId, targetDisplayId);
                "%s scheduleMovePipToDisplay from=%d to=%d", TAG, originDisplayId, targetDisplayId);
        mPipDisplayLayoutState.setDisplayId(targetDisplayId);
        mPipDisplayLayoutState.setDisplayLayout(
                mDisplayController.getDisplayLayout(targetDisplayId));
        mPipBoundsState.updateMinMaxSize(mPipBoundsState.getAspectRatio());


        // Set bounds to the bounds on drag release so that we can use this as the origin bounds
        // Set bounds to the bounds on drag release so that we can use this as the origin bounds
        // during animation to snap to the display's edge.
        // during animation to snap to the display's edge.
@@ -107,6 +112,7 @@ public class PipDisplayTransferHandler implements
        // is released and the display ID and layout are updated.
        // is released and the display ID and layout are updated.
        mPipBoundsAlgorithm.snapToMovementBoundsEdge(boundsOnRelease,
        mPipBoundsAlgorithm.snapToMovementBoundsEdge(boundsOnRelease,
                mDisplayController.getDisplayLayout(targetDisplayId));
                mDisplayController.getDisplayLayout(targetDisplayId));
        snapBoundsWithinMinMaxSize(boundsOnRelease);


        Bundle extra = new Bundle();
        Bundle extra = new Bundle();
        extra.putInt(ORIGIN_DISPLAY_ID_KEY, originDisplayId);
        extra.putInt(ORIGIN_DISPLAY_ID_KEY, originDisplayId);
@@ -116,6 +122,38 @@ public class PipDisplayTransferHandler implements
        mPipTransitionState.setState(PipTransitionState.SCHEDULED_BOUNDS_CHANGE, extra);
        mPipTransitionState.setState(PipTransitionState.SCHEDULED_BOUNDS_CHANGE, extra);
    }
    }


    /**
     * Restricts {@param bounds} to the allowed min/max size constraints and snaps bounds to the
     * correct edge based on the snap fraction.
     */
    private void snapBoundsWithinMinMaxSize(Rect bounds) {
        final float snapFraction = mPipBoundsAlgorithm.getSnapAlgorithm().getSnapFraction(
                bounds,
                mPipBoundsAlgorithm.getMovementBounds(bounds),
                mPipBoundsState.getStashedState());

        final Point minSize = mPipBoundsState.getMinSize();
        final Point maxSize = mPipBoundsState.getMaxSize();
        int newWidth = bounds.width();
        int newHeight = bounds.height();

        if (bounds.width() < minSize.x || bounds.height() < minSize.y) {
            newWidth = minSize.x;
            newHeight = minSize.y;
        } else if (bounds.width() > maxSize.x || bounds.height() > maxSize.y) {
            newWidth = maxSize.x;
            newHeight = maxSize.y;
        }

        bounds.set(0, 0, newWidth, newHeight);

        mPipBoundsAlgorithm.getSnapAlgorithm().applySnapFraction(bounds,
                mPipBoundsAlgorithm.getMovementBounds(bounds), snapFraction,
                mPipBoundsState.getStashedState(), mPipBoundsState.getStashOffset(),
                mPipDisplayLayoutState.getDisplayBounds(),
                mPipDisplayLayoutState.getDisplayLayout().stableInsets());
    }

    @Override
    @Override
    public void onPipTransitionStateChanged(@PipTransitionState.TransitionState int oldState,
    public void onPipTransitionStateChanged(@PipTransitionState.TransitionState int oldState,
            @PipTransitionState.TransitionState int newState, @Nullable Bundle extra) {
            @PipTransitionState.TransitionState int newState, @Nullable Bundle extra) {
@@ -158,10 +196,6 @@ public class PipDisplayTransferHandler implements
                Trace.instant(Trace.TRACE_TAG_WINDOW_MANAGER,
                Trace.instant(Trace.TRACE_TAG_WINDOW_MANAGER,
                        "PipDisplayTransferHandler#changingPipBounds");
                        "PipDisplayTransferHandler#changingPipBounds");


                mPipDisplayLayoutState.setDisplayId(mTargetDisplayId);
                mPipDisplayLayoutState.setDisplayLayout(
                        mDisplayController.getDisplayLayout(mTargetDisplayId));

                mPipSurfaceTransactionHelper.round(startTx, pipLeash, true).shadow(startTx,
                mPipSurfaceTransactionHelper.round(startTx, pipLeash, true).shadow(startTx,
                        pipLeash, true /* applyShadowRadius */);
                        pipLeash, true /* applyShadowRadius */);
                // Set state to exiting and exited PiP to unregister input consumer on the current
                // Set state to exiting and exited PiP to unregister input consumer on the current
@@ -177,7 +211,7 @@ public class PipDisplayTransferHandler implements


                final PipResizeAnimator animator = mPipResizeAnimatorSupplier.get(mContext,
                final PipResizeAnimator animator = mPipResizeAnimatorSupplier.get(mContext,
                        mPipSurfaceTransactionHelper, pipLeash, startTx, finishTx,
                        mPipSurfaceTransactionHelper, pipLeash, startTx, finishTx,
                        mPipBoundsState.getBounds(), mPipBoundsState.getBounds(), pipBounds,
                        pipBounds, mPipBoundsState.getBounds(), pipBounds,
                        duration, 0);
                        duration, 0);


                animator.setAnimationEndCallback(() -> {
                animator.setAnimationEndCallback(() -> {
+18 −1
Original line number Original line Diff line number Diff line
@@ -41,6 +41,7 @@ import org.mockito.kotlin.whenever
import org.mockito.kotlin.verify
import org.mockito.kotlin.verify
import android.content.res.Configuration
import android.content.res.Configuration
import android.content.res.Resources
import android.content.res.Resources
import android.graphics.Point
import android.graphics.PointF
import android.graphics.PointF
import android.graphics.Rect
import android.graphics.Rect
import android.os.Bundle
import android.os.Bundle
@@ -63,6 +64,7 @@ import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.common.MultiDisplayDragMoveBoundsCalculator
import com.android.wm.shell.common.MultiDisplayDragMoveBoundsCalculator
import com.android.wm.shell.common.MultiDisplayTestUtil.TestDisplay
import com.android.wm.shell.common.MultiDisplayTestUtil.TestDisplay
import com.android.wm.shell.common.pip.PipBoundsAlgorithm
import com.android.wm.shell.common.pip.PipBoundsAlgorithm
import com.android.wm.shell.common.pip.PipSnapAlgorithm
import com.android.wm.shell.pip2.animation.PipResizeAnimator
import com.android.wm.shell.pip2.animation.PipResizeAnimator
import com.android.wm.shell.pip2.phone.PipTransitionState.EXITED_PIP
import com.android.wm.shell.pip2.phone.PipTransitionState.EXITED_PIP
import com.android.wm.shell.pip2.phone.PipTransitionState.EXITING_PIP
import com.android.wm.shell.pip2.phone.PipTransitionState.EXITING_PIP
@@ -86,6 +88,7 @@ class PipDisplayTransferHandlerTest : ShellTestCase() {
    private val mockRootTaskDisplayAreaOrganizer = mock<RootTaskDisplayAreaOrganizer>()
    private val mockRootTaskDisplayAreaOrganizer = mock<RootTaskDisplayAreaOrganizer>()
    private val mockPipBoundsState = mock<PipBoundsState>()
    private val mockPipBoundsState = mock<PipBoundsState>()
    private val mockPipBoundsAlgorithm = mock<PipBoundsAlgorithm>()
    private val mockPipBoundsAlgorithm = mock<PipBoundsAlgorithm>()
    private val mockPipSnapAlgorithm = mock<PipSnapAlgorithm>()
    private val mockTaskInfo = mock<ActivityManager.RunningTaskInfo>()
    private val mockTaskInfo = mock<ActivityManager.RunningTaskInfo>()
    private val mockDisplayController = mock<DisplayController>()
    private val mockDisplayController = mock<DisplayController>()
    private val mockTransaction = mock<SurfaceControl.Transaction>()
    private val mockTransaction = mock<SurfaceControl.Transaction>()
@@ -133,6 +136,10 @@ class PipDisplayTransferHandlerTest : ShellTestCase() {
        whenever(mockTransaction.show(any())).thenReturn(mockTransaction)
        whenever(mockTransaction.show(any())).thenReturn(mockTransaction)
        whenever(mockFactory.transaction).thenReturn(mockTransaction)
        whenever(mockFactory.transaction).thenReturn(mockTransaction)
        whenever(mockPipBoundsState.bounds).thenReturn(mockBounds)
        whenever(mockPipBoundsState.bounds).thenReturn(mockBounds)
        whenever(mockPipBoundsAlgorithm.snapAlgorithm).thenReturn(mockPipSnapAlgorithm)
        whenever(mockPipSnapAlgorithm.getSnapFraction(any(), any(), any())).thenReturn(0.5f)
        whenever(mockPipBoundsState.minSize).thenReturn(MIN_SIZE)
        whenever(mockPipBoundsState.maxSize).thenReturn(MAX_SIZE)
        whenever(
        whenever(
            mockSurfaceTransactionHelper.setPipTransformations(
            mockSurfaceTransactionHelper.setPipTransformations(
                any(),
                any(),
@@ -165,6 +172,11 @@ class PipDisplayTransferHandlerTest : ShellTestCase() {
            whenever(mockDisplayController.getDisplayLayout(id)).thenReturn(displayLayout)
            whenever(mockDisplayController.getDisplayLayout(id)).thenReturn(displayLayout)
            whenever(mockDisplayController.isDisplayInTopology(id)).thenReturn(true)
            whenever(mockDisplayController.isDisplayInTopology(id)).thenReturn(true)
        }
        }
        whenever(mockPipDisplayLayoutState.displayLayout).thenReturn(
            displayLayouts.get(
                ORIGIN_DISPLAY_ID
            )
        )


        pipDisplayTransferHandler =
        pipDisplayTransferHandler =
            PipDisplayTransferHandler(
            PipDisplayTransferHandler(
@@ -181,13 +193,16 @@ class PipDisplayTransferHandlerTest : ShellTestCase() {
    }
    }


    @Test
    @Test
    fun scheduleMovePipToDisplay_setsTransitionState() {
    fun scheduleMovePipToDisplay_setsDisplayAndTransitionStates() {
        pipDisplayTransferHandler.scheduleMovePipToDisplay(
        pipDisplayTransferHandler.scheduleMovePipToDisplay(
            ORIGIN_DISPLAY_ID,
            ORIGIN_DISPLAY_ID,
            TARGET_DISPLAY_ID,
            TARGET_DISPLAY_ID,
            DESTINATION_BOUNDS
            DESTINATION_BOUNDS
        )
        )


        verify(mockPipDisplayLayoutState).displayId = eq(TARGET_DISPLAY_ID)
        verify(mockPipDisplayLayoutState).displayLayout =
            eq(displayLayouts.get(TARGET_DISPLAY_ID))!!
        verify(mockPipBoundsAlgorithm).snapToMovementBoundsEdge(
        verify(mockPipBoundsAlgorithm).snapToMovementBoundsEdge(
            eq(DESTINATION_BOUNDS),
            eq(DESTINATION_BOUNDS),
            eq(displayLayouts.get(TARGET_DISPLAY_ID))
            eq(displayLayouts.get(TARGET_DISPLAY_ID))
@@ -480,5 +495,7 @@ class PipDisplayTransferHandlerTest : ShellTestCase() {
        val START_DRAG_COORDINATES = PointF(100f, 100f)
        val START_DRAG_COORDINATES = PointF(100f, 100f)
        val PIP_BOUNDS = Rect(0, 0, 700, 700)
        val PIP_BOUNDS = Rect(0, 0, 700, 700)
        val DESTINATION_BOUNDS = Rect(100, 100, 800, 800)
        val DESTINATION_BOUNDS = Rect(100, 100, 800, 800)
        val MIN_SIZE = Point(100, 200)
        val MAX_SIZE = Point(300, 400)
    }
    }
}
}
 No newline at end of file