diff options
5 files changed, 293 insertions, 18 deletions
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 b3977829d1c3..e1af2c48789f 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -349,7 +349,7 @@ public class TouchExplorer extends BaseEventStreamTransformation AccessibilityService.GESTURE_DOUBLE_TAP_AND_HOLD, event.getDisplayId(), mGestureDetector.getMotionEvents()); - mAms.onGesture(gestureEvent); + dispatchGesture(gestureEvent); } mState.startDelegating(); } @@ -367,7 +367,7 @@ public class TouchExplorer extends BaseEventStreamTransformation AccessibilityService.GESTURE_DOUBLE_TAP, event.getDisplayId(), mGestureDetector.getMotionEvents()); - mAms.onGesture(gestureEvent); + dispatchGesture(gestureEvent); } if (mSendTouchExplorationEndDelayed.isPending()) { mSendTouchExplorationEndDelayed.forceSendAndRemove(); @@ -402,13 +402,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); - + dispatchGesture(gestureEvent); return true; } @@ -444,10 +440,7 @@ public class TouchExplorer extends BaseEventStreamTransformation AccessibilityService.GESTURE_UNKNOWN, event.getDisplayId(), mGestureDetector.getMotionEvents()); - if (DEBUG) { - Slog.d(LOG_TAG, "Dispatching gesture event:" + gestureEvent.toString()); - } - mAms.onGesture(gestureEvent); + dispatchGesture(gestureEvent); } return false; } @@ -658,7 +651,7 @@ public class TouchExplorer extends BaseEventStreamTransformation AccessibilityService.GESTURE_PASSTHROUGH, event.getDisplayId(), mGestureDetector.getMotionEvents()); - mAms.onGesture(gestureEvent); + dispatchGesture(gestureEvent); } computeDraggingPointerIdIfNeeded(event); pointerIdBits = 1 << mDraggingPointerId; @@ -682,7 +675,7 @@ public class TouchExplorer extends BaseEventStreamTransformation AccessibilityService.GESTURE_PASSTHROUGH, event.getDisplayId(), mGestureDetector.getMotionEvents()); - mAms.onGesture(gestureEvent); + dispatchGesture(gestureEvent); } mState.startDelegating(); mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags); @@ -704,7 +697,7 @@ public class TouchExplorer extends BaseEventStreamTransformation AccessibilityService.GESTURE_PASSTHROUGH, event.getDisplayId(), mGestureDetector.getMotionEvents()); - mAms.onGesture(gestureEvent); + dispatchGesture(gestureEvent); } mState.startDelegating(); if (mState.isTouchExploring()) { @@ -725,7 +718,7 @@ public class TouchExplorer extends BaseEventStreamTransformation AccessibilityService.GESTURE_PASSTHROUGH, event.getDisplayId(), mGestureDetector.getMotionEvents()); - mAms.onGesture(gestureEvent); + dispatchGesture(gestureEvent); } mState.startDelegating(); event = MotionEvent.obtainNoHistory(event); @@ -1304,7 +1297,7 @@ public class TouchExplorer extends BaseEventStreamTransformation AccessibilityService.GESTURE_TOUCH_EXPLORATION, mState.getLastReceivedEvent().getDisplayId(), mGestureDetector.getMotionEvents()); - mAms.onGesture(gestureEvent); + dispatchGesture(gestureEvent); } if (!mEvents.isEmpty() && !mRawEvents.isEmpty()) { // Deliver a down event. @@ -1439,6 +1432,13 @@ public class TouchExplorer extends BaseEventStreamTransformation } } + private void dispatchGesture(AccessibilityGestureEvent gestureEvent) { + if (DEBUG) { + Slog.d(LOG_TAG, "Dispatching gesture event:" + gestureEvent.toString()); + } + mAms.onGesture(gestureEvent); + } + @Override public String toString() { return "TouchExplorer { " diff --git a/services/tests/servicestests/res/raw/a11y_three_finger_swipe_down_gesture.log b/services/tests/servicestests/res/raw/a11y_three_finger_swipe_down_gesture.log new file mode 100644 index 000000000000..cf791f2f3ecb --- /dev/null +++ b/services/tests/servicestests/res/raw/a11y_three_finger_swipe_down_gesture.log @@ -0,0 +1,29 @@ + * Gesture6_id30:Swipe down with 3 finger +MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=500.0, y[0]=696.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=5273700, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_POINTER_DOWN(1), actionButton=0, id[0]=0, x[0]=500.0, y[0]=696.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=764.0, y[1]=801.0, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=5273700, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=500.0, y[0]=696.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=764.0, y[1]=801.0, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=5273709, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_POINTER_DOWN(2), actionButton=0, id[0]=0, x[0]=500.0, y[0]=696.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=764.0, y[1]=801.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=294.0, y[2]=849.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273709, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=500.0, y[0]=696.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=766.0, y[1]=811.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=294.0, y[2]=849.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273715, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=503.0, y[0]=699.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=773.0, y[1]=838.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=294.0, y[2]=849.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273725, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=521.0, y[0]=728.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=776.0, y[1]=862.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=305.0, y[2]=876.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273734, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=535.0, y[0]=765.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=782.0, y[1]=898.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=313.0, y[2]=911.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273741, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=545.0, y[0]=795.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=786.0, y[1]=918.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=323.0, y[2]=941.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273750, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=555.0, y[0]=832.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=790.0, y[1]=959.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=333.0, y[2]=976.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273758, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=560.0, y[0]=870.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=794.0, y[1]=988.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=339.0, y[2]=1020.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273767, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=565.0, y[0]=909.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=797.0, y[1]=1031.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=345.0, y[2]=1052.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273776, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=568.0, y[0]=948.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=801.0, y[1]=1060.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=348.0, y[2]=1102.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273784, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=570.0, y[0]=985.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=804.0, y[1]=1103.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=352.0, y[2]=1130.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273793, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=571.0, y[0]=1028.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=807.0, y[1]=1133.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=355.0, y[2]=1178.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273801, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=572.0, y[0]=1061.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=809.0, y[1]=1175.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=358.0, y[2]=1212.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273810, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=574.0, y[0]=1108.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=811.0, y[1]=1206.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=360.0, y[2]=1260.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273822, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=575.0, y[0]=1141.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=812.0, y[1]=1249.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=363.0, y[2]=1294.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273831, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=576.0, y[0]=1191.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=815.0, y[1]=1281.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=364.0, y[2]=1343.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273836, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=578.0, y[0]=1227.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=816.0, y[1]=1324.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=368.0, y[2]=1374.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273844, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=581.0, y[0]=1276.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=820.0, y[1]=1360.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=371.0, y[2]=1421.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273853, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=581.0, y[0]=1324.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=823.0, y[1]=1406.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=372.0, y[2]=1464.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273862, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=584.0, y[0]=1369.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=824.0, y[1]=1445.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=379.0, y[2]=1506.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273870, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=586.0, y[0]=1417.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=826.0, y[1]=1493.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=387.0, y[2]=1553.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273879, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=586.0, y[0]=1417.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=826.0, y[1]=1493.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=387.0, y[2]=1553.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273888, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_POINTER_UP(0), actionButton=0, id[0]=0, x[0]=586.0, y[0]=1417.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=1, x[1]=826.0, y[1]=1493.0, toolType[1]=TOOL_TYPE_FINGER, id[2]=2, x[2]=387.0, y[2]=1553.0, toolType[2]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=3, historySize=0, eventTime=5273895, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_POINTER_UP(0), actionButton=0, id[0]=1, x[0]=826.0, y[0]=1493.0, toolType[0]=TOOL_TYPE_FINGER, id[1]=2, x[1]=387.0, y[1]=1553.0, toolType[1]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=2, historySize=0, eventTime=5273895, downTime=5273700, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_UP, actionButton=0, id[0]=2, x[0]=387.0, y[0]=1553.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=5273895, downTime=5273700, deviceId=4, source=0x1002, displayId=0 }
\ No newline at end of file diff --git a/services/tests/servicestests/res/raw/a11y_touch_explore_gesture.log b/services/tests/servicestests/res/raw/a11y_touch_explore_gesture.log new file mode 100644 index 000000000000..3cfb0a72181f --- /dev/null +++ b/services/tests/servicestests/res/raw/a11y_touch_explore_gesture.log @@ -0,0 +1,4 @@ +* Gesture4_id-2:Touch explore +MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=825.0, y[0]=2028.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=5258108, downTime=5258108, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_MOVE, actionButton=0, id[0]=0, x[0]=825.0, y[0]=2028.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=5258133, downTime=5258108, deviceId=4, source=0x1002, displayId=0 } +MotionEvent { action=ACTION_UP, actionButton=0, id[0]=0, x[0]=825.0, y[0]=2028.0, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, classification=NONE, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=5258141, downTime=5258108, deviceId=4, source=0x1002, displayId=0 }
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java index 89bd625c8289..7bf0bb873fc3 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java @@ -35,7 +35,10 @@ import static com.android.server.accessibility.gestures.TouchState.STATE_TOUCH_E import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.verify; +import android.accessibilityservice.AccessibilityGestureEvent; +import android.accessibilityservice.AccessibilityService; import android.content.Context; import android.graphics.PointF; import android.os.Looper; @@ -51,6 +54,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.server.accessibility.AccessibilityManagerService; import com.android.server.accessibility.EventStreamTransformation; +import com.android.server.accessibility.utils.GestureLogParser; import com.android.server.testutils.OffsettableClock; import org.junit.Before; @@ -58,7 +62,15 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; - +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; @@ -93,6 +105,11 @@ public class TouchExplorerTest { private int mTouchSlop; private long mLastDownTime = Integer.MIN_VALUE; + @Mock + private AccessibilityManagerService mMockAms; + @Captor + private ArgumentCaptor<AccessibilityGestureEvent> mGestureCaptor; + // mock package-private GestureManifold class @Rule public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = @@ -122,6 +139,7 @@ public class TouchExplorerTest { @Before public void setUp() { + MockitoAnnotations.initMocks(this); if (Looper.myLooper() == null) { Looper.prepare(); } @@ -130,7 +148,7 @@ public class TouchExplorerTest { AccessibilityManagerService ams = new AccessibilityManagerService(mContext); mCaptor = new EventCaptor(); mHandler = new TestHandler(); - mTouchExplorer = new TouchExplorer(mContext, ams, null, mHandler); + mTouchExplorer = new TouchExplorer(mContext, mMockAms, null, mHandler); mTouchExplorer.setNext(mCaptor); } @@ -395,6 +413,61 @@ public class TouchExplorerTest { mTouchExplorer.setMultiFingerGesturesEnabled(false); } + @Test + public void testTouchExploreGestureLog() { + passInGesture(com.android.frameworks.servicestests.R.raw.a11y_touch_explore_gesture, + AccessibilityService.GESTURE_TOUCH_EXPLORATION); + } + @Test + public void testThreeFingerSwipeDownGestureLog() { + passInGesture( + com.android.frameworks.servicestests.R.raw.a11y_three_finger_swipe_down_gesture, + AccessibilityService.GESTURE_3_FINGER_SWIPE_DOWN); + } + + /** + * Used to play back event data of a gesture by parsing the log into MotionEvents and sending + * them to TouchExplorer. + * @param resourceId a raw resource that corresponds to a text file + * @param gestureId the id of the gesture expected to be dispatched + */ + private void passInGesture(int resourceId, int gestureId) { + mTouchExplorer.setMultiFingerGesturesEnabled(true); + mTouchExplorer.setSendMotionEventsEnabled(true); + mTouchExplorer.setTwoFingerPassthroughEnabled(true); + List<Integer> actions = new ArrayList<>(); + try ( + InputStream fis = mContext.getResources().openRawResource(resourceId); + InputStreamReader isr = new InputStreamReader(fis, Charset.forName("UTF-8")); + BufferedReader br = new BufferedReader(isr); + ) { + String line; + while ((line = br.readLine()) != null) { + if (line.isEmpty() || !line.contains("MotionEvent")) { + continue; + } + + MotionEvent motionEvent = GestureLogParser.getMotionEventFromLogLine(line); + actions.add(motionEvent.getAction()); + send(motionEvent); + } + + // Fast forward to dispatch GESTURE_TOUCH_EXPLORATION + mHandler.fastForward(USER_INTENT_TIMEOUT); + } catch (IOException ioException) { + ioException.printStackTrace(); + } + + verify(mMockAms).onGesture(mGestureCaptor.capture()); + AccessibilityGestureEvent gestureEvent = mGestureCaptor.getValue(); + assertEquals(gestureId, gestureEvent.getGestureId()); + List<MotionEvent> motionEvents = gestureEvent.getMotionEvents(); + assertEquals(actions.size(), motionEvents.size()); + for (int i = 0; i < actions.size(); i++) { + assertEquals((int) actions.get(i), motionEvents.get(i).getAction()); + } + } + private static MotionEvent fromTouchscreen(MotionEvent ev) { ev.setSource(InputDevice.SOURCE_TOUCHSCREEN); return ev; diff --git a/services/tests/servicestests/src/com/android/server/accessibility/utils/GestureLogParser.java b/services/tests/servicestests/src/com/android/server/accessibility/utils/GestureLogParser.java new file mode 100644 index 000000000000..cd848f4a018d --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/accessibility/utils/GestureLogParser.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.accessibility.utils; + +import android.view.MotionEvent; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * This class helps parse a gesture event log into its individual MotionEvents + */ +public class GestureLogParser { + /** Gets a MotionEvent from a log line */ + public static MotionEvent getMotionEventFromLogLine(String line) { + final int downTime; + final int eventTime; + int action; + final int pointerCount; + + final MotionEvent.PointerProperties[] properties; + final MotionEvent.PointerCoords[] pointerCoords; + final int metaState; + final int buttonState = 0; + final int xPrecision = 1; + final int yPrecision = 1; + final int deviceId; + final int edgeFlags; + final int source; + final int flags; + final int actionIndex; + + downTime = findInt(line, "downTime=(\\d+)"); + eventTime = findInt(line, "eventTime=(\\d+)"); + action = stringToAction(findString(line, "action=(\\w+)")); + + // For pointer indices + Pattern p = Pattern.compile("action=(\\w+)\\((\\d)"); + Matcher matcher = p.matcher(line); + if (matcher.find()) { + actionIndex = Integer.decode(matcher.group(2)); + action = action | (actionIndex << MotionEvent.ACTION_POINTER_INDEX_SHIFT); + } + + pointerCount = findInt(line, "pointerCount=(\\d+)"); + metaState = findInt(line, "metaState=(\\d+)"); + deviceId = findInt(line, "deviceId=(\\d+)"); + edgeFlags = Integer.decode(findString(line, "edgeFlags=(\\w+)")); + source = Integer.decode(findString(line, "source=(\\w+)")); + flags = Integer.decode(findString(line, "flags=(\\w+)")); + properties = findProperties(line, pointerCount); + pointerCoords = findCoordinates(line, pointerCount); + + return MotionEvent.obtain(downTime, eventTime, action, + pointerCount, properties, pointerCoords, metaState, buttonState, + xPrecision, yPrecision, deviceId, edgeFlags, source, flags); + } + + private static int findInt(String eventText, String pattern) { + final Pattern p = Pattern.compile(pattern); + final Matcher matcher = p.matcher(eventText); + matcher.find(); + return Integer.decode(matcher.group(1)); + } + + private static float findFloat(String eventText, String pattern) { + final Pattern p = Pattern.compile(pattern); + final Matcher matcher = p.matcher(eventText); + matcher.find(); + return Float.parseFloat(matcher.group(1)); + } + + private static String findString(String eventText, String pattern) { + final Pattern p = Pattern.compile(pattern); + final Matcher matcher = p.matcher(eventText); + matcher.find(); + return matcher.group(1); + } + + private static MotionEvent.PointerCoords[] findCoordinates(String eventText, int pointerCount) { + if (pointerCount == 0) { + return null; + } + + final MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[pointerCount]; + float x; + float y; + for (int i = 0; i < pointerCount; i++) { + + x = findFloat(eventText, "x\\[" + i + "\\]=([\\d.]+)"); + y = findFloat(eventText, "y\\[" + i + "\\]=([\\d.]+)"); + + MotionEvent.PointerCoords pointerCoords = new MotionEvent.PointerCoords(); + pointerCoords.x = x; + pointerCoords.y = y; + pointerCoords.pressure = 1; + pointerCoords.size = 1; + + coords[i] = pointerCoords; + } + return coords; + } + + private static MotionEvent.PointerProperties[] findProperties( + String eventText, int pointerCount) { + if (pointerCount == 0) { + return null; + } + + final MotionEvent.PointerProperties[] props = + new MotionEvent.PointerProperties[pointerCount]; + int id; + for (int i = 0; i < pointerCount; i++) { + id = findInt(eventText, "id\\[" + i + "\\]=([\\d])"); + MotionEvent.PointerProperties pointerProps = new MotionEvent.PointerProperties(); + pointerProps.id = id; + pointerProps.toolType = MotionEvent.TOOL_TYPE_FINGER; + props[i] = pointerProps; + } + return props; + } + + private static int stringToAction(String action) { + switch (action) { + case "ACTION_DOWN": + return MotionEvent.ACTION_DOWN; + case "ACTION_UP": + return MotionEvent.ACTION_UP; + case "ACTION_CANCEL": + return MotionEvent.ACTION_CANCEL; + case "ACTION_OUTSIDE": + return MotionEvent.ACTION_OUTSIDE; + case "ACTION_MOVE": + return MotionEvent.ACTION_MOVE; + case "ACTION_HOVER_MOVE": + return MotionEvent.ACTION_HOVER_MOVE; + case "ACTION_SCROLL": + return MotionEvent.ACTION_SCROLL; + case "ACTION_HOVER_ENTER": + return MotionEvent.ACTION_HOVER_ENTER; + case "ACTION_HOVER_EXIT": + return MotionEvent.ACTION_HOVER_EXIT; + case "ACTION_BUTTON_PRESS": + return MotionEvent.ACTION_BUTTON_PRESS; + case "ACTION_BUTTON_RELEASE": + return MotionEvent.ACTION_BUTTON_RELEASE; + case "ACTION_POINTER_DOWN": + return MotionEvent.ACTION_POINTER_DOWN; + case "ACTION_POINTER_UP": + return MotionEvent.ACTION_POINTER_UP; + default: + return -1; + } + } +} |