summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java58
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt63
2 files changed, 111 insertions, 10 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
index da268988bac7..3fd3656ccbc5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
@@ -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;
@@ -67,7 +71,7 @@ class DragDetector {
*
* @return the result returned by {@link #mEventHandler}, or the result when
* {@link #mEventHandler} handles the previous down event if the event shouldn't be passed
- */
+ */
boolean onMotionEvent(View v, MotionEvent ev) {
final boolean isTouchScreen =
(ev.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN;
@@ -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;
}
@@ -129,4 +167,4 @@ class DragDetector {
interface MotionEventHandler {
boolean handleMotionEvent(@Nullable View v, MotionEvent ev);
}
-}
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt
index 3fbab0f9e2bb..56224b4b4025 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragDetectorTest.kt
@@ -85,6 +85,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 {
return@argThat it.action == MotionEvent.ACTION_DOWN
@@ -166,6 +183,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 {
it.action == MotionEvent.ACTION_HOVER_ENTER