From 6dc501b986dabc049ea2bf414b47910079dff46c Mon Sep 17 00:00:00 2001 From: Ameer Armaly Date: Tue, 4 Feb 2020 14:04:18 -0800 Subject: [PATCH 1/2] Fix crash when a motion event doesn't include locations for all pointers. When performing a multi-finger gesture, if one finger goes up before the rest of the fingers have finished moving, we need to account for that finger not being present in subsequent motion events. Bug: 148880038 Bug:136131815 Test: Enable talkback. Enable debugging in TouchExplorer. Perform multi-finger gestures in such a way that one finger goes up just before the other fingers finish moving. Inspect logs. Test: atest GestureManifoldTest AccessibilityGestureDetectorTest TouchExplorerTest Change-Id: Ic3158301be657f39232db9f5b3006f87d8d83c4f --- .../gestures/MultiFingerSwipe.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java index 8249239e3602e..96ef2b54fab9f 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java @@ -250,11 +250,29 @@ class MultiFingerSwipe extends GestureMatcher { @Override protected void onMove(MotionEvent event, MotionEvent rawEvent, int policyFlags) { - for (int pointerIndex = 0; pointerIndex < rawEvent.getPointerCount(); ++pointerIndex) { + for (int pointerIndex = 0; pointerIndex < mTargetFingerCount; ++pointerIndex) { + if (mPointerIds[pointerIndex] == INVALID_POINTER_ID) { + // Fingers have started to move before the required number of fingers are down. + // However, they can still move less than the touch slop and still be considered + // touching, not moving. + // So we just ignore fingers that haven't been assigned a pointer id and process + // those who have. + continue; + } if (DEBUG) { Slog.d(getGestureName(), "Processing move on finger " + pointerIndex); } int index = rawEvent.findPointerIndex(mPointerIds[pointerIndex]); + if (index < 0) { + // This finger is not present in this event. It could have gone up just before this + // movement. + if (DEBUG) { + Slog.d( + getGestureName(), + "Finger " + pointerIndex + " not found in this event. skipping."); + } + continue; + } final float x = rawEvent.getX(index); final float y = rawEvent.getY(index); if (x < 0f || y < 0f) { From ec5eb82a6d6f070fddcbee40a81ee09656bd6fda Mon Sep 17 00:00:00 2001 From: Ameer Armaly Date: Thu, 30 Jan 2020 15:42:17 -0800 Subject: [PATCH 2/2] Add four-finger gestures. This CL includes the following gestures: 1) Four-finger single / double / triple tap. 2) Four-finger swipe up / down / left / right. Bug: 136131815 Test: atest GestureManifoldTest AccessibilityGestureDetectorTest TouchExplorerTest Change-Id: If5b4bfc680423f0672452b9aa440c8f18333f565 --- api/current.txt | 7 ++++++ .../AccessibilityGestureEvent.java | 23 ++++++++++++++++++- .../AccessibilityService.java | 21 +++++++++++++++++ .../GestureDescription.java | 7 ++++-- .../gestures/GestureManifold.java | 23 +++++++++++++++++++ .../gestures/MultiFingerSwipe.java | 6 ++--- 6 files changed, 81 insertions(+), 6 deletions(-) diff --git a/api/current.txt b/api/current.txt index 87a5cd7a648bb..bbe3015db589e 100644 --- a/api/current.txt +++ b/api/current.txt @@ -2888,6 +2888,13 @@ package android.accessibilityservice { field public static final int GESTURE_3_FINGER_SWIPE_RIGHT = 32; // 0x20 field public static final int GESTURE_3_FINGER_SWIPE_UP = 29; // 0x1d field public static final int GESTURE_3_FINGER_TRIPLE_TAP = 24; // 0x18 + field public static final int GESTURE_4_FINGER_DOUBLE_TAP = 38; // 0x26 + field public static final int GESTURE_4_FINGER_SINGLE_TAP = 37; // 0x25 + field public static final int GESTURE_4_FINGER_SWIPE_DOWN = 34; // 0x22 + field public static final int GESTURE_4_FINGER_SWIPE_LEFT = 35; // 0x23 + field public static final int GESTURE_4_FINGER_SWIPE_RIGHT = 36; // 0x24 + field public static final int GESTURE_4_FINGER_SWIPE_UP = 33; // 0x21 + field public static final int GESTURE_4_FINGER_TRIPLE_TAP = 39; // 0x27 field public static final int GESTURE_DOUBLE_TAP = 17; // 0x11 field public static final int GESTURE_DOUBLE_TAP_AND_HOLD = 18; // 0x12 field public static final int GESTURE_SWIPE_DOWN = 2; // 0x2 diff --git a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java index 9cf1de93e344c..ace13513e39db 100644 --- a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java +++ b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java @@ -31,6 +31,13 @@ import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_RIGHT; import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_UP; import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP; +import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP; +import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SINGLE_TAP; +import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_DOWN; +import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_LEFT; +import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_RIGHT; +import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_UP; +import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_TRIPLE_TAP; import static android.accessibilityservice.AccessibilityService.GESTURE_DOUBLE_TAP; import static android.accessibilityservice.AccessibilityService.GESTURE_DOUBLE_TAP_AND_HOLD; import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN; @@ -105,7 +112,14 @@ public final class AccessibilityGestureEvent implements Parcelable { GESTURE_3_FINGER_SWIPE_DOWN, GESTURE_3_FINGER_SWIPE_LEFT, GESTURE_3_FINGER_SWIPE_RIGHT, - GESTURE_3_FINGER_SWIPE_UP + GESTURE_3_FINGER_SWIPE_UP, + GESTURE_4_FINGER_DOUBLE_TAP, + GESTURE_4_FINGER_SINGLE_TAP, + GESTURE_4_FINGER_SWIPE_DOWN, + GESTURE_4_FINGER_SWIPE_LEFT, + GESTURE_4_FINGER_SWIPE_RIGHT, + GESTURE_4_FINGER_SWIPE_UP, + GESTURE_4_FINGER_TRIPLE_TAP }) @Retention(RetentionPolicy.SOURCE) public @interface GestureId {} @@ -165,6 +179,9 @@ public final class AccessibilityGestureEvent implements Parcelable { case GESTURE_3_FINGER_SINGLE_TAP: return "GESTURE_3_FINGER_SINGLE_TAP"; case GESTURE_3_FINGER_DOUBLE_TAP: return "GESTURE_3_FINGER_DOUBLE_TAP"; case GESTURE_3_FINGER_TRIPLE_TAP: return "GESTURE_3_FINGER_TRIPLE_TAP"; + case GESTURE_4_FINGER_SINGLE_TAP: return "GESTURE_4_FINGER_SINGLE_TAP"; + case GESTURE_4_FINGER_DOUBLE_TAP: return "GESTURE_4_FINGER_DOUBLE_TAP"; + case GESTURE_4_FINGER_TRIPLE_TAP: return "GESTURE_4_FINGER_TRIPLE_TAP"; case GESTURE_DOUBLE_TAP: return "GESTURE_DOUBLE_TAP"; case GESTURE_DOUBLE_TAP_AND_HOLD: return "GESTURE_DOUBLE_TAP_AND_HOLD"; case GESTURE_SWIPE_DOWN: return "GESTURE_SWIPE_DOWN"; @@ -191,6 +208,10 @@ public final class AccessibilityGestureEvent implements Parcelable { case GESTURE_3_FINGER_SWIPE_LEFT: return "GESTURE_3_FINGER_SWIPE_LEFT"; case GESTURE_3_FINGER_SWIPE_RIGHT: return "GESTURE_3_FINGER_SWIPE_RIGHT"; case GESTURE_3_FINGER_SWIPE_UP: return "GESTURE_3_FINGER_SWIPE_UP"; + case GESTURE_4_FINGER_SWIPE_DOWN: return "GESTURE_4_FINGER_SWIPE_DOWN"; + case GESTURE_4_FINGER_SWIPE_LEFT: return "GESTURE_4_FINGER_SWIPE_LEFT"; + case GESTURE_4_FINGER_SWIPE_RIGHT: return "GESTURE_4_FINGER_SWIPE_RIGHT"; + case GESTURE_4_FINGER_SWIPE_UP: return "GESTURE_4_FINGER_SWIPE_UP"; default: return Integer.toHexString(eventType); } } diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 2165fb35a0e58..11f7f465cca5c 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -388,6 +388,27 @@ public abstract class AccessibilityService extends Service { */ public static final int GESTURE_3_FINGER_SWIPE_RIGHT = 32; + /** The user has performed a four-finger swipe up gesture on the touch screen. */ + public static final int GESTURE_4_FINGER_SWIPE_UP = 33; + + /** The user has performed a four-finger swipe down gesture on the touch screen. */ + public static final int GESTURE_4_FINGER_SWIPE_DOWN = 34; + + /** The user has performed a four-finger swipe left gesture on the touch screen. */ + public static final int GESTURE_4_FINGER_SWIPE_LEFT = 35; + + /** The user has performed a four-finger swipe right gesture on the touch screen. */ + public static final int GESTURE_4_FINGER_SWIPE_RIGHT = 36; + + /** The user has performed a four-finger single tap gesture on the touch screen. */ + public static final int GESTURE_4_FINGER_SINGLE_TAP = 37; + + /** The user has performed a four-finger double tap gesture on the touch screen. */ + public static final int GESTURE_4_FINGER_DOUBLE_TAP = 38; + + /** The user has performed a four-finger triple tap gesture on the touch screen. */ + public static final int GESTURE_4_FINGER_TRIPLE_TAP = 39; + /** * The {@link Intent} that must be declared as handled by the service. */ diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java index 3b79d217c5133..a821dadf49489 100644 --- a/core/java/android/accessibilityservice/GestureDescription.java +++ b/core/java/android/accessibilityservice/GestureDescription.java @@ -40,7 +40,7 @@ import java.util.List; */ public final class GestureDescription { /** Gestures may contain no more than this many strokes */ - private static final int MAX_STROKE_COUNT = 10; + private static final int MAX_STROKE_COUNT = 20; /** * Upper bound on total gesture duration. Nearly all gestures will be much shorter. @@ -194,7 +194,10 @@ public final class GestureDescription { public Builder addStroke(@NonNull StrokeDescription strokeDescription) { if (mStrokes.size() >= MAX_STROKE_COUNT) { throw new IllegalStateException( - "Attempting to add too many strokes to a gesture"); + "Attempting to add too many strokes to a gesture. Maximum is " + + MAX_STROKE_COUNT + + ", got " + + mStrokes.size()); } mStrokes.add(strokeDescription); diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java index 5d170d34d77d1..b74be7e3f3459 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java @@ -30,6 +30,13 @@ import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_RIGHT; import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_UP; import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP; +import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP; +import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SINGLE_TAP; +import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_DOWN; +import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_LEFT; +import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_RIGHT; +import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SWIPE_UP; +import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_TRIPLE_TAP; import static android.accessibilityservice.AccessibilityService.GESTURE_DOUBLE_TAP; import static android.accessibilityservice.AccessibilityService.GESTURE_DOUBLE_TAP_AND_HOLD; import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN; @@ -133,6 +140,13 @@ class GestureManifold implements GestureMatcher.StateChangeListener { new MultiFingerMultiTap(mContext, 3, 2, GESTURE_3_FINGER_DOUBLE_TAP, this)); mMultiFingerGestures.add( new MultiFingerMultiTap(mContext, 3, 3, GESTURE_3_FINGER_TRIPLE_TAP, this)); + // Four-finger taps. + mMultiFingerGestures.add( + new MultiFingerMultiTap(mContext, 4, 1, GESTURE_4_FINGER_SINGLE_TAP, this)); + mMultiFingerGestures.add( + new MultiFingerMultiTap(mContext, 4, 2, GESTURE_4_FINGER_DOUBLE_TAP, this)); + mMultiFingerGestures.add( + new MultiFingerMultiTap(mContext, 4, 3, GESTURE_4_FINGER_TRIPLE_TAP, this)); // Two-finger swipes. mMultiFingerGestures.add( new MultiFingerSwipe(context, 2, DOWN, GESTURE_2_FINGER_SWIPE_DOWN, this)); @@ -151,6 +165,15 @@ class GestureManifold implements GestureMatcher.StateChangeListener { new MultiFingerSwipe(context, 3, RIGHT, GESTURE_3_FINGER_SWIPE_RIGHT, this)); mMultiFingerGestures.add( new MultiFingerSwipe(context, 3, UP, GESTURE_3_FINGER_SWIPE_UP, this)); + // Four-finger swipes. + mMultiFingerGestures.add( + new MultiFingerSwipe(context, 4, DOWN, GESTURE_4_FINGER_SWIPE_DOWN, this)); + mMultiFingerGestures.add( + new MultiFingerSwipe(context, 4, LEFT, GESTURE_4_FINGER_SWIPE_LEFT, this)); + mMultiFingerGestures.add( + new MultiFingerSwipe(context, 4, RIGHT, GESTURE_4_FINGER_SWIPE_RIGHT, this)); + mMultiFingerGestures.add( + new MultiFingerSwipe(context, 4, UP, GESTURE_4_FINGER_SWIPE_UP, this)); } /** diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java index 96ef2b54fab9f..a14584a63bb2c 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java @@ -139,7 +139,7 @@ class MultiFingerSwipe extends GestureMatcher { final int actionIndex = getActionIndex(rawEvent); final int pointerId = rawEvent.getPointerId(actionIndex); int pointerIndex = rawEvent.getPointerCount() - 1; - if (pointerId < 0 || pointerId > rawEvent.getPointerCount() - 1) { + if (pointerId < 0) { // Nonsensical pointer id. cancelGesture(event, rawEvent, policyFlags); return; @@ -185,7 +185,7 @@ class MultiFingerSwipe extends GestureMatcher { } final int actionIndex = getActionIndex(rawEvent); final int pointerId = rawEvent.getPointerId(actionIndex); - if (pointerId < 0 || pointerId > rawEvent.getPointerCount() - 1) { + if (pointerId < 0) { // Nonsensical pointer id. cancelGesture(event, rawEvent, policyFlags); return; @@ -224,7 +224,7 @@ class MultiFingerSwipe extends GestureMatcher { mCurrentFingerCount -= 1; final int actionIndex = getActionIndex(event); final int pointerId = event.getPointerId(actionIndex); - if (pointerId < 0 || pointerId > rawEvent.getPointerCount() - 1) { + if (pointerId < 0) { // Nonsensical pointer id. cancelGesture(event, rawEvent, policyFlags); return;