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

Commit 2aeee525 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Disable the PiP dismiss target if input is not touch screen." into main

parents f510a115 aaaab629
Loading
Loading
Loading
Loading
+25 −7
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import android.os.SystemProperties;
import android.provider.DeviceConfig;
import android.util.Size;
import android.view.DisplayCutout;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -98,7 +99,7 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha
    @NonNull private final SizeSpecSource mSizeSpecSource;
    @NonNull private final PipDisplayLayoutState mPipDisplayLayoutState;
    private final PipUiEventLogger mPipUiEventLogger;
    private final PipDismissTargetHandler mPipDismissTargetHandler;
    private PipDismissTargetHandler mPipDismissTargetHandler;
    private final ShellExecutor mMainExecutor;
    @Nullable private final PipPerfHintController mPipPerfHintController;

@@ -554,6 +555,7 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha
        }

        if ((ev.getAction() == MotionEvent.ACTION_DOWN || mTouchState.isUserInteracting())
                && isDismissTargetEnabled(ev)
                && mPipDismissTargetHandler.maybeConsumeMotionEvent(ev)) {
            // If the first touch event occurs within the magnetic field, pass the ACTION_DOWN event
            // to the touch state. Touch state needs a DOWN event in order to later process MOVE
@@ -787,22 +789,29 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha
        return mMotionHelper;
    }

    @VisibleForTesting
    public PipResizeGestureHandler getPipResizeGestureHandler() {
    @VisibleForTesting PipResizeGestureHandler getPipResizeGestureHandler() {
        return mPipResizeGestureHandler;
    }

    @VisibleForTesting
    public void setPipResizeGestureHandler(PipResizeGestureHandler pipResizeGestureHandler) {
    void setPipResizeGestureHandler(PipResizeGestureHandler pipResizeGestureHandler) {
        mPipResizeGestureHandler = pipResizeGestureHandler;
    }

    @VisibleForTesting PipDismissTargetHandler getPipDismissTargetHandler() {
        return mPipDismissTargetHandler;
    }

    @VisibleForTesting
    public void setPipMotionHelper(PipMotionHelper pipMotionHelper) {
    void setPipDismissTargetHandler(PipDismissTargetHandler pipDismissTargetHandler) {
        mPipDismissTargetHandler = pipDismissTargetHandler;
    }

    @VisibleForTesting void setPipMotionHelper(PipMotionHelper pipMotionHelper) {
        mMotionHelper = pipMotionHelper;
    }

    @VisibleForTesting public void setPipTouchState(PipTouchState pipTouchState) {
    @VisibleForTesting void setPipTouchState(PipTouchState pipTouchState) {
        mTouchState = pipTouchState;
    }

@@ -876,8 +885,10 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha

            if (touchState.startedDragging()) {
                mSavedSnapFraction = -1f;
                if (isDismissTargetEnabled(touchState.getLatestMotionEvent())) {
                    mPipDismissTargetHandler.showDismissTargetMaybe();
                }
            }

            if (touchState.isDragging()) {
                mPipBoundsState.setHasUserMovedPip(true);
@@ -1087,6 +1098,13 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha
        }
    }

    private boolean isDismissTargetEnabled(MotionEvent ev) {
        // Only allow dismiss target to be shown and enabled on touch screen and stylus input
        return !mPipDesktopState.isDraggingPipAcrossDisplaysEnabled()
                || ev.getSource() == InputDevice.SOURCE_TOUCHSCREEN
                || ev.getSource() == InputDevice.SOURCE_STYLUS;
    }

    /**
     * Updates the current movement bounds based on whether the menu is currently visible and
     * resized.
+10 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ public class PipTouchState {
    private final PointF mLastTouch = new PointF();
    private final PointF mLastDelta = new PointF();
    private final PointF mVelocity = new PointF();
    private MotionEvent mLatestMotionEvent;
    private boolean mAllowTouches = true;

    // Set to false to block both PipTouchHandler and PipResizeGestureHandler's input processing
@@ -119,6 +120,7 @@ public class PipTouchState {
                initOrResetVelocityTracker();
                addMovementToVelocityTracker(ev);

                mLatestMotionEvent = ev;
                mActivePointerId = ev.getPointerId(0);
                if (DEBUG) {
                    ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
@@ -247,6 +249,13 @@ public class PipTouchState {
        return mLastTouch;
    }

    /**
     * @return the motion event of the latest touch event.
     */
    public MotionEvent getLatestMotionEvent() {
        return mLatestMotionEvent;
    }

    /**
     * @return the movement delta between the last handled touch event and the previous touch
     * position.
@@ -419,6 +428,7 @@ public class PipTouchState {
        pw.println(innerPrefix + "mLastTouch=" + mLastTouch);
        pw.println(innerPrefix + "mLastDelta=" + mLastDelta);
        pw.println(innerPrefix + "mVelocity=" + mVelocity);
        pw.println(innerPrefix + "mLatestMotionEvent=" + mLatestMotionEvent);
        pw.println(innerPrefix + "mIsUserInteracting=" + mIsUserInteracting);
        pw.println(innerPrefix + "mIsDragging=" + mIsDragging);
        pw.println(innerPrefix + "mStartedDragging=" + mStartedDragging);
+79 −3
Original line number Diff line number Diff line
@@ -20,6 +20,9 @@ import android.graphics.Rect
import android.graphics.RectF
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.InputDevice.SOURCE_MOUSE
import android.view.InputDevice.SOURCE_TOUCHSCREEN
import android.view.MotionEvent
import android.view.SurfaceControl
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito
@@ -49,6 +52,7 @@ import org.mockito.ArgumentMatchers.anyInt
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever

@@ -85,6 +89,8 @@ class PipTouchHandlerTest : ShellTestCase() {
    private val mockDisplayLayout = mock<DisplayLayout>()
    private val mockTouchPosition = PointF()
    private val mockPipSurfaceTransactionHelper = mock<PipSurfaceTransactionHelper>()
    private val mockMotionEvent = mock<MotionEvent>()
    private val mockPipDismissTargetHandler = mock<PipDismissTargetHandler>()

    private lateinit var pipTouchHandler: PipTouchHandler
    private lateinit var pipTouchGesture: PipTouchGesture
@@ -108,12 +114,16 @@ class PipTouchHandlerTest : ShellTestCase() {
        )
        pipTouchGesture = pipTouchHandler.touchGesture
        pipTouchHandler.setPipTouchState(pipTouchState)
        pipTouchHandler.setPipDismissTargetHandler(mockPipDismissTargetHandler)

        whenever(pipTouchState.downTouchPosition).thenReturn(mockTouchPosition)
        whenever(pipTouchState.velocity).thenReturn(mockTouchPosition)
        whenever(pipTouchState.lastTouchPosition).thenReturn(mockTouchPosition)
        whenever(pipTouchState.lastTouchDisplayId).thenReturn(ORIGIN_DISPLAY_ID)
        whenever(pipTouchState.lastTouchDelta).thenReturn(mockTouchPosition)
        whenever(pipTouchState.isUserInteracting).thenReturn(true)
        whenever(pipTouchState.allowInputEvents).thenReturn(true)
        whenever(pipTouchState.latestMotionEvent).thenReturn(mockMotionEvent)
        whenever(pipTransitionState.pinnedTaskLeash).thenReturn(mockLeash)
        whenever(mockPipBoundsState.movementBounds).thenReturn(PIP_BOUNDS)
        whenever(mockPipBoundsState.motionBoundsState).thenReturn(mockMotionBoundsState)
@@ -133,11 +143,11 @@ class PipTouchHandlerTest : ShellTestCase() {
    @Test
    fun pipTouchGesture_crossDisplayDragFlagEnabled_onMove_showsMirrors() {
        whenever(mockPipDesktopState.isDraggingPipAcrossDisplaysEnabled()).thenReturn(true)
        whenever(pipTouchState.isUserInteracting).thenReturn(true)
        whenever(pipTouchState.isDragging).thenReturn(true)
        // Initialize variables that are set on down
        pipTouchGesture.onDown(pipTouchState)

        pipTouchHandler.handleTouchEvent(mockMotionEvent)
        pipTouchGesture.onMove(pipTouchState)

        ExtendedMockito.verify {
@@ -152,14 +162,14 @@ class PipTouchHandlerTest : ShellTestCase() {
            )
        }
        verify(mockPipDisplayTransferHandler).showDragMirrorOnConnectedDisplays(
             eq(GLOBAL_BOUNDS), eq(ORIGIN_DISPLAY_ID))
            eq(GLOBAL_BOUNDS), eq(ORIGIN_DISPLAY_ID)
        )
        verify(mockPipMotionHelper).movePip(eq(PIP_BOUNDS), eq(true), eq(ORIGIN_DISPLAY_ID))
    }

    @Test
    fun pipTouchGesture_crossDisplayDragFlagEnabled_onUpOnADifferentDisplay_schedulesMovePip() {
        whenever(mockPipDesktopState.isDraggingPipAcrossDisplaysEnabled()).thenReturn(true)
        whenever(pipTouchState.isUserInteracting).thenReturn(true)
        pipTouchGesture.onDown(pipTouchState)

        pipTouchHandler.mEnableStash = false
@@ -183,6 +193,72 @@ class PipTouchHandlerTest : ShellTestCase() {
        verify(mockPipDisplayTransferHandler).removeMirrors()
    }

    @Test
    fun handleTouchEvent_crossDisplayFlagDisabled_shouldAllowDismissTargetHandler() {
        whenever(mockPipDesktopState.isDraggingPipAcrossDisplaysEnabled()).thenReturn(false)
        whenever(mockMotionEvent.source).thenReturn(SOURCE_MOUSE)

        pipTouchHandler.handleTouchEvent(mockMotionEvent)

        verify(mockPipDismissTargetHandler).maybeConsumeMotionEvent(any())
    }

    @Test
    fun handleTouchEvent_crossDisplayFlagEnabled_touchScreenInput_shouldAllowDismissTargetHandler() {
        whenever(mockPipDesktopState.isDraggingPipAcrossDisplaysEnabled()).thenReturn(true)
        whenever(mockMotionEvent.source).thenReturn(SOURCE_TOUCHSCREEN)

        pipTouchHandler.handleTouchEvent(mockMotionEvent)

        verify(mockPipDismissTargetHandler).maybeConsumeMotionEvent(any())
    }

    @Test
    fun handleTouchEvent_crossDisplayFlagEnabled_mouseInput_shouldNotAllowDismissTargetHandler() {
        whenever(mockPipDesktopState.isDraggingPipAcrossDisplaysEnabled()).thenReturn(true)
        whenever(mockMotionEvent.source).thenReturn(SOURCE_MOUSE)

        pipTouchHandler.handleTouchEvent(mockMotionEvent)

        verify(mockPipDismissTargetHandler, never()).maybeConsumeMotionEvent(any())
    }

    @Test
    fun onMove_crossDisplayFlagDisabled_shouldShowDismissTarget() {
        whenever(mockPipDesktopState.isDraggingPipAcrossDisplaysEnabled()).thenReturn(false)
        whenever(pipTouchState.startedDragging()).thenReturn(true)
        whenever(mockMotionEvent.source).thenReturn(SOURCE_MOUSE)

        pipTouchHandler.handleTouchEvent(mockMotionEvent)
        pipTouchGesture.onMove(pipTouchState)

        verify(mockPipDismissTargetHandler).showDismissTargetMaybe()
    }

    @Test
    fun onMove_crossDisplayFlagEnabled_touchScreenInput_shouldShowDismissTarget() {
        whenever(mockPipDesktopState.isDraggingPipAcrossDisplaysEnabled()).thenReturn(true)
        whenever(pipTouchState.startedDragging()).thenReturn(true)
        whenever(mockMotionEvent.source).thenReturn(SOURCE_TOUCHSCREEN)

        pipTouchHandler.handleTouchEvent(mockMotionEvent)
        pipTouchGesture.onMove(pipTouchState)

        verify(mockPipDismissTargetHandler).showDismissTargetMaybe()
    }

    @Test
    fun onMove_crossDisplayFlagEnabled_mouseInput_shouldShowDismissTarget() {
        whenever(mockPipDesktopState.isDraggingPipAcrossDisplaysEnabled()).thenReturn(true)
        whenever(pipTouchState.startedDragging()).thenReturn(true)
        whenever(mockMotionEvent.source).thenReturn(SOURCE_MOUSE)

        pipTouchHandler.handleTouchEvent(mockMotionEvent)
        pipTouchGesture.onMove(pipTouchState)

        verify(mockPipDismissTargetHandler, never()).showDismissTargetMaybe()
    }

    private companion object {
        const val ORIGIN_DISPLAY_ID = 0
        const val TARGET_DISPLAY_ID = 1