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

Commit 186e354e authored by Vania Desmonda's avatar Vania Desmonda
Browse files

Limit dragging using 2 pointers so that it doesn't create a clunky

behaviour when the user uses 2 fingers to resize at once or
sequentalliy.

Test: atest WMShellUnitTests:DragDetectorTest
Flag: EXEMPT fixing bug
Fixes: 336242246
Fixes: 336247472
Change-Id: I9e003b7effd8c7893195afd38aade704e80d969d
parent 29bad4ea
Loading
Loading
Loading
Loading
+48 −10
Original line number Diff line number Diff line
@@ -19,7 +19,11 @@ package com.android.wm.shell.windowdecor;
import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_HOVER_ENTER;
import static android.view.MotionEvent.ACTION_HOVER_EXIT;
import static android.view.MotionEvent.ACTION_HOVER_MOVE;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;

import android.graphics.PointF;
@@ -43,7 +47,7 @@ class DragDetector {
    private final PointF mInputDownPoint = new PointF();
    private int mTouchSlop;
    private boolean mIsDragEvent;
    private int mDragPointerId;
    private int mDragPointerId = -1;

    private boolean mResultOfDownAction;

@@ -86,10 +90,14 @@ class DragDetector {
                return mResultOfDownAction;
            }
            case ACTION_MOVE: {
                if (ev.findPointerIndex(mDragPointerId) == -1) {
                    mDragPointerId = ev.getPointerId(0);
                if (mDragPointerId == -1) {
                    // The primary pointer was lifted, ignore the rest of the gesture.
                    return mResultOfDownAction;
                }
                final int dragPointerIndex = ev.findPointerIndex(mDragPointerId);
                if (dragPointerIndex == -1) {
                    throw new IllegalStateException("Failed to find primary pointer!");
                }
                if (!mIsDragEvent) {
                    float dx = ev.getRawX(dragPointerIndex) - mInputDownPoint.x;
                    float dy = ev.getRawY(dragPointerIndex) - mInputDownPoint.y;
@@ -99,22 +107,52 @@ class DragDetector {
                }
                // The event handler should only be notified about 'move' events if a drag has been
                // detected.
                if (mIsDragEvent) {
                    return mEventHandler.handleMotionEvent(v, ev);
                } else {
                if (!mIsDragEvent) {
                    return mResultOfDownAction;
                }
                return mEventHandler.handleMotionEvent(v,
                        getSinglePointerEvent(ev, mDragPointerId));
            }
            case ACTION_HOVER_ENTER:
            case ACTION_HOVER_MOVE:
            case ACTION_HOVER_EXIT: {
                return mEventHandler.handleMotionEvent(v,
                        getSinglePointerEvent(ev, mDragPointerId));
            }
            case ACTION_POINTER_UP: {
                if (mDragPointerId == -1) {
                    // The primary pointer was lifted, ignore the rest of the gesture.
                    return mResultOfDownAction;
                }
                if (mDragPointerId != ev.getPointerId(ev.getActionIndex())) {
                    // Ignore a secondary pointer being lifted.
                    return mResultOfDownAction;
                }
                // The primary pointer is being lifted.
                final int dragPointerId = mDragPointerId;
                mDragPointerId = -1;
                return mEventHandler.handleMotionEvent(v, getSinglePointerEvent(ev, dragPointerId));
            }
            case ACTION_UP:
            case ACTION_CANCEL: {
                final int dragPointerId = mDragPointerId;
                resetState();
                return mEventHandler.handleMotionEvent(v, ev);
                if (dragPointerId == -1) {
                    // The primary pointer was lifted, ignore the rest of the gesture.
                    return mResultOfDownAction;
                }
                return mEventHandler.handleMotionEvent(v, getSinglePointerEvent(ev, dragPointerId));
            }
            default:
                return mEventHandler.handleMotionEvent(v, ev);
                // Ignore other events.
                return mResultOfDownAction;
        }
    }

    private static MotionEvent getSinglePointerEvent(MotionEvent ev, int pointerId) {
        return ev.getPointerCount() > 1 ? ev.split(1 << pointerId) : ev;
    }

    void setTouchSlop(int touchSlop) {
        mTouchSlop = touchSlop;
    }
+63 −0
Original line number Diff line number Diff line
@@ -84,6 +84,23 @@ class DragDetectorTest {
        })
    }

    @Test
    fun testNoMove_mouse_passesDownAndUp() {
        assertTrue(dragDetector.onMotionEvent(
            createMotionEvent(MotionEvent.ACTION_DOWN, isTouch = false)))
        verify(eventHandler).handleMotionEvent(any(), argThat {
            return@argThat it.action == MotionEvent.ACTION_DOWN && it.x == X && it.y == Y &&
                    it.source == InputDevice.SOURCE_MOUSE
        })

        assertTrue(dragDetector.onMotionEvent(
            createMotionEvent(MotionEvent.ACTION_UP, isTouch = false)))
        verify(eventHandler).handleMotionEvent(any(), argThat {
            return@argThat it.action == MotionEvent.ACTION_UP && it.x == X && it.y == Y &&
                    it.source == InputDevice.SOURCE_MOUSE
        })
    }

    @Test
    fun testMoveInSlop_touch_passesDownAndUp() {
        `when`(eventHandler.handleMotionEvent(any(), argThat {
@@ -165,6 +182,52 @@ class DragDetectorTest {
        })
    }

    @Test
    fun testDownMoveDown_shouldIgnoreTheSecondDownMotion() {
        assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_DOWN)))
        verify(eventHandler).handleMotionEvent(any(), argThat {
            return@argThat it.action == MotionEvent.ACTION_DOWN && it.x == X && it.y == Y &&
                    it.source == InputDevice.SOURCE_TOUCHSCREEN
        })

        val newX = X + SLOP + 1
        assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_MOVE, newX, Y)))
        verify(eventHandler).handleMotionEvent(any(), argThat {
            return@argThat it.action == MotionEvent.ACTION_MOVE && it.x == newX && it.y == Y &&
                    it.source == InputDevice.SOURCE_TOUCHSCREEN
        })

        assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_DOWN)))
        verify(eventHandler).handleMotionEvent(any(), argThat {
            return@argThat it.action == MotionEvent.ACTION_MOVE && it.x == newX && it.y == Y &&
                    it.source == InputDevice.SOURCE_TOUCHSCREEN
        })
    }

    @Test
    fun testDownMouseMoveDownTouch_shouldIgnoreTheTouchDownMotion() {
        assertTrue(dragDetector.onMotionEvent(
            createMotionEvent(MotionEvent.ACTION_DOWN, isTouch = false)))
        verify(eventHandler).handleMotionEvent(any(), argThat {
            return@argThat it.action == MotionEvent.ACTION_DOWN && it.x == X && it.y == Y &&
                    it.source == InputDevice.SOURCE_MOUSE
        })

        val newX = X + SLOP + 1
        assertTrue(dragDetector.onMotionEvent(
            createMotionEvent(MotionEvent.ACTION_MOVE, newX, Y, isTouch = false)))
        verify(eventHandler).handleMotionEvent(any(), argThat {
            return@argThat it.action == MotionEvent.ACTION_MOVE && it.x == newX && it.y == Y &&
                    it.source == InputDevice.SOURCE_MOUSE
        })

        assertTrue(dragDetector.onMotionEvent(createMotionEvent(MotionEvent.ACTION_DOWN)))
        verify(eventHandler).handleMotionEvent(any(), argThat {
            return@argThat it.action == MotionEvent.ACTION_MOVE && it.x == newX && it.y == Y &&
                    it.source == InputDevice.SOURCE_MOUSE
        })
    }

    @Test
    fun testPassesHoverEnter() {
        `when`(eventHandler.handleMotionEvent(any(), argThat {