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

Commit 475b073b authored by Vania Desmonda's avatar Vania Desmonda
Browse files

Don't show drag mirrors on displays that are not in the topology.

In projected mode, when dragging PiP across displays, the mirror is
sometimes shown on the default display (the phone) but it's not part of
the topology, so the PiP window can't be dragged over to that display.

Fixes: 422699849
Test: atest PipDisplayTransferHandlerTest
Flag: com.android.window.flags.enable_dragging_pip_across_displays
Change-Id: I9fbcb419f6366d22daa884b0c096b94d9338e535
parent 896dd599
Loading
Loading
Loading
Loading
+27 −6
Original line number Diff line number Diff line
@@ -203,18 +203,19 @@ public class PipDisplayTransferHandler implements
    public void showDragMirrorOnConnectedDisplays(RectF globalDpPipBounds, int focusedDisplayId) {
        final Transaction transaction = mSurfaceControlTransactionFactory.getTransaction();
        mIsMirrorShown = false;
        // If PiP is on a display that's not in the topology, don't show drag mirrors on other
        // displays because it can't be dragged over.
        if (!mDisplayController.isDisplayInTopology(focusedDisplayId)) return;

        // Iterate through each connected display ID to ensure partial PiP bounds are shown on
        // all corresponding displays while dragging
        for (int displayId : mRootTaskDisplayAreaOrganizer.getDisplayIds()) {
            DisplayLayout displayLayout = mDisplayController.getDisplayLayout(displayId);
            if (displayLayout == null) continue;

            boolean shouldShowOnDisplay = RectF.intersects(globalDpPipBounds,
                    displayLayout.globalBoundsDp());

            // Hide mirror if it's the currently focused display or if the PiP bounds do not
            // intersect with the boundaries of a given display bounds
            if (displayId == focusedDisplayId || !shouldShowOnDisplay) {
            // Hide mirror(s) if it shouldn't be shown on this display.
            if (!canShowMirrorForDisplay(displayId, focusedDisplayId, displayLayout,
                    globalDpPipBounds)) {
                if (mOnDragMirrorPerDisplayId.containsKey(displayId)) {
                    SurfaceControl pipMirror = mOnDragMirrorPerDisplayId.get(displayId);
                    transaction.hide(pipMirror);
@@ -244,6 +245,26 @@ public class PipDisplayTransferHandler implements
        transaction.apply();
    }

    /**
     * Drag mirrors can only be shown on non-focused display(s) in the topology that intersect
     * with the PiP global DP bounds.
     *
     * @param displayId         the given display ID on which drag mirror should be shown
     * @param focusedDisplayId  the display ID of where the PiP window is focused on
     *                          (where the pointer is)
     * @param displayLayout     the display layout of the given display ID
     * @param globalDpBounds    the PiP bounds in global DP
     * @return whether drag mirror can be shown on a given display ID.
     */
    private boolean canShowMirrorForDisplay(int displayId, int focusedDisplayId,
            DisplayLayout displayLayout, RectF globalDpBounds) {
        boolean pipBoundsIntersectDisplay = RectF.intersects(globalDpBounds,
                displayLayout.globalBoundsDp());

        return displayId != focusedDisplayId && pipBoundsIntersectDisplay
                && mDisplayController.isDisplayInTopology(displayId);
    }

    /**
     * Remove all drag indicator mirrors from each connected display.
     */
+65 −0
Original line number Diff line number Diff line
@@ -163,6 +163,7 @@ class PipDisplayTransferHandlerTest : ShellTestCase() {
                TestDisplay.entries.find { it.id == id }?.getSpyDisplayLayout(resources)
            displayLayouts.put(id, displayLayout)
            whenever(mockDisplayController.getDisplayLayout(id)).thenReturn(displayLayout)
            whenever(mockDisplayController.isDisplayInTopology(id)).thenReturn(true)
        }

        pipDisplayTransferHandler =
@@ -385,6 +386,70 @@ class PipDisplayTransferHandlerTest : ShellTestCase() {
        assertThat(pipDisplayTransferHandler.isMirrorShown()).isTrue()
    }

    @Test
    fun showDragMirrorOnConnectedDisplays_displayNotInTopology_createsOneFewerMirror() {
        val globalDpBounds = MultiDisplayDragMoveBoundsCalculator.calculateGlobalDpBoundsForDrag(
            displayLayouts.get(ORIGIN_DISPLAY_ID)!!, START_DRAG_COORDINATES,
            PIP_BOUNDS, displayLayouts.get(TARGET_DISPLAY_ID)!!,
            1000f, -100f)
        whenever(mockDisplayController.isDisplayInTopology(SECONDARY_DISPLAY_ID)).thenReturn(false)

        pipDisplayTransferHandler.showDragMirrorOnConnectedDisplays(
            globalDpBounds, ORIGIN_DISPLAY_ID
        )

        verify(mockRootTaskDisplayAreaOrganizer).reparentToDisplayArea(
            eq(TARGET_DISPLAY_ID),
            any(),
            any()
        )
        assertThat(pipDisplayTransferHandler.mOnDragMirrorPerDisplayId.size).isEqualTo(1)
        assertThat(
            pipDisplayTransferHandler.mOnDragMirrorPerDisplayId.containsKey(
                SECONDARY_DISPLAY_ID
            )
        ).isFalse()
        assertThat(
            pipDisplayTransferHandler.mOnDragMirrorPerDisplayId.containsKey(
                TARGET_DISPLAY_ID
            )
        ).isTrue()
        verify(mockSurfaceTransactionHelper, times(1)).setPipTransformations(
            any(),
            any(),
            any(),
            any(),
            any()
        )
        verify(mockSurfaceTransactionHelper, times(1)).setMirrorTransformations(any(), any())
        verify(mockTransaction, times(1)).apply()
        assertThat(pipDisplayTransferHandler.isMirrorShown()).isTrue()
    }

    @Test
    fun showDragMirrorOnConnectedDisplays_focusedDisplayNotInTopology_doesNotCreateMirrors() {
        val globalDpBounds = MultiDisplayDragMoveBoundsCalculator.calculateGlobalDpBoundsForDrag(
            displayLayouts.get(ORIGIN_DISPLAY_ID)!!, START_DRAG_COORDINATES,
            PIP_BOUNDS, displayLayouts.get(TARGET_DISPLAY_ID)!!,
            1000f, -100f)
        whenever(mockDisplayController.isDisplayInTopology(ORIGIN_DISPLAY_ID)).thenReturn(false)

        pipDisplayTransferHandler.showDragMirrorOnConnectedDisplays(
            globalDpBounds, ORIGIN_DISPLAY_ID
        )

        verify(mockRootTaskDisplayAreaOrganizer, never()).reparentToDisplayArea(
            any(), any(), any()
        )
        assertThat(pipDisplayTransferHandler.mOnDragMirrorPerDisplayId.isEmpty()).isTrue()
        verify(mockSurfaceTransactionHelper, never()).setPipTransformations(
            any(), any(), any(), any(), any()
        )
        verify(mockSurfaceTransactionHelper, never()).setMirrorTransformations(any(), any())
        verify(mockTransaction, never()).apply()
        assertThat(pipDisplayTransferHandler.isMirrorShown()).isFalse()
    }

    @Test
    fun removeMirrors_removesAllMirrorsAndAppliesTransactionOnce() {
        pipDisplayTransferHandler.mOnDragMirrorPerDisplayId = ArrayMap()