Loading api/current.txt +5 −0 Original line number Diff line number Diff line Loading @@ -2804,9 +2804,14 @@ package android.accessibilityservice { public static class GestureDescription.StrokeDescription { ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long); ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long, int, boolean); method public int getContinuedStrokeId(); method public long getDuration(); method public int getId(); method public android.graphics.Path getPath(); method public long getStartTime(); method public boolean isContinued(); field public static final int INVALID_STROKE_ID = -1; // 0xffffffff } } api/system-current.txt +5 −0 Original line number Diff line number Diff line Loading @@ -2918,9 +2918,14 @@ package android.accessibilityservice { public static class GestureDescription.StrokeDescription { ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long); ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long, int, boolean); method public int getContinuedStrokeId(); method public long getDuration(); method public int getId(); method public android.graphics.Path getPath(); method public long getStartTime(); method public boolean isContinued(); field public static final int INVALID_STROKE_ID = -1; // 0xffffffff } } api/test-current.txt +5 −0 Original line number Diff line number Diff line Loading @@ -2804,9 +2804,14 @@ package android.accessibilityservice { public static class GestureDescription.StrokeDescription { ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long); ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long, int, boolean); method public int getContinuedStrokeId(); method public long getDuration(); method public int getId(); method public android.graphics.Path getPath(); method public long getStartTime(); method public boolean isContinued(); field public static final int INVALID_STROKE_ID = -1; // 0xffffffff } } core/java/android/accessibilityservice/GestureDescription.java +85 −186 Original line number Diff line number Diff line Loading @@ -23,10 +23,6 @@ import android.graphics.PathMeasure; import android.graphics.RectF; import android.os.Parcel; import android.os.Parcelable; import android.view.InputDevice; import android.view.MotionEvent; import android.view.MotionEvent.PointerCoords; import android.view.MotionEvent.PointerProperties; import java.util.ArrayList; import java.util.List; Loading Loading @@ -128,9 +124,14 @@ public final class GestureDescription { for (int i = 0; i < mStrokes.size(); i++) { StrokeDescription strokeDescription = mStrokes.get(i); if (strokeDescription.hasPointForTime(time)) { touchPoints[numPointsFound].mPathIndex = i; touchPoints[numPointsFound].mIsStartOfPath = (time == strokeDescription.mStartTime); touchPoints[numPointsFound].mIsEndOfPath = (time == strokeDescription.mEndTime); touchPoints[numPointsFound].mStrokeId = strokeDescription.getId(); touchPoints[numPointsFound].mContinuedStrokeId = strokeDescription.getContinuedStrokeId(); touchPoints[numPointsFound].mIsStartOfPath = (strokeDescription.getContinuedStrokeId() < 0) && (time == strokeDescription.mStartTime); touchPoints[numPointsFound].mIsEndOfPath = !strokeDescription.isContinued() && (time == strokeDescription.mEndTime); strokeDescription.getPosForTime(time, mTempPos); touchPoints[numPointsFound].mX = Math.round(mTempPos[0]); touchPoints[numPointsFound].mY = Math.round(mTempPos[1]); Loading Loading @@ -196,6 +197,10 @@ public final class GestureDescription { * Immutable description of stroke that can be part of a gesture. */ public static class StrokeDescription { public static final int INVALID_STROKE_ID = -1; static int sIdCounter; Path mPath; long mStartTime; long mEndTime; Loading @@ -203,6 +208,9 @@ public final class GestureDescription { private PathMeasure mPathMeasure; // The tap location is only set for zero-length paths float[] mTapLocation; int mId; boolean mContinued; int mContinuedStrokeId; /** * @param path The path to follow. Must have exactly one contour. The bounds of the path Loading @@ -216,6 +224,32 @@ public final class GestureDescription { public StrokeDescription(@NonNull Path path, @IntRange(from = 0) long startTime, @IntRange(from = 0) long duration) { this(path, startTime, duration, INVALID_STROKE_ID, false); } /** * @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. * Must be positive. * @param continuedStrokeId The ID of the stroke that this stroke continues, or * {@link #INVALID_STROKE_ID} if it continues no stroke. The stroke it * continues must have its isContinued flag set to {@code true} and must be in the * gesture dispatched immediately before the one containing this stroke. * @param isContinued {@code true} if this stroke will be continued by one in the * next gesture {@code false} otherwise. Continued strokes keep their pointers down when * the gesture completes. */ public StrokeDescription(@NonNull Path path, @IntRange(from = 0) long startTime, @IntRange(from = 0) long duration, @IntRange(from = 0) int continuedStrokeId, boolean isContinued) { mContinued = isContinued; mContinuedStrokeId = continuedStrokeId; if (duration <= 0) { throw new IllegalArgumentException("Duration must be positive"); } Loading Loading @@ -252,6 +286,7 @@ public final class GestureDescription { mStartTime = startTime; mEndTime = startTime + duration; mTimeToLengthConversion = getLength() / duration; mId = sIdCounter++; } /** Loading Loading @@ -281,6 +316,34 @@ public final class GestureDescription { return mEndTime - mStartTime; } /** * Get the stroke's ID. The ID is used when a stroke is to be continued by another * stroke in a future gesture. * * @return the ID of this stroke */ public int getId() { return mId; } /** * Check if this stroke is marked to continue in the next gesture. * * @return {@code true} if the stroke is to be continued. */ public boolean isContinued() { return mContinued; } /** * Get the ID of the stroke that this one will continue. * * @return The ID of the stroke that this stroke continues, or 0 if no such stroke exists. */ public int getContinuedStrokeId() { return mContinuedStrokeId; } float getLength() { return mPathMeasure.getLength(); } Loading Loading @@ -314,11 +377,12 @@ public final class GestureDescription { private static final int FLAG_IS_START_OF_PATH = 0x01; private static final int FLAG_IS_END_OF_PATH = 0x02; int mPathIndex; boolean mIsStartOfPath; boolean mIsEndOfPath; float mX; float mY; public int mStrokeId; public int mContinuedStrokeId; public boolean mIsStartOfPath; public boolean mIsEndOfPath; public float mX; public float mY; public TouchPoint() { } Loading @@ -328,7 +392,8 @@ public final class GestureDescription { } public TouchPoint(Parcel parcel) { mPathIndex = parcel.readInt(); mStrokeId = parcel.readInt(); mContinuedStrokeId = parcel.readInt(); int startEnd = parcel.readInt(); mIsStartOfPath = (startEnd & FLAG_IS_START_OF_PATH) != 0; mIsEndOfPath = (startEnd & FLAG_IS_END_OF_PATH) != 0; Loading @@ -336,8 +401,9 @@ public final class GestureDescription { mY = parcel.readFloat(); } void copyFrom(TouchPoint other) { mPathIndex = other.mPathIndex; public void copyFrom(TouchPoint other) { mStrokeId = other.mStrokeId; mContinuedStrokeId = other.mContinuedStrokeId; mIsStartOfPath = other.mIsStartOfPath; mIsEndOfPath = other.mIsEndOfPath; mX = other.mX; Loading @@ -351,7 +417,8 @@ public final class GestureDescription { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mPathIndex); dest.writeInt(mStrokeId); dest.writeInt(mContinuedStrokeId); int startEnd = mIsStartOfPath ? FLAG_IS_START_OF_PATH : 0; startEnd |= mIsEndOfPath ? FLAG_IS_END_OF_PATH : 0; dest.writeInt(startEnd); Loading Loading @@ -426,30 +493,15 @@ public final class GestureDescription { } /** * Class to convert a GestureDescription to a series of MotionEvents. * Class to convert a GestureDescription to a series of GestureSteps. * * @hide */ public static class MotionEventGenerator { /** * Constants used to initialize all MotionEvents */ private static final int EVENT_META_STATE = 0; private static final int EVENT_BUTTON_STATE = 0; private static final int EVENT_DEVICE_ID = 0; private static final int EVENT_EDGE_FLAGS = 0; private static final int EVENT_SOURCE = InputDevice.SOURCE_TOUCHSCREEN; private static final int EVENT_FLAGS = 0; private static final float EVENT_X_PRECISION = 1; private static final float EVENT_Y_PRECISION = 1; /* Lazily-created scratch memory for processing touches */ private static TouchPoint[] sCurrentTouchPoints; private static TouchPoint[] sLastTouchPoints; private static PointerCoords[] sPointerCoords; private static PointerProperties[] sPointerProps; static List<GestureStep> getGestureStepsFromGestureDescription( public static List<GestureStep> getGestureStepsFromGestureDescription( GestureDescription description, int sampleTimeMs) { final List<GestureStep> gestureSteps = new ArrayList<>(); Loading @@ -474,31 +526,6 @@ public final class GestureDescription { 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; } private static TouchPoint[] getCurrentTouchPoints(int requiredCapacity) { if ((sCurrentTouchPoints == null) || (sCurrentTouchPoints.length < requiredCapacity)) { sCurrentTouchPoints = new TouchPoint[requiredCapacity]; Loading @@ -508,133 +535,5 @@ public final class GestureDescription { } return sCurrentTouchPoints; } private static TouchPoint[] getLastTouchPoints(int requiredCapacity) { if ((sLastTouchPoints == null) || (sLastTouchPoints.length < requiredCapacity)) { sLastTouchPoints = new TouchPoint[requiredCapacity]; for (int i = 0; i < requiredCapacity; i++) { sLastTouchPoints[i] = new TouchPoint(); } } return sLastTouchPoints; } private static PointerCoords[] getPointerCoords(int requiredCapacity) { if ((sPointerCoords == null) || (sPointerCoords.length < requiredCapacity)) { sPointerCoords = new PointerCoords[requiredCapacity]; for (int i = 0; i < requiredCapacity; i++) { sPointerCoords[i] = new PointerCoords(); } } return sPointerCoords; } private static PointerProperties[] getPointerProps(int requiredCapacity) { if ((sPointerProps == null) || (sPointerProps.length < requiredCapacity)) { sPointerProps = new PointerProperties[requiredCapacity]; for (int i = 0; i < requiredCapacity; i++) { sPointerProps[i] = new PointerProperties(); } } return sPointerProps; } private static void appendMoveEventIfNeeded(List<MotionEvent> motionEvents, TouchPoint[] lastTouchPoints, int lastTouchPointsSize, TouchPoint[] currentTouchPoints, int currentTouchPointsSize, long currentTime) { /* Look for pointers that have moved */ boolean moveFound = false; for (int i = 0; i < currentTouchPointsSize; i++) { int lastPointsIndex = findPointByPathIndex(lastTouchPoints, lastTouchPointsSize, currentTouchPoints[i].mPathIndex); if (lastPointsIndex >= 0) { moveFound |= (lastTouchPoints[lastPointsIndex].mX != currentTouchPoints[i].mX) || (lastTouchPoints[lastPointsIndex].mY != currentTouchPoints[i].mY); lastTouchPoints[lastPointsIndex].copyFrom(currentTouchPoints[i]); } } if (moveFound) { long downTime = motionEvents.get(motionEvents.size() - 1).getDownTime(); motionEvents.add(obtainMotionEvent(downTime, currentTime, MotionEvent.ACTION_MOVE, lastTouchPoints, lastTouchPointsSize)); } } private static int appendUpEvents(List<MotionEvent> motionEvents, TouchPoint[] lastTouchPoints, int lastTouchPointsSize, TouchPoint[] currentTouchPoints, int currentTouchPointsSize, long currentTime) { /* Look for a pointer at the end of its path */ for (int i = 0; i < currentTouchPointsSize; i++) { if (currentTouchPoints[i].mIsEndOfPath) { int indexOfUpEvent = findPointByPathIndex(lastTouchPoints, lastTouchPointsSize, currentTouchPoints[i].mPathIndex); if (indexOfUpEvent < 0) { continue; // Should not happen } long downTime = motionEvents.get(motionEvents.size() - 1).getDownTime(); int action = (lastTouchPointsSize == 1) ? MotionEvent.ACTION_UP : MotionEvent.ACTION_POINTER_UP; action |= indexOfUpEvent << MotionEvent.ACTION_POINTER_INDEX_SHIFT; motionEvents.add(obtainMotionEvent(downTime, currentTime, action, lastTouchPoints, lastTouchPointsSize)); /* Remove this point from lastTouchPoints */ for (int j = indexOfUpEvent; j < lastTouchPointsSize - 1; j++) { lastTouchPoints[j].copyFrom(lastTouchPoints[j+1]); } lastTouchPointsSize--; } } return lastTouchPointsSize; } private static int appendDownEvents(List<MotionEvent> motionEvents, TouchPoint[] lastTouchPoints, int lastTouchPointsSize, TouchPoint[] currentTouchPoints, int currentTouchPointsSize, long currentTime) { /* Look for a pointer that is just starting */ for (int i = 0; i < currentTouchPointsSize; i++) { if (currentTouchPoints[i].mIsStartOfPath) { /* Add the point to last coords and use the new array to generate the event */ lastTouchPoints[lastTouchPointsSize++].copyFrom(currentTouchPoints[i]); int action = (lastTouchPointsSize == 1) ? MotionEvent.ACTION_DOWN : MotionEvent.ACTION_POINTER_DOWN; long downTime = (action == MotionEvent.ACTION_DOWN) ? currentTime : motionEvents.get(motionEvents.size() - 1).getDownTime(); action |= i << MotionEvent.ACTION_POINTER_INDEX_SHIFT; motionEvents.add(obtainMotionEvent(downTime, currentTime, action, lastTouchPoints, lastTouchPointsSize)); } } return lastTouchPointsSize; } private static MotionEvent obtainMotionEvent(long downTime, long eventTime, int action, TouchPoint[] touchPoints, int touchPointsSize) { PointerCoords[] pointerCoords = getPointerCoords(touchPointsSize); PointerProperties[] pointerProperties = getPointerProps(touchPointsSize); for (int i = 0; i < touchPointsSize; i++) { pointerProperties[i].id = touchPoints[i].mPathIndex; pointerProperties[i].toolType = MotionEvent.TOOL_TYPE_UNKNOWN; pointerCoords[i].clear(); pointerCoords[i].pressure = 1.0f; pointerCoords[i].size = 1.0f; pointerCoords[i].x = touchPoints[i].mX; pointerCoords[i].y = touchPoints[i].mY; } return MotionEvent.obtain(downTime, eventTime, action, touchPointsSize, pointerProperties, pointerCoords, EVENT_META_STATE, EVENT_BUTTON_STATE, EVENT_X_PRECISION, EVENT_Y_PRECISION, EVENT_DEVICE_ID, EVENT_EDGE_FLAGS, EVENT_SOURCE, EVENT_FLAGS); } private static int findPointByPathIndex(TouchPoint[] touchPoints, int touchPointsSize, int pathIndex) { for (int i = 0; i < touchPointsSize; i++) { if (touchPoints[i].mPathIndex == pathIndex) { return i; } } return -1; } } } services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +2 −9 Original line number Diff line number Diff line Loading @@ -2843,15 +2843,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } if (mMotionEventInjector != null) { List<GestureDescription.GestureStep> steps = gestureSteps.getList(); List<MotionEvent> events = GestureDescription.MotionEventGenerator .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); mMotionEventInjector.injectEvents(steps, mServiceInterface, sequence); return; } else { Slog.e(LOG_TAG, "Gesture is not well-formed"); } } else { Slog.e(LOG_TAG, "MotionEventInjector installation timed out"); } Loading Loading
api/current.txt +5 −0 Original line number Diff line number Diff line Loading @@ -2804,9 +2804,14 @@ package android.accessibilityservice { public static class GestureDescription.StrokeDescription { ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long); ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long, int, boolean); method public int getContinuedStrokeId(); method public long getDuration(); method public int getId(); method public android.graphics.Path getPath(); method public long getStartTime(); method public boolean isContinued(); field public static final int INVALID_STROKE_ID = -1; // 0xffffffff } }
api/system-current.txt +5 −0 Original line number Diff line number Diff line Loading @@ -2918,9 +2918,14 @@ package android.accessibilityservice { public static class GestureDescription.StrokeDescription { ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long); ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long, int, boolean); method public int getContinuedStrokeId(); method public long getDuration(); method public int getId(); method public android.graphics.Path getPath(); method public long getStartTime(); method public boolean isContinued(); field public static final int INVALID_STROKE_ID = -1; // 0xffffffff } }
api/test-current.txt +5 −0 Original line number Diff line number Diff line Loading @@ -2804,9 +2804,14 @@ package android.accessibilityservice { public static class GestureDescription.StrokeDescription { ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long); ctor public GestureDescription.StrokeDescription(android.graphics.Path, long, long, int, boolean); method public int getContinuedStrokeId(); method public long getDuration(); method public int getId(); method public android.graphics.Path getPath(); method public long getStartTime(); method public boolean isContinued(); field public static final int INVALID_STROKE_ID = -1; // 0xffffffff } }
core/java/android/accessibilityservice/GestureDescription.java +85 −186 Original line number Diff line number Diff line Loading @@ -23,10 +23,6 @@ import android.graphics.PathMeasure; import android.graphics.RectF; import android.os.Parcel; import android.os.Parcelable; import android.view.InputDevice; import android.view.MotionEvent; import android.view.MotionEvent.PointerCoords; import android.view.MotionEvent.PointerProperties; import java.util.ArrayList; import java.util.List; Loading Loading @@ -128,9 +124,14 @@ public final class GestureDescription { for (int i = 0; i < mStrokes.size(); i++) { StrokeDescription strokeDescription = mStrokes.get(i); if (strokeDescription.hasPointForTime(time)) { touchPoints[numPointsFound].mPathIndex = i; touchPoints[numPointsFound].mIsStartOfPath = (time == strokeDescription.mStartTime); touchPoints[numPointsFound].mIsEndOfPath = (time == strokeDescription.mEndTime); touchPoints[numPointsFound].mStrokeId = strokeDescription.getId(); touchPoints[numPointsFound].mContinuedStrokeId = strokeDescription.getContinuedStrokeId(); touchPoints[numPointsFound].mIsStartOfPath = (strokeDescription.getContinuedStrokeId() < 0) && (time == strokeDescription.mStartTime); touchPoints[numPointsFound].mIsEndOfPath = !strokeDescription.isContinued() && (time == strokeDescription.mEndTime); strokeDescription.getPosForTime(time, mTempPos); touchPoints[numPointsFound].mX = Math.round(mTempPos[0]); touchPoints[numPointsFound].mY = Math.round(mTempPos[1]); Loading Loading @@ -196,6 +197,10 @@ public final class GestureDescription { * Immutable description of stroke that can be part of a gesture. */ public static class StrokeDescription { public static final int INVALID_STROKE_ID = -1; static int sIdCounter; Path mPath; long mStartTime; long mEndTime; Loading @@ -203,6 +208,9 @@ public final class GestureDescription { private PathMeasure mPathMeasure; // The tap location is only set for zero-length paths float[] mTapLocation; int mId; boolean mContinued; int mContinuedStrokeId; /** * @param path The path to follow. Must have exactly one contour. The bounds of the path Loading @@ -216,6 +224,32 @@ public final class GestureDescription { public StrokeDescription(@NonNull Path path, @IntRange(from = 0) long startTime, @IntRange(from = 0) long duration) { this(path, startTime, duration, INVALID_STROKE_ID, false); } /** * @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. * Must be positive. * @param continuedStrokeId The ID of the stroke that this stroke continues, or * {@link #INVALID_STROKE_ID} if it continues no stroke. The stroke it * continues must have its isContinued flag set to {@code true} and must be in the * gesture dispatched immediately before the one containing this stroke. * @param isContinued {@code true} if this stroke will be continued by one in the * next gesture {@code false} otherwise. Continued strokes keep their pointers down when * the gesture completes. */ public StrokeDescription(@NonNull Path path, @IntRange(from = 0) long startTime, @IntRange(from = 0) long duration, @IntRange(from = 0) int continuedStrokeId, boolean isContinued) { mContinued = isContinued; mContinuedStrokeId = continuedStrokeId; if (duration <= 0) { throw new IllegalArgumentException("Duration must be positive"); } Loading Loading @@ -252,6 +286,7 @@ public final class GestureDescription { mStartTime = startTime; mEndTime = startTime + duration; mTimeToLengthConversion = getLength() / duration; mId = sIdCounter++; } /** Loading Loading @@ -281,6 +316,34 @@ public final class GestureDescription { return mEndTime - mStartTime; } /** * Get the stroke's ID. The ID is used when a stroke is to be continued by another * stroke in a future gesture. * * @return the ID of this stroke */ public int getId() { return mId; } /** * Check if this stroke is marked to continue in the next gesture. * * @return {@code true} if the stroke is to be continued. */ public boolean isContinued() { return mContinued; } /** * Get the ID of the stroke that this one will continue. * * @return The ID of the stroke that this stroke continues, or 0 if no such stroke exists. */ public int getContinuedStrokeId() { return mContinuedStrokeId; } float getLength() { return mPathMeasure.getLength(); } Loading Loading @@ -314,11 +377,12 @@ public final class GestureDescription { private static final int FLAG_IS_START_OF_PATH = 0x01; private static final int FLAG_IS_END_OF_PATH = 0x02; int mPathIndex; boolean mIsStartOfPath; boolean mIsEndOfPath; float mX; float mY; public int mStrokeId; public int mContinuedStrokeId; public boolean mIsStartOfPath; public boolean mIsEndOfPath; public float mX; public float mY; public TouchPoint() { } Loading @@ -328,7 +392,8 @@ public final class GestureDescription { } public TouchPoint(Parcel parcel) { mPathIndex = parcel.readInt(); mStrokeId = parcel.readInt(); mContinuedStrokeId = parcel.readInt(); int startEnd = parcel.readInt(); mIsStartOfPath = (startEnd & FLAG_IS_START_OF_PATH) != 0; mIsEndOfPath = (startEnd & FLAG_IS_END_OF_PATH) != 0; Loading @@ -336,8 +401,9 @@ public final class GestureDescription { mY = parcel.readFloat(); } void copyFrom(TouchPoint other) { mPathIndex = other.mPathIndex; public void copyFrom(TouchPoint other) { mStrokeId = other.mStrokeId; mContinuedStrokeId = other.mContinuedStrokeId; mIsStartOfPath = other.mIsStartOfPath; mIsEndOfPath = other.mIsEndOfPath; mX = other.mX; Loading @@ -351,7 +417,8 @@ public final class GestureDescription { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mPathIndex); dest.writeInt(mStrokeId); dest.writeInt(mContinuedStrokeId); int startEnd = mIsStartOfPath ? FLAG_IS_START_OF_PATH : 0; startEnd |= mIsEndOfPath ? FLAG_IS_END_OF_PATH : 0; dest.writeInt(startEnd); Loading Loading @@ -426,30 +493,15 @@ public final class GestureDescription { } /** * Class to convert a GestureDescription to a series of MotionEvents. * Class to convert a GestureDescription to a series of GestureSteps. * * @hide */ public static class MotionEventGenerator { /** * Constants used to initialize all MotionEvents */ private static final int EVENT_META_STATE = 0; private static final int EVENT_BUTTON_STATE = 0; private static final int EVENT_DEVICE_ID = 0; private static final int EVENT_EDGE_FLAGS = 0; private static final int EVENT_SOURCE = InputDevice.SOURCE_TOUCHSCREEN; private static final int EVENT_FLAGS = 0; private static final float EVENT_X_PRECISION = 1; private static final float EVENT_Y_PRECISION = 1; /* Lazily-created scratch memory for processing touches */ private static TouchPoint[] sCurrentTouchPoints; private static TouchPoint[] sLastTouchPoints; private static PointerCoords[] sPointerCoords; private static PointerProperties[] sPointerProps; static List<GestureStep> getGestureStepsFromGestureDescription( public static List<GestureStep> getGestureStepsFromGestureDescription( GestureDescription description, int sampleTimeMs) { final List<GestureStep> gestureSteps = new ArrayList<>(); Loading @@ -474,31 +526,6 @@ public final class GestureDescription { 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; } private static TouchPoint[] getCurrentTouchPoints(int requiredCapacity) { if ((sCurrentTouchPoints == null) || (sCurrentTouchPoints.length < requiredCapacity)) { sCurrentTouchPoints = new TouchPoint[requiredCapacity]; Loading @@ -508,133 +535,5 @@ public final class GestureDescription { } return sCurrentTouchPoints; } private static TouchPoint[] getLastTouchPoints(int requiredCapacity) { if ((sLastTouchPoints == null) || (sLastTouchPoints.length < requiredCapacity)) { sLastTouchPoints = new TouchPoint[requiredCapacity]; for (int i = 0; i < requiredCapacity; i++) { sLastTouchPoints[i] = new TouchPoint(); } } return sLastTouchPoints; } private static PointerCoords[] getPointerCoords(int requiredCapacity) { if ((sPointerCoords == null) || (sPointerCoords.length < requiredCapacity)) { sPointerCoords = new PointerCoords[requiredCapacity]; for (int i = 0; i < requiredCapacity; i++) { sPointerCoords[i] = new PointerCoords(); } } return sPointerCoords; } private static PointerProperties[] getPointerProps(int requiredCapacity) { if ((sPointerProps == null) || (sPointerProps.length < requiredCapacity)) { sPointerProps = new PointerProperties[requiredCapacity]; for (int i = 0; i < requiredCapacity; i++) { sPointerProps[i] = new PointerProperties(); } } return sPointerProps; } private static void appendMoveEventIfNeeded(List<MotionEvent> motionEvents, TouchPoint[] lastTouchPoints, int lastTouchPointsSize, TouchPoint[] currentTouchPoints, int currentTouchPointsSize, long currentTime) { /* Look for pointers that have moved */ boolean moveFound = false; for (int i = 0; i < currentTouchPointsSize; i++) { int lastPointsIndex = findPointByPathIndex(lastTouchPoints, lastTouchPointsSize, currentTouchPoints[i].mPathIndex); if (lastPointsIndex >= 0) { moveFound |= (lastTouchPoints[lastPointsIndex].mX != currentTouchPoints[i].mX) || (lastTouchPoints[lastPointsIndex].mY != currentTouchPoints[i].mY); lastTouchPoints[lastPointsIndex].copyFrom(currentTouchPoints[i]); } } if (moveFound) { long downTime = motionEvents.get(motionEvents.size() - 1).getDownTime(); motionEvents.add(obtainMotionEvent(downTime, currentTime, MotionEvent.ACTION_MOVE, lastTouchPoints, lastTouchPointsSize)); } } private static int appendUpEvents(List<MotionEvent> motionEvents, TouchPoint[] lastTouchPoints, int lastTouchPointsSize, TouchPoint[] currentTouchPoints, int currentTouchPointsSize, long currentTime) { /* Look for a pointer at the end of its path */ for (int i = 0; i < currentTouchPointsSize; i++) { if (currentTouchPoints[i].mIsEndOfPath) { int indexOfUpEvent = findPointByPathIndex(lastTouchPoints, lastTouchPointsSize, currentTouchPoints[i].mPathIndex); if (indexOfUpEvent < 0) { continue; // Should not happen } long downTime = motionEvents.get(motionEvents.size() - 1).getDownTime(); int action = (lastTouchPointsSize == 1) ? MotionEvent.ACTION_UP : MotionEvent.ACTION_POINTER_UP; action |= indexOfUpEvent << MotionEvent.ACTION_POINTER_INDEX_SHIFT; motionEvents.add(obtainMotionEvent(downTime, currentTime, action, lastTouchPoints, lastTouchPointsSize)); /* Remove this point from lastTouchPoints */ for (int j = indexOfUpEvent; j < lastTouchPointsSize - 1; j++) { lastTouchPoints[j].copyFrom(lastTouchPoints[j+1]); } lastTouchPointsSize--; } } return lastTouchPointsSize; } private static int appendDownEvents(List<MotionEvent> motionEvents, TouchPoint[] lastTouchPoints, int lastTouchPointsSize, TouchPoint[] currentTouchPoints, int currentTouchPointsSize, long currentTime) { /* Look for a pointer that is just starting */ for (int i = 0; i < currentTouchPointsSize; i++) { if (currentTouchPoints[i].mIsStartOfPath) { /* Add the point to last coords and use the new array to generate the event */ lastTouchPoints[lastTouchPointsSize++].copyFrom(currentTouchPoints[i]); int action = (lastTouchPointsSize == 1) ? MotionEvent.ACTION_DOWN : MotionEvent.ACTION_POINTER_DOWN; long downTime = (action == MotionEvent.ACTION_DOWN) ? currentTime : motionEvents.get(motionEvents.size() - 1).getDownTime(); action |= i << MotionEvent.ACTION_POINTER_INDEX_SHIFT; motionEvents.add(obtainMotionEvent(downTime, currentTime, action, lastTouchPoints, lastTouchPointsSize)); } } return lastTouchPointsSize; } private static MotionEvent obtainMotionEvent(long downTime, long eventTime, int action, TouchPoint[] touchPoints, int touchPointsSize) { PointerCoords[] pointerCoords = getPointerCoords(touchPointsSize); PointerProperties[] pointerProperties = getPointerProps(touchPointsSize); for (int i = 0; i < touchPointsSize; i++) { pointerProperties[i].id = touchPoints[i].mPathIndex; pointerProperties[i].toolType = MotionEvent.TOOL_TYPE_UNKNOWN; pointerCoords[i].clear(); pointerCoords[i].pressure = 1.0f; pointerCoords[i].size = 1.0f; pointerCoords[i].x = touchPoints[i].mX; pointerCoords[i].y = touchPoints[i].mY; } return MotionEvent.obtain(downTime, eventTime, action, touchPointsSize, pointerProperties, pointerCoords, EVENT_META_STATE, EVENT_BUTTON_STATE, EVENT_X_PRECISION, EVENT_Y_PRECISION, EVENT_DEVICE_ID, EVENT_EDGE_FLAGS, EVENT_SOURCE, EVENT_FLAGS); } private static int findPointByPathIndex(TouchPoint[] touchPoints, int touchPointsSize, int pathIndex) { for (int i = 0; i < touchPointsSize; i++) { if (touchPoints[i].mPathIndex == pathIndex) { return i; } } return -1; } } }
services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +2 −9 Original line number Diff line number Diff line Loading @@ -2843,15 +2843,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } if (mMotionEventInjector != null) { List<GestureDescription.GestureStep> steps = gestureSteps.getList(); List<MotionEvent> events = GestureDescription.MotionEventGenerator .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); mMotionEventInjector.injectEvents(steps, mServiceInterface, sequence); return; } else { Slog.e(LOG_TAG, "Gesture is not well-formed"); } } else { Slog.e(LOG_TAG, "MotionEventInjector installation timed out"); } Loading