Merge "Add API to record touch interactions."

This commit is contained in:
Ameer Armaly
2020-10-21 00:02:43 +00:00
committed by Android (Google) Code Review
12 changed files with 250 additions and 13 deletions

View File

@@ -2851,6 +2851,7 @@ package android.accessibilityservice {
method public int describeContents();
method public int getDisplayId();
method public int getGestureId();
method @NonNull public java.util.List<android.view.MotionEvent> getMotionEvents();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.accessibilityservice.AccessibilityGestureEvent> CREATOR;
}
@@ -2932,6 +2933,7 @@ package android.accessibilityservice {
field public static final int GESTURE_SWIPE_UP_AND_DOWN = 7; // 0x7
field public static final int GESTURE_SWIPE_UP_AND_LEFT = 13; // 0xd
field public static final int GESTURE_SWIPE_UP_AND_RIGHT = 14; // 0xe
field public static final int GESTURE_UNKNOWN = 0; // 0x0
field public static final int GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS = 14; // 0xe
field public static final int GLOBAL_ACTION_ACCESSIBILITY_BUTTON = 11; // 0xb
field public static final int GLOBAL_ACTION_ACCESSIBILITY_BUTTON_CHOOSER = 12; // 0xc
@@ -3047,6 +3049,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_SEND_MOTION_EVENTS = 16384; // 0x4000
field public static final int FLAG_SERVICE_HANDLES_DOUBLE_TAP = 2048; // 0x800
field public int eventTypes;
field public int feedbackType;

View File

@@ -46,6 +46,7 @@ import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER
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_PASSTHROUGH;
import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN;
import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN_AND_LEFT;
import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_DOWN_AND_RIGHT;
@@ -62,15 +63,21 @@ import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_UP
import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_UP_AND_DOWN;
import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_UP_AND_LEFT;
import static android.accessibilityservice.AccessibilityService.GESTURE_SWIPE_UP_AND_RIGHT;
import static android.accessibilityservice.AccessibilityService.GESTURE_TOUCH_EXPLORATION;
import static android.accessibilityservice.AccessibilityService.GESTURE_UNKNOWN;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.content.pm.ParceledListSlice;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.MotionEvent;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
/**
* This class describes the gesture event including gesture id and which display it happens
@@ -87,6 +94,8 @@ public final class AccessibilityGestureEvent implements Parcelable {
/** @hide */
@IntDef(prefix = { "GESTURE_" }, value = {
GESTURE_UNKNOWN,
GESTURE_TOUCH_EXPLORATION,
GESTURE_2_FINGER_SINGLE_TAP,
GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD,
GESTURE_2_FINGER_DOUBLE_TAP,
@@ -139,17 +148,27 @@ public final class AccessibilityGestureEvent implements Parcelable {
@GestureId
private final int mGestureId;
private final int mDisplayId;
private List<MotionEvent> mMotionEvents = new ArrayList<>();
/** @hide */
public AccessibilityGestureEvent(
int gestureId, int displayId, @NonNull List<MotionEvent> motionEvents) {
mGestureId = gestureId;
mDisplayId = displayId;
mMotionEvents.addAll(motionEvents);
}
/** @hide */
@TestApi
public AccessibilityGestureEvent(int gestureId, int displayId) {
mGestureId = gestureId;
mDisplayId = displayId;
this(gestureId, displayId, new ArrayList<MotionEvent>());
}
private AccessibilityGestureEvent(@NonNull Parcel parcel) {
mGestureId = parcel.readInt();
mDisplayId = parcel.readInt();
ParceledListSlice<MotionEvent> slice = parcel.readParcelable(getClass().getClassLoader());
mMotionEvents = slice.getList();
}
/**
@@ -172,6 +191,15 @@ public final class AccessibilityGestureEvent implements Parcelable {
return mGestureId;
}
/**
* Returns the motion events that lead to this gesture.
*
*/
@NonNull
public List<MotionEvent> getMotionEvents() {
return mMotionEvents;
}
@NonNull
@Override
public String toString() {
@@ -179,12 +207,26 @@ public final class AccessibilityGestureEvent implements Parcelable {
stringBuilder.append("gestureId: ").append(eventTypeToString(mGestureId));
stringBuilder.append(", ");
stringBuilder.append("displayId: ").append(mDisplayId);
stringBuilder.append(", ");
stringBuilder.append("Motion Events: [");
for (int i = 0; i < mMotionEvents.size(); ++i) {
String action = MotionEvent.actionToString(mMotionEvents.get(i).getActionMasked());
stringBuilder.append(action);
if (i < (mMotionEvents.size() - 1)) {
stringBuilder.append(", ");
} else {
stringBuilder.append("]");
}
}
stringBuilder.append(']');
return stringBuilder.toString();
}
private static String eventTypeToString(int eventType) {
switch (eventType) {
case GESTURE_UNKNOWN: return "GESTURE_UNKNOWN";
case GESTURE_PASSTHROUGH: return "GESTURE_PASSTHROUGH";
case GESTURE_TOUCH_EXPLORATION: return "GESTURE_TOUCH_EXPLORATION";
case GESTURE_2_FINGER_SINGLE_TAP: return "GESTURE_2_FINGER_SINGLE_TAP";
case GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD:
return "GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD";
@@ -252,6 +294,7 @@ public final class AccessibilityGestureEvent implements Parcelable {
public void writeToParcel(@NonNull Parcel parcel, int flags) {
parcel.writeInt(mGestureId);
parcel.writeInt(mDisplayId);
parcel.writeParcelable(new ParceledListSlice<MotionEvent>(mMotionEvents), 0);
}
/**

View File

@@ -234,6 +234,29 @@ import java.util.function.Consumer;
*/
public abstract class AccessibilityService extends Service {
/**
* The user has performed a touch-exploration gesture on the touch screen without ever
* triggering gesture detection. This gesture is only dispatched when {@link
* AccessibilityServiceInfo#FLAG_SEND_MOTION_EVENTS} is set.
*
* @hide
*/
public static final int GESTURE_TOUCH_EXPLORATION = -2;
/**
* The user has performed a passthrough gesture on the touch screen without ever triggering
* gesture detection. This gesture is only dispatched when {@link
* AccessibilityServiceInfo#FLAG_SEND_MOTION_EVENTS} is set.
* @hide
*/
public static final int GESTURE_PASSTHROUGH = -1;
/**
* The user has performed an unrecognized gesture on the touch screen. This gesture is only
* dispatched when {@link AccessibilityServiceInfo#FLAG_SEND_MOTION_EVENTS} is set.
*/
public static final int GESTURE_UNKNOWN = 0;
/**
* The user has performed a swipe up gesture on the touch screen.
*/

View File

@@ -376,6 +376,20 @@ public class AccessibilityServiceInfo implements Parcelable {
*/
public static final int FLAG_REQUEST_2_FINGER_PASSTHROUGH = 0x0002000;
/**
* This flag requests that when when {@link #FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled, a
* service will receive the motion events for each successfully-detected gesture. The service
* will also receive an AccessibilityGestureEvent of type GESTURE_INVALID for each cancelled
* gesture along with its motion events. A service will receive a gesture of type
* GESTURE_PASSTHROUGH and accompanying motion events for every passthrough gesture that does
* not start gesture detection. This information can be used to collect instances of improper
* gesture detection behavior and relay that information to framework developers. 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_SEND_MOTION_EVENTS = 0x0004000;
/** {@hide} */
public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
@@ -1276,6 +1290,8 @@ public class AccessibilityServiceInfo implements Parcelable {
return "FLAG_REQUEST_MULTI_FINGER_GESTURES";
case FLAG_REQUEST_2_FINGER_PASSTHROUGH:
return "FLAG_REQUEST_2_FINGER_PASSTHROUGH";
case FLAG_SEND_MOTION_EVENTS:
return "FLAG_SEND_MOTION_EVENTS";
case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
case FLAG_REPORT_VIEW_IDS:

View File

@@ -3748,6 +3748,7 @@
<flag name="flagServiceHandlesDoubleTap" value="0x00000800" />
<!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_MULTI_FINGER_GESTURES}. -->
<flag name="flagRequestMultiFingerGestures" value="0x00001000" />
<flag name="flagSendMotionEvents" value="0x0004000" />
</attr>
<!-- Component name of an activity that allows the user to modify
the settings for this service. This setting cannot be changed at runtime. -->

View File

@@ -2851,6 +2851,7 @@ package android.accessibilityservice {
method public int describeContents();
method public int getDisplayId();
method public int getGestureId();
method @NonNull public java.util.List<android.view.MotionEvent> getMotionEvents();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.accessibilityservice.AccessibilityGestureEvent> CREATOR;
}
@@ -2932,6 +2933,7 @@ package android.accessibilityservice {
field public static final int GESTURE_SWIPE_UP_AND_DOWN = 7; // 0x7
field public static final int GESTURE_SWIPE_UP_AND_LEFT = 13; // 0xd
field public static final int GESTURE_SWIPE_UP_AND_RIGHT = 14; // 0xe
field public static final int GESTURE_UNKNOWN = 0; // 0x0
field public static final int GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS = 14; // 0xe
field public static final int GLOBAL_ACTION_ACCESSIBILITY_BUTTON = 11; // 0xb
field public static final int GLOBAL_ACTION_ACCESSIBILITY_BUTTON_CHOOSER = 12; // 0xc
@@ -3047,6 +3049,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_SEND_MOTION_EVENTS = 16384; // 0x4000
field public static final int FLAG_SERVICE_HANDLES_DOUBLE_TAP = 2048; // 0x800
field public int eventTypes;
field public int feedbackType;

View File

@@ -150,6 +150,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
private boolean mRequestTwoFingerPassthrough;
private boolean mSendMotionEvents;
boolean mRequestFilterKeyEvents;
boolean mRetrieveInteractiveWindows;
@@ -329,6 +331,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
& AccessibilityServiceInfo.FLAG_REQUEST_MULTI_FINGER_GESTURES) != 0;
mRequestTwoFingerPassthrough =
(info.flags & AccessibilityServiceInfo.FLAG_REQUEST_2_FINGER_PASSTHROUGH) != 0;
mSendMotionEvents =
(info.flags & AccessibilityServiceInfo.FLAG_SEND_MOTION_EVENTS) != 0;
mRequestFilterKeyEvents =
(info.flags & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0;
mRetrieveInteractiveWindows = (info.flags
@@ -1780,6 +1784,10 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
return mRequestTwoFingerPassthrough;
}
public boolean isSendMotionEventsEnabled() {
return mSendMotionEvents;
}
@Override
public void setGestureDetectionPassthroughRegion(int displayId, Region region) {
mSystemSupport.setGestureDetectionPassthroughRegion(displayId, region);

View File

@@ -119,12 +119,19 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
static final int FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x00000100;
/**
* Flag for enabling multi-finger gestures.
* Flag for enabling two-finger passthrough when multi-finger gestures are enabled.
*
* @see #setUserAndEnabledFeatures(int, int)
*/
static final int FLAG_REQUEST_2_FINGER_PASSTHROUGH = 0x00000200;
/**
* Flag for including motion events when dispatching a gesture.
*
* @see #setUserAndEnabledFeatures(int, int)
*/
static final int FLAG_SEND_MOTION_EVENTS = 0x00000400;
static final int FEATURES_AFFECTING_MOTION_EVENTS =
FLAG_FEATURE_INJECT_MOTION_EVENTS
| FLAG_FEATURE_AUTOCLICK
@@ -432,6 +439,9 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
if ((mEnabledFeatures & FLAG_REQUEST_2_FINGER_PASSTHROUGH) != 0) {
explorer.setTwoFingerPassthroughEnabled(true);
}
if ((mEnabledFeatures & FLAG_SEND_MOTION_EVENTS) != 0) {
explorer.setSendMotionEventsEnabled(true);
}
addFirstEventHandler(displayId, explorer);
mTouchExplorer.put(displayId, explorer);
}

View File

@@ -1867,6 +1867,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (userState.isFilterKeyEventsEnabledLocked()) {
flags |= AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS;
}
if (userState.isSendMotionEventsEnabled()) {
flags |= AccessibilityInputFilter.FLAG_SEND_MOTION_EVENTS;
}
if (userState.isAutoclickEnabledLocked()) {
flags |= AccessibilityInputFilter.FLAG_FEATURE_AUTOCLICK;
}
@@ -2147,6 +2151,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
boolean serviceHandlesDoubleTapEnabled = false;
boolean requestMultiFingerGestures = false;
boolean requestTwoFingerPassthrough = false;
boolean sendMotionEvents = false;
final int serviceCount = userState.mBoundServices.size();
for (int i = 0; i < serviceCount; i++) {
AccessibilityServiceConnection service = userState.mBoundServices.get(i);
@@ -2155,6 +2160,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
serviceHandlesDoubleTapEnabled = service.isServiceHandlesDoubleTapEnabled();
requestMultiFingerGestures = service.isMultiFingerGesturesEnabled();
requestTwoFingerPassthrough = service.isTwoFingerPassthroughEnabled();
sendMotionEvents = service.isSendMotionEventsEnabled();
break;
}
}
@@ -2172,6 +2178,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
userState.setServiceHandlesDoubleTapLocked(serviceHandlesDoubleTapEnabled);
userState.setMultiFingerGesturesLocked(requestMultiFingerGestures);
userState.setTwoFingerPassthroughLocked(requestTwoFingerPassthrough);
userState.setSendMotionEventsEnabled(sendMotionEvents);
}
private boolean readAccessibilityShortcutKeySettingLocked(AccessibilityUserState userState) {

View File

@@ -111,6 +111,7 @@ class AccessibilityUserState {
private boolean mServiceHandlesDoubleTap;
private boolean mRequestMultiFingerGestures;
private boolean mRequestTwoFingerPassthrough;
private boolean mSendMotionEventsEnabled;
private int mUserInteractiveUiTimeout;
private int mUserNonInteractiveUiTimeout;
private int mNonInteractiveUiTimeout = 0;
@@ -171,6 +172,7 @@ class AccessibilityUserState {
mServiceHandlesDoubleTap = false;
mRequestMultiFingerGestures = false;
mRequestTwoFingerPassthrough = false;
mSendMotionEventsEnabled = false;
mIsDisplayMagnificationEnabled = false;
mIsAutoclickEnabled = false;
mUserNonInteractiveUiTimeout = 0;
@@ -460,6 +462,7 @@ class AccessibilityUserState {
.append(String.valueOf(mRequestMultiFingerGestures));
pw.append(", requestTwoFingerPassthrough=")
.append(String.valueOf(mRequestTwoFingerPassthrough));
pw.append(", sendMotionEventsEnabled").append(String.valueOf(mSendMotionEventsEnabled));
pw.append(", displayMagnificationEnabled=").append(String.valueOf(
mIsDisplayMagnificationEnabled));
pw.append(", autoclickEnabled=").append(String.valueOf(mIsAutoclickEnabled));
@@ -802,6 +805,13 @@ class AccessibilityUserState {
mRequestTwoFingerPassthrough = enabled;
}
public boolean isSendMotionEventsEnabled() {
return mSendMotionEventsEnabled;
}
public void setSendMotionEventsEnabled(boolean mode) {
mSendMotionEventsEnabled = mode;
}
public int getUserInteractiveUiTimeoutLocked() {
return mUserInteractiveUiTimeout;

View File

@@ -99,11 +99,15 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
boolean mMultiFingerGesturesEnabled;
// Whether the two-finger passthrough is enabled when multi-finger gestures are enabled.
private boolean mTwoFingerPassthroughEnabled;
// Whether to send the motion events during gesture dispatch.
private boolean mSendMotionEventsEnabled = false;
// A list of all the multi-finger gestures, for easy adding and removal.
private final List<GestureMatcher> mMultiFingerGestures = new ArrayList<>();
// A list of two-finger swipes, for easy adding and removal when turning on or off two-finger
// passthrough.
private final List<GestureMatcher> mTwoFingerSwipes = new ArrayList<>();
// The list of motion events for the current gesture.
private List<MotionEvent> mEvents = new ArrayList<>();
// Shared state information.
private TouchState mState;
@@ -230,6 +234,9 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
return false;
}
}
if (mSendMotionEventsEnabled) {
mEvents.add(MotionEvent.obtainNoHistory(rawEvent));
}
for (GestureMatcher matcher : mGestures) {
if (matcher.getState() != GestureMatcher.STATE_GESTURE_CANCELED) {
if (DEBUG) {
@@ -240,9 +247,8 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
Slog.d(LOG_TAG, matcher.toString());
}
if (matcher.getState() == GestureMatcher.STATE_GESTURE_COMPLETED) {
// Here we just clear and return. The actual gesture dispatch is done in
// Here we just return. The actual gesture dispatch is done in
// onStateChanged().
clear();
// No need to process this event any further.
return true;
}
@@ -255,6 +261,11 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
for (GestureMatcher matcher : mGestures) {
matcher.clear();
}
if (mEvents != null) {
while (mEvents.size() > 0) {
mEvents.remove(0).recycle();
}
}
}
/**
@@ -340,29 +351,28 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
case GESTURE_DOUBLE_TAP:
if (mServiceHandlesDoubleTap) {
AccessibilityGestureEvent gestureEvent =
new AccessibilityGestureEvent(gestureId, event.getDisplayId());
new AccessibilityGestureEvent(gestureId, event.getDisplayId(), mEvents);
mListener.onGestureCompleted(gestureEvent);
} else {
mListener.onDoubleTap(event, rawEvent, policyFlags);
}
clear();
break;
case GESTURE_DOUBLE_TAP_AND_HOLD:
if (mServiceHandlesDoubleTap) {
AccessibilityGestureEvent gestureEvent =
new AccessibilityGestureEvent(gestureId, event.getDisplayId());
new AccessibilityGestureEvent(gestureId, event.getDisplayId(), mEvents);
mListener.onGestureCompleted(gestureEvent);
} else {
mListener.onDoubleTapAndHold(event, rawEvent, policyFlags);
}
clear();
break;
default:
AccessibilityGestureEvent gestureEvent =
new AccessibilityGestureEvent(gestureId, event.getDisplayId());
new AccessibilityGestureEvent(gestureId, event.getDisplayId(), mEvents);
mListener.onGestureCompleted(gestureEvent);
break;
}
clear();
}
public boolean isMultiFingerGesturesEnabled() {
@@ -406,4 +416,25 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
public boolean isServiceHandlesDoubleTapEnabled() {
return mServiceHandlesDoubleTap;
}
public void setSendMotionEventsEnabled(boolean mode) {
mSendMotionEventsEnabled = mode;
if (!mode) {
while (mEvents.size() > 0) {
mEvents.remove(0).recycle();
}
}
}
public boolean isSendMotionEventsEnabled() {
return mSendMotionEventsEnabled;
}
/**
* Returns the current list of motion events. It is the caller's responsibility to copy the list
* if they want it to persist after a call to clear().
*/
public List<MotionEvent> getMotionEvents() {
return mEvents;
}
}

View File

@@ -37,6 +37,7 @@ import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
import static com.android.server.accessibility.gestures.TouchState.ALL_POINTER_ID_BITS;
import android.accessibilityservice.AccessibilityGestureEvent;
import android.accessibilityservice.AccessibilityService;
import android.annotation.NonNull;
import android.content.Context;
import android.graphics.Region;
@@ -340,6 +341,14 @@ public class TouchExplorer extends BaseEventStreamTransformation
public void onDoubleTapAndHold(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
if (mDispatcher.longPressWithTouchEvents(event, policyFlags)) {
sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
if (isSendMotionEventsEnabled()) {
AccessibilityGestureEvent gestureEvent =
new AccessibilityGestureEvent(
AccessibilityService.GESTURE_DOUBLE_TAP_AND_HOLD,
event.getDisplayId(),
mGestureDetector.getMotionEvents());
mAms.onGesture(gestureEvent);
}
mState.startDelegating();
}
}
@@ -350,7 +359,14 @@ public class TouchExplorer extends BaseEventStreamTransformation
// Remove pending event deliveries.
mSendHoverEnterAndMoveDelayed.cancel();
mSendHoverExitDelayed.cancel();
if (isSendMotionEventsEnabled()) {
AccessibilityGestureEvent gestureEvent =
new AccessibilityGestureEvent(
AccessibilityService.GESTURE_DOUBLE_TAP,
event.getDisplayId(),
mGestureDetector.getMotionEvents());
mAms.onGesture(gestureEvent);
}
if (mSendTouchExplorationEndDelayed.isPending()) {
mSendTouchExplorationEndDelayed.forceSendAndRemove();
}
@@ -385,6 +401,9 @@ public class TouchExplorer extends BaseEventStreamTransformation
@Override
public boolean onGestureCompleted(AccessibilityGestureEvent gestureEvent) {
if (DEBUG) {
Slog.d(LOG_TAG, "Dispatching gesture event:" + gestureEvent.toString());
}
endGestureDetection(true);
mSendTouchInteractionEndDelayed.cancel();
mAms.onGesture(gestureEvent);
@@ -411,12 +430,24 @@ public class TouchExplorer extends BaseEventStreamTransformation
mDispatcher.sendMotionEvent(
event,
ACTION_HOVER_MOVE,
mState.getLastReceivedEvent(),
event,
pointerIdBits,
policyFlags);
return true;
}
}
if (isSendMotionEventsEnabled()) {
// Send a gesture with motion events to represent the cancelled gesture.
AccessibilityGestureEvent gestureEvent =
new AccessibilityGestureEvent(
AccessibilityService.GESTURE_UNKNOWN,
event.getDisplayId(),
mGestureDetector.getMotionEvents());
if (DEBUG) {
Slog.d(LOG_TAG, "Dispatching gesture event:" + gestureEvent.toString());
}
mAms.onGesture(gestureEvent);
}
return false;
}
@@ -620,6 +651,14 @@ public class TouchExplorer extends BaseEventStreamTransformation
if (isDraggingGesture(event)) {
// Two pointers moving in the same direction within
// a given distance perform a drag.
if (isSendMotionEventsEnabled()) {
AccessibilityGestureEvent gestureEvent =
new AccessibilityGestureEvent(
AccessibilityService.GESTURE_PASSTHROUGH,
event.getDisplayId(),
mGestureDetector.getMotionEvents());
mAms.onGesture(gestureEvent);
}
computeDraggingPointerIdIfNeeded(event);
pointerIdBits = 1 << mDraggingPointerId;
event.setEdgeFlags(mReceivedPointerTracker.getLastReceivedDownEdgeFlags());
@@ -636,6 +675,14 @@ public class TouchExplorer extends BaseEventStreamTransformation
mState.startDragging();
} else {
// Two pointers moving arbitrary are delegated to the view hierarchy.
if (isSendMotionEventsEnabled()) {
AccessibilityGestureEvent gestureEvent =
new AccessibilityGestureEvent(
AccessibilityService.GESTURE_PASSTHROUGH,
event.getDisplayId(),
mGestureDetector.getMotionEvents());
mAms.onGesture(gestureEvent);
}
mState.startDelegating();
mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
}
@@ -650,6 +697,14 @@ public class TouchExplorer extends BaseEventStreamTransformation
if (DEBUG) {
Slog.d(LOG_TAG, "Three-finger edge swipe detected.");
}
if (isSendMotionEventsEnabled()) {
AccessibilityGestureEvent gestureEvent =
new AccessibilityGestureEvent(
AccessibilityService.GESTURE_PASSTHROUGH,
event.getDisplayId(),
mGestureDetector.getMotionEvents());
mAms.onGesture(gestureEvent);
}
mState.startDelegating();
if (mState.isTouchExploring()) {
mDispatcher.sendDownForAllNotInjectedPointers(event,
@@ -663,6 +718,14 @@ public class TouchExplorer extends BaseEventStreamTransformation
}
} else {
// More than two pointers are delegated to the view hierarchy.
if (isSendMotionEventsEnabled()) {
AccessibilityGestureEvent gestureEvent =
new AccessibilityGestureEvent(
AccessibilityService.GESTURE_PASSTHROUGH,
event.getDisplayId(),
mGestureDetector.getMotionEvents());
mAms.onGesture(gestureEvent);
}
mState.startDelegating();
event = MotionEvent.obtainNoHistory(event);
mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
@@ -1109,6 +1172,7 @@ public class TouchExplorer extends BaseEventStreamTransformation
public void setTwoFingerPassthroughEnabled(boolean enabled) {
mGestureDetector.setTwoFingerPassthroughEnabled(enabled);
}
public void setGestureDetectionPassthroughRegion(Region region) {
mGestureDetectionPassthroughRegion = region;
}
@@ -1117,6 +1181,17 @@ public class TouchExplorer extends BaseEventStreamTransformation
mTouchExplorationPassthroughRegion = region;
}
/**
* Whether to send the motion events that make up each gesture to the accessibility service.
*/
public void setSendMotionEventsEnabled(boolean mode) {
mGestureDetector.setSendMotionEventsEnabled(mode);
}
public boolean isSendMotionEventsEnabled() {
return mGestureDetector.isSendMotionEventsEnabled();
}
private boolean shouldPerformGestureDetection(MotionEvent event) {
if (mState.isDelegating()) {
return false;
@@ -1213,7 +1288,14 @@ public class TouchExplorer extends BaseEventStreamTransformation
public void run() {
// Send an accessibility event to announce the touch exploration start.
mDispatcher.sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_START);
if (isSendMotionEventsEnabled()) {
AccessibilityGestureEvent gestureEvent =
new AccessibilityGestureEvent(
AccessibilityService.GESTURE_TOUCH_EXPLORATION,
mState.getLastReceivedEvent().getDisplayId(),
mGestureDetector.getMotionEvents());
mAms.onGesture(gestureEvent);
}
if (!mEvents.isEmpty() && !mRawEvents.isEmpty()) {
// Deliver a down event.
mDispatcher.sendMotionEvent(mEvents.get(0), ACTION_HOVER_ENTER,