Merge "Limit capabilities of a11y gesture dispatch." into nyc-mr1-dev
This commit is contained in:
@@ -628,8 +628,8 @@ public abstract class AccessibilityService extends Service {
|
|||||||
if (connection == null) {
|
if (connection == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
List<MotionEvent> events = MotionEventGenerator.getMotionEventsFromGestureDescription(
|
List<GestureDescription.GestureStep> steps =
|
||||||
gesture, 100);
|
MotionEventGenerator.getGestureStepsFromGestureDescription(gesture, 100);
|
||||||
try {
|
try {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
mGestureStatusCallbackSequence++;
|
mGestureStatusCallbackSequence++;
|
||||||
@@ -641,8 +641,8 @@ public abstract class AccessibilityService extends Service {
|
|||||||
callback, handler);
|
callback, handler);
|
||||||
mGestureStatusCallbackInfos.put(mGestureStatusCallbackSequence, callbackInfo);
|
mGestureStatusCallbackInfos.put(mGestureStatusCallbackSequence, callbackInfo);
|
||||||
}
|
}
|
||||||
connection.sendMotionEvents(mGestureStatusCallbackSequence,
|
connection.sendGesture(mGestureStatusCallbackSequence,
|
||||||
new ParceledListSlice<>(events));
|
new ParceledListSlice<>(steps));
|
||||||
}
|
}
|
||||||
} catch (RemoteException re) {
|
} catch (RemoteException re) {
|
||||||
throw new RuntimeException(re);
|
throw new RuntimeException(re);
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import android.annotation.NonNull;
|
|||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
import android.graphics.PathMeasure;
|
import android.graphics.PathMeasure;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
import android.view.InputDevice;
|
import android.view.InputDevice;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.MotionEvent.PointerCoords;
|
import android.view.MotionEvent.PointerCoords;
|
||||||
@@ -303,13 +305,37 @@ public final class GestureDescription {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TouchPoint {
|
/**
|
||||||
|
* The location of a finger for gesture dispatch
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static class TouchPoint implements Parcelable {
|
||||||
|
private static final int FLAG_IS_START_OF_PATH = 0x01;
|
||||||
|
private static final int FLAG_IS_END_OF_PATH = 0x02;
|
||||||
|
|
||||||
int mPathIndex;
|
int mPathIndex;
|
||||||
boolean mIsStartOfPath;
|
boolean mIsStartOfPath;
|
||||||
boolean mIsEndOfPath;
|
boolean mIsEndOfPath;
|
||||||
float mX;
|
float mX;
|
||||||
float mY;
|
float mY;
|
||||||
|
|
||||||
|
public TouchPoint() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public TouchPoint(TouchPoint pointToCopy) {
|
||||||
|
copyFrom(pointToCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TouchPoint(Parcel parcel) {
|
||||||
|
mPathIndex = parcel.readInt();
|
||||||
|
int startEnd = parcel.readInt();
|
||||||
|
mIsStartOfPath = (startEnd & FLAG_IS_START_OF_PATH) != 0;
|
||||||
|
mIsEndOfPath = (startEnd & FLAG_IS_END_OF_PATH) != 0;
|
||||||
|
mX = parcel.readFloat();
|
||||||
|
mY = parcel.readFloat();
|
||||||
|
}
|
||||||
|
|
||||||
void copyFrom(TouchPoint other) {
|
void copyFrom(TouchPoint other) {
|
||||||
mPathIndex = other.mPathIndex;
|
mPathIndex = other.mPathIndex;
|
||||||
mIsStartOfPath = other.mIsStartOfPath;
|
mIsStartOfPath = other.mIsStartOfPath;
|
||||||
@@ -317,12 +343,94 @@ public final class GestureDescription {
|
|||||||
mX = other.mX;
|
mX = other.mX;
|
||||||
mY = other.mY;
|
mY = other.mY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeInt(mPathIndex);
|
||||||
|
int startEnd = mIsStartOfPath ? FLAG_IS_START_OF_PATH : 0;
|
||||||
|
startEnd |= mIsEndOfPath ? FLAG_IS_END_OF_PATH : 0;
|
||||||
|
dest.writeInt(startEnd);
|
||||||
|
dest.writeFloat(mX);
|
||||||
|
dest.writeFloat(mY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<TouchPoint> CREATOR
|
||||||
|
= new Parcelable.Creator<TouchPoint>() {
|
||||||
|
public TouchPoint createFromParcel(Parcel in) {
|
||||||
|
return new TouchPoint(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TouchPoint[] newArray(int size) {
|
||||||
|
return new TouchPoint[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A step along a gesture. Contains all of the touch points at a particular time
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static class GestureStep implements Parcelable {
|
||||||
|
public long timeSinceGestureStart;
|
||||||
|
public int numTouchPoints;
|
||||||
|
public TouchPoint[] touchPoints;
|
||||||
|
|
||||||
|
public GestureStep(long timeSinceGestureStart, int numTouchPoints,
|
||||||
|
TouchPoint[] touchPointsToCopy) {
|
||||||
|
this.timeSinceGestureStart = timeSinceGestureStart;
|
||||||
|
this.numTouchPoints = numTouchPoints;
|
||||||
|
this.touchPoints = new TouchPoint[numTouchPoints];
|
||||||
|
for (int i = 0; i < numTouchPoints; i++) {
|
||||||
|
this.touchPoints[i] = new TouchPoint(touchPointsToCopy[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GestureStep(Parcel parcel) {
|
||||||
|
timeSinceGestureStart = parcel.readLong();
|
||||||
|
Parcelable[] parcelables =
|
||||||
|
parcel.readParcelableArray(TouchPoint.class.getClassLoader());
|
||||||
|
numTouchPoints = (parcelables == null) ? 0 : parcelables.length;
|
||||||
|
touchPoints = new TouchPoint[numTouchPoints];
|
||||||
|
for (int i = 0; i < numTouchPoints; i++) {
|
||||||
|
touchPoints[i] = (TouchPoint) parcelables[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeLong(timeSinceGestureStart);
|
||||||
|
dest.writeParcelableArray(touchPoints, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<GestureStep> CREATOR
|
||||||
|
= new Parcelable.Creator<GestureStep>() {
|
||||||
|
public GestureStep createFromParcel(Parcel in) {
|
||||||
|
return new GestureStep(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GestureStep[] newArray(int size) {
|
||||||
|
return new GestureStep[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to convert a GestureDescription to a series of MotionEvents.
|
* Class to convert a GestureDescription to a series of MotionEvents.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
*/
|
*/
|
||||||
static class MotionEventGenerator {
|
public static class MotionEventGenerator {
|
||||||
/**
|
/**
|
||||||
* Constants used to initialize all MotionEvents
|
* Constants used to initialize all MotionEvents
|
||||||
*/
|
*/
|
||||||
@@ -341,39 +449,53 @@ public final class GestureDescription {
|
|||||||
private static PointerCoords[] sPointerCoords;
|
private static PointerCoords[] sPointerCoords;
|
||||||
private static PointerProperties[] sPointerProps;
|
private static PointerProperties[] sPointerProps;
|
||||||
|
|
||||||
static List<MotionEvent> getMotionEventsFromGestureDescription(
|
static List<GestureStep> getGestureStepsFromGestureDescription(
|
||||||
GestureDescription description, int sampleTimeMs) {
|
GestureDescription description, int sampleTimeMs) {
|
||||||
final List<MotionEvent> motionEvents = new ArrayList<>();
|
final List<GestureStep> gestureSteps = new ArrayList<>();
|
||||||
|
|
||||||
// Point data at each time we generate an event for
|
// Point data at each time we generate an event for
|
||||||
final TouchPoint[] currentTouchPoints =
|
final TouchPoint[] currentTouchPoints =
|
||||||
getCurrentTouchPoints(description.getStrokeCount());
|
getCurrentTouchPoints(description.getStrokeCount());
|
||||||
// Point data sent in last touch event
|
int currentTouchPointSize = 0;
|
||||||
int lastTouchPointSize = 0;
|
|
||||||
final TouchPoint[] lastTouchPoints =
|
|
||||||
getLastTouchPoints(description.getStrokeCount());
|
|
||||||
|
|
||||||
/* Loop through each time slice where there are touch points */
|
/* Loop through each time slice where there are touch points */
|
||||||
long timeSinceGestureStart = 0;
|
long timeSinceGestureStart = 0;
|
||||||
long nextKeyPointTime = description.getNextKeyPointAtLeast(timeSinceGestureStart);
|
long nextKeyPointTime = description.getNextKeyPointAtLeast(timeSinceGestureStart);
|
||||||
while (nextKeyPointTime >= 0) {
|
while (nextKeyPointTime >= 0) {
|
||||||
timeSinceGestureStart = (lastTouchPointSize == 0) ? nextKeyPointTime
|
timeSinceGestureStart = (currentTouchPointSize == 0) ? nextKeyPointTime
|
||||||
: Math.min(nextKeyPointTime, timeSinceGestureStart + sampleTimeMs);
|
: Math.min(nextKeyPointTime, timeSinceGestureStart + sampleTimeMs);
|
||||||
int currentTouchPointSize = description.getPointsForTime(timeSinceGestureStart,
|
currentTouchPointSize = description.getPointsForTime(timeSinceGestureStart,
|
||||||
currentTouchPoints);
|
currentTouchPoints);
|
||||||
|
gestureSteps.add(new GestureStep(timeSinceGestureStart, currentTouchPointSize,
|
||||||
appendMoveEventIfNeeded(motionEvents, lastTouchPoints, lastTouchPointSize,
|
currentTouchPoints));
|
||||||
currentTouchPoints, currentTouchPointSize, timeSinceGestureStart);
|
|
||||||
lastTouchPointSize = appendUpEvents(motionEvents, lastTouchPoints,
|
|
||||||
lastTouchPointSize, currentTouchPoints, currentTouchPointSize,
|
|
||||||
timeSinceGestureStart);
|
|
||||||
lastTouchPointSize = appendDownEvents(motionEvents, lastTouchPoints,
|
|
||||||
lastTouchPointSize, currentTouchPoints, currentTouchPointSize,
|
|
||||||
timeSinceGestureStart);
|
|
||||||
|
|
||||||
/* Move to next time slice */
|
/* Move to next time slice */
|
||||||
nextKeyPointTime = description.getNextKeyPointAtLeast(timeSinceGestureStart + 1);
|
nextKeyPointTime = description.getNextKeyPointAtLeast(timeSinceGestureStart + 1);
|
||||||
}
|
}
|
||||||
|
return gestureSteps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<MotionEvent> getMotionEventsFromGestureSteps(List<GestureStep> steps) {
|
||||||
|
final List<MotionEvent> motionEvents = new ArrayList<>();
|
||||||
|
|
||||||
|
// Number of points in last touch event
|
||||||
|
int lastTouchPointSize = 0;
|
||||||
|
TouchPoint[] lastTouchPoints;
|
||||||
|
|
||||||
|
for (int i = 0; i < steps.size(); i++) {
|
||||||
|
GestureStep step = steps.get(i);
|
||||||
|
int currentTouchPointSize = step.numTouchPoints;
|
||||||
|
lastTouchPoints = getLastTouchPoints(
|
||||||
|
Math.max(lastTouchPointSize, currentTouchPointSize));
|
||||||
|
|
||||||
|
appendMoveEventIfNeeded(motionEvents, lastTouchPoints, lastTouchPointSize,
|
||||||
|
step.touchPoints, currentTouchPointSize, step.timeSinceGestureStart);
|
||||||
|
lastTouchPointSize = appendUpEvents(motionEvents, lastTouchPoints,
|
||||||
|
lastTouchPointSize, step.touchPoints, currentTouchPointSize,
|
||||||
|
step.timeSinceGestureStart);
|
||||||
|
lastTouchPointSize = appendDownEvents(motionEvents, lastTouchPoints,
|
||||||
|
lastTouchPointSize, step.touchPoints, currentTouchPointSize,
|
||||||
|
step.timeSinceGestureStart);
|
||||||
|
}
|
||||||
return motionEvents;
|
return motionEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,5 +88,5 @@ interface IAccessibilityServiceConnection {
|
|||||||
|
|
||||||
void setSoftKeyboardCallbackEnabled(boolean enabled);
|
void setSoftKeyboardCallbackEnabled(boolean enabled);
|
||||||
|
|
||||||
void sendMotionEvents(int sequence, in ParceledListSlice events);
|
void sendGesture(int sequence, in ParceledListSlice gestureSteps);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import static android.accessibilityservice.AccessibilityServiceInfo.DEFAULT;
|
|||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.accessibilityservice.AccessibilityService;
|
import android.accessibilityservice.AccessibilityService;
|
||||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||||
|
import android.accessibilityservice.GestureDescription;
|
||||||
import android.accessibilityservice.IAccessibilityServiceClient;
|
import android.accessibilityservice.IAccessibilityServiceClient;
|
||||||
import android.accessibilityservice.IAccessibilityServiceConnection;
|
import android.accessibilityservice.IAccessibilityServiceConnection;
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
@@ -2752,7 +2753,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendMotionEvents(int sequence, ParceledListSlice events) {
|
public void sendGesture(int sequence, ParceledListSlice gestureSteps) {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
if (mSecurityPolicy.canPerformGestures(this)) {
|
if (mSecurityPolicy.canPerformGestures(this)) {
|
||||||
final long endMillis =
|
final long endMillis =
|
||||||
@@ -2766,9 +2767,16 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mMotionEventInjector != null) {
|
if (mMotionEventInjector != null) {
|
||||||
mMotionEventInjector.injectEvents((List<MotionEvent>) events.getList(),
|
List<GestureDescription.GestureStep> steps = gestureSteps.getList();
|
||||||
mServiceInterface, sequence);
|
List<MotionEvent> events = GestureDescription.MotionEventGenerator
|
||||||
return;
|
.getMotionEventsFromGestureSteps(steps);
|
||||||
|
// Confirm that the motion events end with an UP event.
|
||||||
|
if (events.get(events.size() - 1).getAction() == MotionEvent.ACTION_UP) {
|
||||||
|
mMotionEventInjector.injectEvents(events, mServiceInterface, sequence);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
Slog.e(LOG_TAG, "Gesture is not well-formed");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Slog.e(LOG_TAG, "MotionEventInjector installation timed out");
|
Slog.e(LOG_TAG, "MotionEventInjector installation timed out");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user