Merge "Add support to play back MotionEvent data for gestures"

This commit is contained in:
Sally Yuen
2020-12-15 01:27:15 +00:00
committed by Android (Google) Code Review
5 changed files with 292 additions and 17 deletions

View File

@@ -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 { "

View File

@@ -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 }

View File

@@ -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 }

View File

@@ -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;

View File

@@ -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;
}
}
}