summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt3
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java2
-rw-r--r--core/java/android/accessibilityservice/AccessibilityServiceInfo.java12
-rw-r--r--core/java/android/view/accessibility/AccessibilityManager.java3
-rw-r--r--core/res/res/values/attrs.xml2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java8
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java20
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java16
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java13
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java45
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/MultiTap.java7
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java19
12 files changed, 128 insertions, 22 deletions
diff --git a/api/current.txt b/api/current.txt
index 1cfc99acca32..b2c8061b9778 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2873,6 +2873,8 @@ package android.accessibilityservice {
method public final boolean performGlobalAction(int);
method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
method public boolean takeScreenshot(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.graphics.Bitmap>);
+ 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
field public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 15; // 0xf
field public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 16; // 0x10
@@ -2989,6 +2991,7 @@ package android.accessibilityservice {
field public static final int FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK = 1024; // 0x400
field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
field public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 64; // 0x40
+ field public static final int FLAG_SERVICE_HANDLES_DOUBLE_TAP = 2048; // 0x800
field public int eventTypes;
field public int feedbackType;
field public int flags;
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index ee6ccc2f5cd7..7722dc318fd7 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -310,13 +310,11 @@ public abstract class AccessibilityService extends Service {
/**
* The user has performed a double tap gesture on the touch screen.
- * @hide
*/
public static final int GESTURE_DOUBLE_TAP = 17;
/**
* The user has performed a double tap and hold gesture on the touch screen.
- * @hide
*/
public static final int GESTURE_DOUBLE_TAP_AND_HOLD = 18;
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 12f2c3b17c96..342b6a5ba7e0 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -341,6 +341,16 @@ public class AccessibilityServiceInfo implements Parcelable {
*/
public static final int FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK = 0x00000400;
+ /**
+ * This flag requests that when {@link #FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled,
+ * double tap and double tap and hold gestures are dispatched to the service rather than being
+ * handled by the framework. If {@link #FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is disabled this
+ * flag has no effect.
+ *
+ * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE
+ */
+ public static final int FLAG_SERVICE_HANDLES_DOUBLE_TAP = 0x0000800;
+
/** {@hide} */
public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
@@ -1221,6 +1231,8 @@ public class AccessibilityServiceInfo implements Parcelable {
return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS";
case FLAG_REQUEST_TOUCH_EXPLORATION_MODE:
return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE";
+ case FLAG_SERVICE_HANDLES_DOUBLE_TAP:
+ return "FLAG_SERVICE_HANDLES_DOUBLE_TAP";
case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
case FLAG_REPORT_VIEW_IDS:
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 9cbba87e6856..4b49d67fe44d 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -102,6 +102,9 @@ public final class AccessibilityManager {
public static final int STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED = 0x00000004;
/** @hide */
+ public static final int STATE_FLAG_DISPATCH_DOUBLE_TAP = 0x00000008;
+
+ /** @hide */
public static final int DALTONIZER_DISABLED = -1;
/** @hide */
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index c9c47b92f782..643a6ff98c1c 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3714,6 +3714,8 @@
<flag name="flagRequestFingerprintGestures" value="0x00000200" />
<!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK}. -->
<flag name="flagRequestShortcutWarningDialogSpokenFeedback" value="0x00000400" />
+ <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_SERVICE_HANDLES_DOUBLE_TAP}. -->
+ <flag name="flagServiceHandlesDoubleTap" value="0x00000800" />
</attr>
<!-- Component name of an activity that allows the user to modify
the settings for this service. This setting cannot be changed at runtime. -->
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 3e74b7a92f5d..a79ddce73004 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -134,6 +134,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
boolean mRequestTouchExplorationMode;
+ private boolean mServiceHandlesDoubleTap;
+
boolean mRequestFilterKeyEvents;
boolean mRetrieveInteractiveWindows;
@@ -298,6 +300,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
mRequestTouchExplorationMode = (info.flags
& AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
+ mServiceHandlesDoubleTap = (info.flags
+ & AccessibilityServiceInfo.FLAG_SERVICE_HANDLES_DOUBLE_TAP) != 0;
mRequestFilterKeyEvents = (info.flags
& AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0;
mRetrieveInteractiveWindows = (info.flags
@@ -1689,4 +1693,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
msg.sendToTarget();
}
}
+
+ public boolean isServiceHandlesDoubleTapEnabled() {
+ return mServiceHandlesDoubleTap;
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 49582a97b890..ee976785be20 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -99,9 +99,20 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
*/
static final int FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER = 0x00000040;
- static final int FEATURES_AFFECTING_MOTION_EVENTS = FLAG_FEATURE_INJECT_MOTION_EVENTS
- | FLAG_FEATURE_AUTOCLICK | FLAG_FEATURE_TOUCH_EXPLORATION
- | FLAG_FEATURE_SCREEN_MAGNIFIER | FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER;
+ /**
+ * Flag for dispatching double tap and double tap and hold to the service.
+ *
+ * @see #setUserAndEnabledFeatures(int, int)
+ */
+ static final int FLAG_SERVICE_HANDLES_DOUBLE_TAP = 0x00000080;
+
+ static final int FEATURES_AFFECTING_MOTION_EVENTS =
+ FLAG_FEATURE_INJECT_MOTION_EVENTS
+ | FLAG_FEATURE_AUTOCLICK
+ | FLAG_FEATURE_TOUCH_EXPLORATION
+ | FLAG_FEATURE_SCREEN_MAGNIFIER
+ | FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER
+ | FLAG_SERVICE_HANDLES_DOUBLE_TAP;
private final Context mContext;
@@ -391,6 +402,9 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
if ((mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) {
TouchExplorer explorer = new TouchExplorer(displayContext, mAms);
+ if ((mEnabledFeatures & FLAG_SERVICE_HANDLES_DOUBLE_TAP) != 0) {
+ explorer.setServiceHandlesDoubleTap(true);
+ }
addFirstEventHandler(displayId, explorer);
mTouchExplorer.put(displayId, explorer);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index bcaecea4c388..560a8ef75c33 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1610,6 +1610,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (userState.isHandlingAccessibilityEventsLocked()
&& userState.isTouchExplorationEnabledLocked()) {
flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
+ if (userState.isServiceHandlesDoubleTapEnabledLocked()) {
+ flags |= AccessibilityInputFilter.FLAG_SERVICE_HANDLES_DOUBLE_TAP;
+ }
}
if (userState.isFilterKeyEventsEnabledLocked()) {
flags |= AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS;
@@ -1882,21 +1885,24 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
private void updateTouchExplorationLocked(AccessibilityUserState userState) {
- boolean enabled = mUiAutomationManager.isTouchExplorationEnabledLocked();
+ boolean touchExplorationEnabled = mUiAutomationManager.isTouchExplorationEnabledLocked();
+ boolean serviceHandlesDoubleTapEnabled = false;
final int serviceCount = userState.mBoundServices.size();
for (int i = 0; i < serviceCount; i++) {
AccessibilityServiceConnection service = userState.mBoundServices.get(i);
if (canRequestAndRequestsTouchExplorationLocked(service, userState)) {
- enabled = true;
+ touchExplorationEnabled = true;
+ serviceHandlesDoubleTapEnabled = service.isServiceHandlesDoubleTapEnabled();
break;
}
}
- if (enabled != userState.isTouchExplorationEnabledLocked()) {
- userState.setTouchExplorationEnabledLocked(enabled);
+ if (touchExplorationEnabled != userState.isTouchExplorationEnabledLocked()) {
+ userState.setTouchExplorationEnabledLocked(touchExplorationEnabled);
+ userState.setServiceHandlesDoubleTapLocked(serviceHandlesDoubleTapEnabled);
final long identity = Binder.clearCallingIdentity();
try {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.TOUCH_EXPLORATION_ENABLED, enabled ? 1 : 0,
+ Settings.Secure.TOUCH_EXPLORATION_ENABLED, touchExplorationEnabled ? 1 : 0,
userState.mUserId);
} finally {
Binder.restoreCallingIdentity(identity);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index ebe2af62b5db..49b11583c4ab 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -103,6 +103,7 @@ class AccessibilityUserState {
private boolean mIsPerformGesturesEnabled;
private boolean mIsTextHighContrastEnabled;
private boolean mIsTouchExplorationEnabled;
+ private boolean mServiceHandlesDoubleTap;
private int mUserInteractiveUiTimeout;
private int mUserNonInteractiveUiTimeout;
private int mNonInteractiveUiTimeout = 0;
@@ -151,6 +152,7 @@ class AccessibilityUserState {
mAccessibilityShortcutKeyTargets.clear();
mAccessibilityButtonTargets.clear();
mIsTouchExplorationEnabled = false;
+ mServiceHandlesDoubleTap = false;
mIsDisplayMagnificationEnabled = false;
mIsAutoclickEnabled = false;
mUserNonInteractiveUiTimeout = 0;
@@ -351,6 +353,7 @@ class AccessibilityUserState {
// Touch exploration relies on enabled accessibility.
if (a11yEnabled && mIsTouchExplorationEnabled) {
clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
+ clientState |= AccessibilityManager.STATE_FLAG_DISPATCH_DOUBLE_TAP;
}
if (mIsTextHighContrastEnabled) {
clientState |= AccessibilityManager.STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED;
@@ -431,6 +434,8 @@ class AccessibilityUserState {
pw.println();
pw.append(" attributes:{id=").append(String.valueOf(mUserId));
pw.append(", touchExplorationEnabled=").append(String.valueOf(mIsTouchExplorationEnabled));
+ pw.append(", serviceHandlesDoubleTap=")
+ .append(String.valueOf(mServiceHandlesDoubleTap));
pw.append(", displayMagnificationEnabled=").append(String.valueOf(
mIsDisplayMagnificationEnabled));
pw.append(", autoclickEnabled=").append(String.valueOf(mIsAutoclickEnabled));
@@ -675,6 +680,14 @@ class AccessibilityUserState {
mIsTouchExplorationEnabled = enabled;
}
+ public boolean isServiceHandlesDoubleTapEnabledLocked() {
+ return mServiceHandlesDoubleTap;
+ }
+
+ public void setServiceHandlesDoubleTapLocked(boolean enabled) {
+ mServiceHandlesDoubleTap = enabled;
+ }
+
public int getUserInteractiveUiTimeoutLocked() {
return mUserInteractiveUiTimeout;
}
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 50d21ba59996..9afcf8dda437 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
@@ -65,6 +65,8 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
private final Handler mHandler;
// Listener to be notified of gesture start and end.
private Listener mListener;
+ // Whether enhanced touch exploration mode is enabled.
+ private boolean mServiceHandlesDoubleTap = false;
// Shared state information.
private TouchState mState;
@@ -154,18 +156,23 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
*/
public interface Listener {
/**
- * Called when the user has performed a double tap and then held down the second tap.
+ * When FLAG_SERVICE_HANDLES_DOUBLE_TAP is enabled, this method is not called; double-tap
+ * and hold is dispatched via onGestureCompleted. Otherwise, this method is called when the
+ * user has performed a double tap and then held down the second tap.
*/
void onDoubleTapAndHold();
/**
- * Called when the user lifts their finger on the second tap of a double tap.
+ * When FLAG_SERVICE_HANDLES_DOUBLE_TAP is enabled, this method is not called; double-tap is
+ * dispatched via onGestureCompleted. Otherwise, this method is called when the user lifts
+ * their finger on the second tap of a double tap.
+ *
* @return true if the event is consumed, else false
*/
boolean onDoubleTap();
/**
- * Called when the system has decided the event stream is a gesture.
+ * Called when the system has decided the event stream is a potential gesture.
*
* @return true if the event is consumed, else false
*/
@@ -193,7 +200,13 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
public void onStateChanged(
int gestureId, int state, MotionEvent event, MotionEvent rawEvent, int policyFlags) {
if (state == GestureMatcher.STATE_GESTURE_STARTED && !mState.isGestureDetecting()) {
- mListener.onGestureStarted();
+ if (gestureId == GESTURE_DOUBLE_TAP || gestureId == GESTURE_DOUBLE_TAP_AND_HOLD) {
+ if (mServiceHandlesDoubleTap) {
+ mListener.onGestureStarted();
+ }
+ } else {
+ mListener.onGestureStarted();
+ }
} else if (state == GestureMatcher.STATE_GESTURE_COMPLETED) {
onGestureCompleted(gestureId);
} else if (state == GestureMatcher.STATE_GESTURE_CANCELED && mState.isGestureDetecting()) {
@@ -217,11 +230,23 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
// Gestures that complete on a delay call clear() here.
switch (gestureId) {
case GESTURE_DOUBLE_TAP:
- mListener.onDoubleTap();
+ if (mServiceHandlesDoubleTap) {
+ AccessibilityGestureEvent gestureEvent =
+ new AccessibilityGestureEvent(gestureId, event.getDisplayId());
+ mListener.onGestureCompleted(gestureEvent);
+ } else {
+ mListener.onDoubleTap();
+ }
clear();
break;
case GESTURE_DOUBLE_TAP_AND_HOLD:
- mListener.onDoubleTapAndHold();
+ if (mServiceHandlesDoubleTap) {
+ AccessibilityGestureEvent gestureEvent =
+ new AccessibilityGestureEvent(gestureId, event.getDisplayId());
+ mListener.onGestureCompleted(gestureEvent);
+ } else {
+ mListener.onDoubleTapAndHold();
+ }
clear();
break;
default:
@@ -231,4 +256,12 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
break;
}
}
+
+ public boolean isServiceHandlesDoubleTapEnabled() {
+ return mServiceHandlesDoubleTap;
+ }
+
+ public void setServiceHandlesDoubleTap(boolean mode) {
+ mServiceHandlesDoubleTap = mode;
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiTap.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiTap.java
index 4c9e590592fe..386cb0636cc2 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiTap.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiTap.java
@@ -70,6 +70,13 @@ class MultiTap extends GestureMatcher {
}
mBaseX = event.getX();
mBaseY = event.getY();
+ if (mCurrentTaps + 1 == mTargetTaps) {
+ // Start gesture detecting on down of final tap.
+ // Note that if this instance is matching double tap,
+ // and the service is not requesting to handle double tap, GestureManifold will
+ // ignore this.
+ startGesture(event, rawEvent, policyFlags);
+ }
}
@Override
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index ba890c5ee41d..caf142420dd6 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -254,7 +254,10 @@ public class TouchExplorer extends BaseEventStreamTransformation
} else if (mState.isDelegating()) {
handleMotionEventStateDelegating(event, rawEvent, policyFlags);
} else if (mState.isGestureDetecting()) {
- // Already handled.
+ // Make sure we don't prematurely get TOUCH_INTERACTION_END
+ // It will be delivered on gesture completion or cancelation.
+ // Note that the delay for sending GESTURE_DETECTION_END remains in place.
+ mSendTouchInteractionEndDelayed.cancel();
} else {
Slog.e(LOG_TAG, "Illegal state: " + mState);
clear(event, policyFlags);
@@ -331,12 +334,8 @@ public class TouchExplorer extends BaseEventStreamTransformation
@Override
public boolean onGestureCompleted(AccessibilityGestureEvent gestureEvent) {
- if (!mState.isGestureDetecting()) {
- return false;
- }
-
endGestureDetection(true);
-
+ mSendTouchInteractionEndDelayed.cancel();
mAms.onGesture(gestureEvent);
return true;
@@ -875,6 +874,14 @@ public class TouchExplorer extends BaseEventStreamTransformation
}
/**
+ * Whether to dispatch double tap and double tap and hold to the service rather than handle them
+ * in the framework.
+ */
+ public void setServiceHandlesDoubleTap(boolean mode) {
+ mGestureDetector.setServiceHandlesDoubleTap(mode);
+ }
+
+ /**
* Class for delayed exiting from gesture detecting mode.
*/
private final class ExitGestureDetectionModeDelayed implements Runnable {