Add multi-finger double tap and hold gestures.
This CL includes two, three and four finger double-tap and hold. Bug: 136131815 Test: atest GestureManifoldTest TouchExplorerTest AccessibilityGestureDetectorTest Change-Id: I4c0a95a4ac2d13e0a7e2c7920df619063ec1cfc0
This commit is contained in:
@@ -2876,6 +2876,7 @@ package android.accessibilityservice {
|
||||
method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
|
||||
method public boolean takeScreenshot(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.accessibilityservice.AccessibilityService.ScreenshotResult>);
|
||||
field public static final int GESTURE_2_FINGER_DOUBLE_TAP = 20; // 0x14
|
||||
field public static final int GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD = 40; // 0x28
|
||||
field public static final int GESTURE_2_FINGER_SINGLE_TAP = 19; // 0x13
|
||||
field public static final int GESTURE_2_FINGER_SWIPE_DOWN = 26; // 0x1a
|
||||
field public static final int GESTURE_2_FINGER_SWIPE_LEFT = 27; // 0x1b
|
||||
@@ -2883,6 +2884,7 @@ package android.accessibilityservice {
|
||||
field public static final int GESTURE_2_FINGER_SWIPE_UP = 25; // 0x19
|
||||
field public static final int GESTURE_2_FINGER_TRIPLE_TAP = 21; // 0x15
|
||||
field public static final int GESTURE_3_FINGER_DOUBLE_TAP = 23; // 0x17
|
||||
field public static final int GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD = 41; // 0x29
|
||||
field public static final int GESTURE_3_FINGER_SINGLE_TAP = 22; // 0x16
|
||||
field public static final int GESTURE_3_FINGER_SWIPE_DOWN = 30; // 0x1e
|
||||
field public static final int GESTURE_3_FINGER_SWIPE_LEFT = 31; // 0x1f
|
||||
@@ -2890,6 +2892,7 @@ package android.accessibilityservice {
|
||||
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_DOUBLE_TAP_AND_HOLD = 42; // 0x2a
|
||||
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
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.accessibilityservice;
|
||||
|
||||
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SINGLE_TAP;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_DOWN;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_LEFT;
|
||||
@@ -25,6 +26,7 @@ import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_UP;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_TRIPLE_TAP;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SINGLE_TAP;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_DOWN;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_LEFT;
|
||||
@@ -32,6 +34,7 @@ import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER
|
||||
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_DOUBLE_TAP_AND_HOLD;
|
||||
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;
|
||||
@@ -83,9 +86,11 @@ public final class AccessibilityGestureEvent implements Parcelable {
|
||||
@IntDef(prefix = { "GESTURE_" }, value = {
|
||||
GESTURE_2_FINGER_SINGLE_TAP,
|
||||
GESTURE_2_FINGER_DOUBLE_TAP,
|
||||
GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD,
|
||||
GESTURE_2_FINGER_TRIPLE_TAP,
|
||||
GESTURE_3_FINGER_SINGLE_TAP,
|
||||
GESTURE_3_FINGER_DOUBLE_TAP,
|
||||
GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD,
|
||||
GESTURE_3_FINGER_TRIPLE_TAP,
|
||||
GESTURE_DOUBLE_TAP,
|
||||
GESTURE_DOUBLE_TAP_AND_HOLD,
|
||||
@@ -114,6 +119,7 @@ public final class AccessibilityGestureEvent implements Parcelable {
|
||||
GESTURE_3_FINGER_SWIPE_RIGHT,
|
||||
GESTURE_3_FINGER_SWIPE_UP,
|
||||
GESTURE_4_FINGER_DOUBLE_TAP,
|
||||
GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD,
|
||||
GESTURE_4_FINGER_SINGLE_TAP,
|
||||
GESTURE_4_FINGER_SWIPE_DOWN,
|
||||
GESTURE_4_FINGER_SWIPE_LEFT,
|
||||
@@ -175,12 +181,18 @@ public final class AccessibilityGestureEvent implements Parcelable {
|
||||
switch (eventType) {
|
||||
case GESTURE_2_FINGER_SINGLE_TAP: return "GESTURE_2_FINGER_SINGLE_TAP";
|
||||
case GESTURE_2_FINGER_DOUBLE_TAP: return "GESTURE_2_FINGER_DOUBLE_TAP";
|
||||
case GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD:
|
||||
return "GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD";
|
||||
case GESTURE_2_FINGER_TRIPLE_TAP: return "GESTURE_2_FINGER_TRIPLE_TAP";
|
||||
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_DOUBLE_TAP_AND_HOLD:
|
||||
return "GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD";
|
||||
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_DOUBLE_TAP_AND_HOLD:
|
||||
return "GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD";
|
||||
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";
|
||||
|
||||
@@ -411,6 +411,15 @@ public abstract class AccessibilityService extends Service {
|
||||
/** 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 user has performed a two-finger double tap and hold gesture on the touch screen. */
|
||||
public static final int GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD = 40;
|
||||
|
||||
/** The user has performed a three-finger double tap and hold gesture on the touch screen. */
|
||||
public static final int GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD = 41;
|
||||
|
||||
/** The user has performed a two-finger double tap and hold gesture on the touch screen. */
|
||||
public static final int GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD = 42;
|
||||
|
||||
/**
|
||||
* The {@link Intent} that must be declared as handled by the service.
|
||||
*/
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.server.accessibility.gestures;
|
||||
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SINGLE_TAP;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_DOWN;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_LEFT;
|
||||
@@ -24,6 +25,7 @@ import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_UP;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_TRIPLE_TAP;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SINGLE_TAP;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_DOWN;
|
||||
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_LEFT;
|
||||
@@ -31,6 +33,7 @@ import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER
|
||||
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_DOUBLE_TAP_AND_HOLD;
|
||||
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;
|
||||
@@ -131,6 +134,9 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
|
||||
new MultiFingerMultiTap(mContext, 2, 1, GESTURE_2_FINGER_SINGLE_TAP, this));
|
||||
mMultiFingerGestures.add(
|
||||
new MultiFingerMultiTap(mContext, 2, 2, GESTURE_2_FINGER_DOUBLE_TAP, this));
|
||||
mMultiFingerGestures.add(
|
||||
new MultiFingerMultiTapAndHold(
|
||||
mContext, 2, 2, GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD, this));
|
||||
mMultiFingerGestures.add(
|
||||
new MultiFingerMultiTap(mContext, 2, 3, GESTURE_2_FINGER_TRIPLE_TAP, this));
|
||||
// Three-finger taps.
|
||||
@@ -138,6 +144,9 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
|
||||
new MultiFingerMultiTap(mContext, 3, 1, GESTURE_3_FINGER_SINGLE_TAP, this));
|
||||
mMultiFingerGestures.add(
|
||||
new MultiFingerMultiTap(mContext, 3, 2, GESTURE_3_FINGER_DOUBLE_TAP, this));
|
||||
mMultiFingerGestures.add(
|
||||
new MultiFingerMultiTapAndHold(
|
||||
mContext, 3, 2, GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD, this));
|
||||
mMultiFingerGestures.add(
|
||||
new MultiFingerMultiTap(mContext, 3, 3, GESTURE_3_FINGER_TRIPLE_TAP, this));
|
||||
// Four-finger taps.
|
||||
@@ -145,6 +154,9 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
|
||||
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 MultiFingerMultiTapAndHold(
|
||||
mContext, 4, 2, GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD, this));
|
||||
mMultiFingerGestures.add(
|
||||
new MultiFingerMultiTap(mContext, 4, 3, GESTURE_4_FINGER_TRIPLE_TAP, this));
|
||||
// Two-finger swipes.
|
||||
|
||||
@@ -42,10 +42,10 @@ class MultiFingerMultiTap extends GestureMatcher {
|
||||
// The acceptable distance the pointer can move and still count as a tap.
|
||||
private int mTouchSlop;
|
||||
// A tap counts when target number of fingers are down and up once.
|
||||
private int mCompletedTapCount;
|
||||
protected int mCompletedTapCount;
|
||||
// A flag set to true when target number of fingers have touched down at once before.
|
||||
// Used to indicate what next finger action should be. Down when false and lift when true.
|
||||
private boolean mIsTargetFingerCountReached = false;
|
||||
protected boolean mIsTargetFingerCountReached = false;
|
||||
// Store initial down points for slop checking and update when next down if is inside slop.
|
||||
private PointF[] mBases;
|
||||
// The points in bases that already have slop checked when onDown or onPointerDown.
|
||||
@@ -56,7 +56,11 @@ class MultiFingerMultiTap extends GestureMatcher {
|
||||
* @throws IllegalArgumentException if <code>fingers<code/> is less than 2
|
||||
* or <code>taps<code/> is not positive.
|
||||
*/
|
||||
MultiFingerMultiTap(Context context, int fingers, int taps, int gestureId,
|
||||
MultiFingerMultiTap(
|
||||
Context context,
|
||||
int fingers,
|
||||
int taps,
|
||||
int gestureId,
|
||||
GestureMatcher.StateChangeListener listener) {
|
||||
super(gestureId, new Handler(context.getMainLooper()), listener);
|
||||
Preconditions.checkArgument(fingers >= 2);
|
||||
@@ -117,8 +121,7 @@ class MultiFingerMultiTap extends GestureMatcher {
|
||||
cancelAfterDoubleTapTimeout(event, rawEvent, policyFlags);
|
||||
|
||||
final PointF nearest = findNearestPoint(rawEvent, mTouchSlop, false);
|
||||
if ((getState() == STATE_GESTURE_STARTED || getState() == STATE_CLEAR)
|
||||
&& null != nearest) {
|
||||
if ((getState() == STATE_GESTURE_STARTED || getState() == STATE_CLEAR) && null != nearest) {
|
||||
// Increase current tap count when the user have all fingers lifted
|
||||
// within the tap timeout since the target number of fingers are down.
|
||||
if (mIsTargetFingerCountReached) {
|
||||
@@ -169,8 +172,7 @@ class MultiFingerMultiTap extends GestureMatcher {
|
||||
} else {
|
||||
nearest = findNearestPoint(rawEvent, mDoubleTapSlop, true);
|
||||
}
|
||||
if ((getState() == STATE_GESTURE_STARTED || getState() == STATE_CLEAR)
|
||||
&& nearest != null) {
|
||||
if ((getState() == STATE_GESTURE_STARTED || getState() == STATE_CLEAR) && nearest != null) {
|
||||
// The user have all fingers down within the tap timeout since first finger down,
|
||||
// setting the timeout for fingers to be lifted.
|
||||
if (currentFingerCount == mTargetFingerCount) {
|
||||
@@ -227,11 +229,11 @@ class MultiFingerMultiTap extends GestureMatcher {
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the nearest location to the given event in the bases.
|
||||
* If no one found, it could be not inside {@code slop}, filtered or empty bases.
|
||||
* When {@code filterMatched} is true, if the location of given event matches one of the points
|
||||
* in {@link #mExcludedPointsForDownSlopChecked} it would be ignored. Otherwise, the location
|
||||
* will be added to {@link #mExcludedPointsForDownSlopChecked}.
|
||||
* Find the nearest location to the given event in the bases. If no one found, it could be not
|
||||
* inside {@code slop}, filtered or empty bases. When {@code filterMatched} is true, if the
|
||||
* location of given event matches one of the points in {@link
|
||||
* #mExcludedPointsForDownSlopChecked} it would be ignored. Otherwise, the location will be
|
||||
* added to {@link #mExcludedPointsForDownSlopChecked}.
|
||||
*
|
||||
* @param event to find nearest point in bases.
|
||||
* @param slop to check to the given location of the event.
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.accessibility.gestures;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
/**
|
||||
* This class matches gestures of the form multi-finger multi-tap and hold. The number of fingers
|
||||
* and taps for each instance is specified in the constructor.
|
||||
*/
|
||||
class MultiFingerMultiTapAndHold extends MultiFingerMultiTap {
|
||||
|
||||
MultiFingerMultiTapAndHold(
|
||||
Context context,
|
||||
int fingers,
|
||||
int taps,
|
||||
int gestureId,
|
||||
GestureMatcher.StateChangeListener listener) {
|
||||
super(context, fingers, taps, gestureId, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPointerDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
|
||||
super.onPointerDown(event, rawEvent, policyFlags);
|
||||
if (mIsTargetFingerCountReached && mCompletedTapCount + 1 == mTargetTapCount) {
|
||||
completeAfterLongPressTimeout(event, rawEvent, policyFlags);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
|
||||
if (mCompletedTapCount + 1 == mTargetFingerCount) {
|
||||
// Calling super.onUp would complete the multi-tap version of this.
|
||||
cancelGesture(event, rawEvent, policyFlags);
|
||||
} else {
|
||||
super.onUp(event, rawEvent, policyFlags);
|
||||
cancelAfterDoubleTapTimeout(event, rawEvent, policyFlags);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGestureName() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append(mTargetFingerCount).append("-Finger ");
|
||||
if (mTargetTapCount == 1) {
|
||||
builder.append("Single");
|
||||
} else if (mTargetTapCount == 2) {
|
||||
builder.append("Double");
|
||||
} else if (mTargetTapCount == 3) {
|
||||
builder.append("Triple");
|
||||
} else if (mTargetTapCount > 3) {
|
||||
builder.append(mTargetTapCount);
|
||||
}
|
||||
return builder.append(" Tap and hold").toString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user