Support zero-length paths for a11y gestures.
Allows taps to be made at a single point.
Bug: 28378216
Change-Id: I398882faef77b3200aa9813c8d36c5d806521a22
diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java
index e18a34d..fc9581e 100644
--- a/core/java/android/accessibilityservice/GestureDescription.java
+++ b/core/java/android/accessibilityservice/GestureDescription.java
@@ -18,7 +18,6 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
-import android.graphics.Matrix;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.RectF;
@@ -26,10 +25,8 @@
import android.view.MotionEvent;
import android.view.MotionEvent.PointerCoords;
import android.view.MotionEvent.PointerProperties;
-import android.view.ViewConfiguration;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
/**
@@ -160,9 +157,10 @@
private final List<StrokeDescription> mStrokes = new ArrayList<>();
/**
- * Add a stroke to the gesture description. Up to {@code MAX_STROKE_COUNT} paths may be
- * added to a gesture, and the total gesture duration (earliest path start time to latest path
- * end time) may not exceed {@code MAX_GESTURE_DURATION_MS}.
+ * Add a stroke to the gesture description. Up to
+ * {@link GestureDescription#getMaxStrokeCount()} paths may be
+ * added to a gesture, and the total gesture duration (earliest path start time to latest
+ * path end time) may not exceed {@link GestureDescription#getMaxGestureDuration()}.
*
* @param strokeDescription the stroke to add.
*
@@ -201,10 +199,13 @@
long mEndTime;
private float mTimeToLengthConversion;
private PathMeasure mPathMeasure;
+ // The tap location is only set for zero-length paths
+ float[] mTapLocation;
/**
- * @param path The path to follow. Must have exactly one contour, and that contour must
- * have nonzero length. The bounds of the path must not be negative.
+ * @param path The path to follow. Must have exactly one contour. The bounds of the path
+ * must not be negative. The path must not be empty. If the path has zero length
+ * (for example, a single {@code moveTo()}), the stroke is a touch that doesn't move.
* @param startTime The time, in milliseconds, from the time the gesture starts to the
* time the stroke should start. Must not be negative.
* @param duration The duration, in milliseconds, the stroke takes to traverse the path.
@@ -225,10 +226,18 @@
|| (bounds.left < 0)) {
throw new IllegalArgumentException("Path bounds must not be negative");
}
+ if (path.isEmpty()) {
+ throw new IllegalArgumentException("Path is empty");
+ }
mPath = new Path(path);
mPathMeasure = new PathMeasure(path, false);
if (mPathMeasure.getLength() == 0) {
- throw new IllegalArgumentException("Path has zero length");
+ // Treat zero-length paths as taps
+ Path tempPath = new Path(path);
+ tempPath.lineTo(-1, -1);
+ mTapLocation = new float[2];
+ PathMeasure pathMeasure = new PathMeasure(tempPath, false);
+ pathMeasure.getPosTan(0, mTapLocation, null);
}
if (mPathMeasure.nextContour()) {
throw new IllegalArgumentException("Path has more than one contour");
@@ -237,12 +246,10 @@
* Calling nextContour has moved mPathMeasure off the first contour, which is the only
* one we care about. Set the path again to go back to the first contour.
*/
- mPathMeasure.setPath(path, false);
+ mPathMeasure.setPath(mPath, false);
mStartTime = startTime;
mEndTime = startTime + duration;
- if (duration > 0) {
- mTimeToLengthConversion = getLength() / duration;
- }
+ mTimeToLengthConversion = getLength() / duration;
}
/**
@@ -278,6 +285,11 @@
/* Assumes hasPointForTime returns true */
boolean getPosForTime(long time, float[] pos) {
+ if (mTapLocation != null) {
+ pos[0] = mTapLocation[0];
+ pos[1] = mTapLocation[1];
+ return true;
+ }
if (time == mEndTime) {
// Close to the end time, roundoff can be a problem
return mPathMeasure.getPosTan(getLength(), pos, null);