TouchExplorer: pass raw events when sending events.
Right now we just send null. This was a todo to be fixed and will mean that the event stream operates consistently.
Bug: 136131815
Test: atest CtsAccessibilityTestCases CtsAccessibilityServiceTestCases
Test: atest FrameworksServicesTests:TouchExplorerTest FrameworksServicesTests:MotionEventInjectorTest
Change-Id: I4578ef4ffe6d3c3e4fc2aa2d06fc0caaa8bb9713
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
index dc7a9aa..5ac3b69 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
@@ -72,10 +72,16 @@
*
* @param prototype The prototype from which to create the injected events.
* @param action The action of the event.
+ * @param rawEvent The original event prior to magnification or other transformations.
* @param pointerIdBits The bits of the pointers to send.
* @param policyFlags The policy flags associated with the event.
*/
- void sendMotionEvent(MotionEvent prototype, int action, int pointerIdBits, int policyFlags) {
+ void sendMotionEvent(
+ MotionEvent prototype,
+ int action,
+ MotionEvent rawEvent,
+ int pointerIdBits,
+ int policyFlags) {
prototype.setAction(action);
MotionEvent event = null;
@@ -105,11 +111,8 @@
// Make sure that the user will see the event.
policyFlags |= WindowManagerPolicy.FLAG_PASS_TO_USER;
- // TODO: For now pass null for the raw event since the touch
- // explorer is the last event transformation and it does
- // not care about the raw event.
if (mReceiver != null) {
- mReceiver.onMotionEvent(event, null, policyFlags);
+ mReceiver.onMotionEvent(event, rawEvent, policyFlags);
} else {
Slog.e(LOG_TAG, "Error sending event: no receiver specified.");
}
@@ -280,7 +283,12 @@
if (!isInjectedPointerDown(pointerId)) {
pointerIdBits |= (1 << pointerId);
final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, i);
- sendMotionEvent(prototype, action, pointerIdBits, policyFlags);
+ sendMotionEvent(
+ prototype,
+ action,
+ mState.getLastReceivedEvent(),
+ pointerIdBits,
+ policyFlags);
}
}
}
@@ -303,7 +311,8 @@
}
pointerIdBits |= (1 << pointerId);
final int action = computeInjectionAction(MotionEvent.ACTION_UP, i);
- sendMotionEvent(prototype, action, pointerIdBits, policyFlags);
+ sendMotionEvent(
+ prototype, action, mState.getLastReceivedEvent(), pointerIdBits, policyFlags);
}
}
}
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 f4ac821..c60e35e 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -183,9 +183,9 @@
private void clear() {
// If we have not received an event then we are in initial
// state. Therefore, there is not need to clean anything.
- MotionEvent event = mReceivedPointerTracker.getLastReceivedEvent();
+ MotionEvent event = mState.getLastReceivedEvent();
if (event != null) {
- clear(mReceivedPointerTracker.getLastReceivedEvent(), WindowManagerPolicy.FLAG_TRUSTED);
+ clear(event, WindowManagerPolicy.FLAG_TRUSTED);
}
}
@@ -229,7 +229,7 @@
Slog.d(LOG_TAG, mState.toString());
}
- mReceivedPointerTracker.onMotionEvent(rawEvent);
+ mState.onReceivedMotionEvent(rawEvent);
if (mGestureDetector.onMotionEvent(event, rawEvent, policyFlags)) {
// Event was handled by the gesture detector.
@@ -250,9 +250,9 @@
} else if (mState.isTouchExploring()) {
handleMotionEventStateTouchExploring(event, rawEvent, policyFlags);
} else if (mState.isDragging()) {
- handleMotionEventStateDragging(event, policyFlags);
+ handleMotionEventStateDragging(event, rawEvent, policyFlags);
} else if (mState.isDelegating()) {
- handleMotionEventStateDelegating(event, policyFlags);
+ handleMotionEventStateDelegating(event, rawEvent, policyFlags);
} else if (mState.isGestureDetecting()) {
// Already handled.
} else {
@@ -292,7 +292,7 @@
}
// Pointers should not be zero when running this command.
- if (mReceivedPointerTracker.getLastReceivedEvent().getPointerCount() == 0) {
+ if (mState.getLastReceivedEvent().getPointerCount() == 0) {
return;
}
// Try to use the standard accessibility API to long click
@@ -368,11 +368,15 @@
// We have just decided that the user is touch,
// exploring so start sending events.
- mSendHoverEnterAndMoveDelayed.addEvent(event);
+ mSendHoverEnterAndMoveDelayed.addEvent(event, mState.getLastReceivedEvent());
mSendHoverEnterAndMoveDelayed.forceSendAndRemove();
mSendHoverExitDelayed.cancel();
mDispatcher.sendMotionEvent(
- event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags);
+ event,
+ MotionEvent.ACTION_HOVER_MOVE,
+ mState.getLastReceivedEvent(),
+ pointerIdBits,
+ policyFlags);
return true;
}
}
@@ -387,7 +391,7 @@
switch (event.getActionMasked()) {
// The only way to leave the clear state is for a pointer to go down.
case MotionEvent.ACTION_DOWN:
- handleActionDown(event, policyFlags);
+ handleActionDown(event, rawEvent, policyFlags);
break;
default:
// Some other nonsensical event.
@@ -399,7 +403,7 @@
* Handles ACTION_DOWN while in the clear or touch interacting states. This event represents the
* first finger touching the screen.
*/
- private void handleActionDown(MotionEvent event, int policyFlags) {
+ private void handleActionDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
mAms.onTouchInteractionStart();
// If we still have not notified the user for the last
@@ -432,10 +436,10 @@
// The idea is to avoid getting stuck in STATE_TOUCH_INTERACTING
final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
final int pointerIdBits = (1 << pointerId);
- mSendHoverEnterAndMoveDelayed.post(event, pointerIdBits, policyFlags);
+ mSendHoverEnterAndMoveDelayed.post(event, rawEvent, pointerIdBits, policyFlags);
} else {
// Cache the event until we discern exploration from gesturing.
- mSendHoverEnterAndMoveDelayed.addEvent(event);
+ mSendHoverEnterAndMoveDelayed.addEvent(event, rawEvent);
}
}
}
@@ -453,7 +457,7 @@
case MotionEvent.ACTION_DOWN:
// Continue the previous interaction.
mSendTouchInteractionEndDelayed.cancel();
- handleActionDown(event, policyFlags);
+ handleActionDown(event, rawEvent, policyFlags);
break;
case MotionEvent.ACTION_POINTER_DOWN:
handleActionPointerDown();
@@ -462,7 +466,7 @@
handleActionMoveStateTouchInteracting(event, rawEvent, policyFlags);
break;
case MotionEvent.ACTION_UP:
- handleActionUp(event, policyFlags);
+ handleActionUp(event, rawEvent, policyFlags);
break;
}
}
@@ -487,7 +491,7 @@
handleActionMoveStateTouchExploring(event, rawEvent, policyFlags);
break;
case MotionEvent.ACTION_UP:
- handleActionUp(event, policyFlags);
+ handleActionUp(event, rawEvent, policyFlags);
break;
default:
break;
@@ -520,7 +524,7 @@
// figure out what the user is doing.
if (mSendHoverEnterAndMoveDelayed.isPending()) {
// Cache the event until we discern exploration from gesturing.
- mSendHoverEnterAndMoveDelayed.addEvent(event);
+ mSendHoverEnterAndMoveDelayed.addEvent(event, rawEvent);
}
break;
case 2:
@@ -538,7 +542,7 @@
mDraggingPointerId = pointerId;
event.setEdgeFlags(mReceivedPointerTracker.getLastReceivedDownEdgeFlags());
mDispatcher.sendMotionEvent(
- event, MotionEvent.ACTION_DOWN, pointerIdBits, policyFlags);
+ event, MotionEvent.ACTION_DOWN, rawEvent, pointerIdBits, policyFlags);
} else {
// Two pointers moving arbitrary are delegated to the view hierarchy.
mState.startDelegating();
@@ -558,13 +562,13 @@
* Handles ACTION_UP while in the touch interacting state. This event represents all fingers
* being lifted from the screen.
*/
- private void handleActionUp(MotionEvent event, int policyFlags) {
+ private void handleActionUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
mAms.onTouchInteractionEnd();
final int pointerId = event.getPointerId(event.getActionIndex());
final int pointerIdBits = (1 << pointerId);
if (mSendHoverEnterAndMoveDelayed.isPending()) {
// If we have not delivered the enter schedule an exit.
- mSendHoverExitDelayed.post(event, pointerIdBits, policyFlags);
+ mSendHoverExitDelayed.post(event, rawEvent, pointerIdBits, policyFlags);
} else {
// The user is touch exploring so we send events for end.
sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
@@ -588,7 +592,7 @@
// Touch exploration.
sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags);
mDispatcher.sendMotionEvent(
- event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags);
+ event, MotionEvent.ACTION_HOVER_MOVE, rawEvent, pointerIdBits, policyFlags);
break;
case 2:
if (mSendHoverEnterAndMoveDelayed.isPending()) {
@@ -638,7 +642,8 @@
* @param event The event to be handled.
* @param policyFlags The policy flags associated with the event.
*/
- private void handleMotionEventStateDragging(MotionEvent event, int policyFlags) {
+ private void handleMotionEventStateDragging(
+ MotionEvent event, MotionEvent rawEvent, int policyFlags) {
int pointerIdBits = 0;
// Clear the dragging pointer id if it's no longer valid.
if (event.findPointerIndex(mDraggingPointerId) == -1) {
@@ -662,7 +667,7 @@
mState.startDelegating();
if (mDraggingPointerId != INVALID_POINTER_ID) {
mDispatcher.sendMotionEvent(
- event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
+ event, MotionEvent.ACTION_UP, rawEvent, pointerIdBits, policyFlags);
}
mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
} break;
@@ -681,6 +686,7 @@
mDispatcher.sendMotionEvent(
event,
MotionEvent.ACTION_MOVE,
+ rawEvent,
pointerIdBits,
policyFlags);
} else {
@@ -690,7 +696,11 @@
// Remove move history before send injected non-move events
event = MotionEvent.obtainNoHistory(event);
// Send an event to the end of the drag gesture.
- mDispatcher.sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits,
+ mDispatcher.sendMotionEvent(
+ event,
+ MotionEvent.ACTION_UP,
+ rawEvent,
+ pointerIdBits,
policyFlags);
// Deliver all pointers to the view hierarchy.
mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
@@ -700,7 +710,11 @@
mState.startDelegating();
event = MotionEvent.obtainNoHistory(event);
// Send an event to the end of the drag gesture.
- mDispatcher.sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits,
+ mDispatcher.sendMotionEvent(
+ event,
+ MotionEvent.ACTION_UP,
+ rawEvent,
+ pointerIdBits,
policyFlags);
// Deliver all pointers to the view hierarchy.
mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
@@ -713,7 +727,7 @@
mDraggingPointerId = INVALID_POINTER_ID;
// Send an event to the end of the drag gesture.
mDispatcher.sendMotionEvent(
- event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
+ event, MotionEvent.ACTION_UP, rawEvent, pointerIdBits, policyFlags);
}
} break;
case MotionEvent.ACTION_UP: {
@@ -726,7 +740,7 @@
mDraggingPointerId = INVALID_POINTER_ID;
// Send an event to the end of the drag gesture.
mDispatcher.sendMotionEvent(
- event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
+ event, MotionEvent.ACTION_UP, rawEvent, pointerIdBits, policyFlags);
}
} break;
}
@@ -738,7 +752,8 @@
* @param event The event to be handled.
* @param policyFlags The policy flags associated with the event.
*/
- private void handleMotionEventStateDelegating(MotionEvent event, int policyFlags) {
+ private void handleMotionEventStateDelegating(
+ MotionEvent event, MotionEvent rawEvent, int policyFlags) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
Slog.e(LOG_TAG, "Delegating state can only be reached if "
@@ -749,7 +764,7 @@
case MotionEvent.ACTION_UP: {
// Deliver the event.
mDispatcher.sendMotionEvent(
- event, event.getAction(), ALL_POINTER_ID_BITS, policyFlags);
+ event, event.getAction(), rawEvent, ALL_POINTER_ID_BITS, policyFlags);
// Announce the end of a the touch interaction.
mAms.onTouchInteractionEnd();
@@ -759,7 +774,7 @@
default: {
// Deliver the event.
mDispatcher.sendMotionEvent(
- event, event.getAction(), ALL_POINTER_ID_BITS, policyFlags);
+ event, event.getAction(), rawEvent, ALL_POINTER_ID_BITS, policyFlags);
}
}
}
@@ -792,7 +807,11 @@
mSendTouchExplorationEndDelayed.post();
}
mDispatcher.sendMotionEvent(
- event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits, policyFlags);
+ event,
+ MotionEvent.ACTION_HOVER_EXIT,
+ mState.getLastReceivedEvent(),
+ pointerIdBits,
+ policyFlags);
}
}
@@ -807,7 +826,11 @@
if (event != null && event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
final int pointerIdBits = event.getPointerIdBits();
mDispatcher.sendMotionEvent(
- event, MotionEvent.ACTION_HOVER_ENTER, pointerIdBits, policyFlags);
+ event,
+ MotionEvent.ACTION_HOVER_ENTER,
+ mState.getLastReceivedEvent(),
+ pointerIdBits,
+ policyFlags);
}
}
@@ -891,20 +914,23 @@
private final String LOG_TAG_SEND_HOVER_DELAYED = "SendHoverEnterAndMoveDelayed";
private final List<MotionEvent> mEvents = new ArrayList<MotionEvent>();
+ private final List<MotionEvent> mRawEvents = new ArrayList<MotionEvent>();
private int mPointerIdBits;
private int mPolicyFlags;
- public void post(MotionEvent event, int pointerIdBits, int policyFlags) {
+ public void post(
+ MotionEvent event, MotionEvent rawEvent, int pointerIdBits, int policyFlags) {
cancel();
- addEvent(event);
+ addEvent(event, rawEvent);
mPointerIdBits = pointerIdBits;
mPolicyFlags = policyFlags;
mHandler.postDelayed(this, mDetermineUserIntentTimeout);
}
- public void addEvent(MotionEvent event) {
+ public void addEvent(MotionEvent event, MotionEvent rawEvent) {
mEvents.add(MotionEvent.obtain(event));
+ mRawEvents.add(MotionEvent.obtain(rawEvent));
}
public void cancel() {
@@ -925,6 +951,10 @@
for (int i = eventCount - 1; i >= 0; i--) {
mEvents.remove(i).recycle();
}
+ final int rawEventcount = mRawEvents.size();
+ for (int i = rawEventcount - 1; i >= 0; i--) {
+ mRawEvents.remove(i).recycle();
+ }
}
public void forceSendAndRemove() {
@@ -939,10 +969,10 @@
mDispatcher.sendAccessibilityEvent(
AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
- if (!mEvents.isEmpty()) {
+ if (!mEvents.isEmpty() && !mRawEvents.isEmpty()) {
// Deliver a down event.
mDispatcher.sendMotionEvent(mEvents.get(0), MotionEvent.ACTION_HOVER_ENTER,
- mPointerIdBits, mPolicyFlags);
+ mRawEvents.get(0), mPointerIdBits, mPolicyFlags);
if (DEBUG) {
Slog.d(LOG_TAG_SEND_HOVER_DELAYED,
"Injecting motion event: ACTION_HOVER_ENTER");
@@ -952,7 +982,7 @@
final int eventCount = mEvents.size();
for (int i = 1; i < eventCount; i++) {
mDispatcher.sendMotionEvent(mEvents.get(i), MotionEvent.ACTION_HOVER_MOVE,
- mPointerIdBits, mPolicyFlags);
+ mRawEvents.get(i), mPointerIdBits, mPolicyFlags);
if (DEBUG) {
Slog.d(LOG_TAG_SEND_HOVER_DELAYED,
"Injecting motion event: ACTION_HOVER_MOVE");
@@ -970,12 +1000,15 @@
private final String LOG_TAG_SEND_HOVER_DELAYED = "SendHoverExitDelayed";
private MotionEvent mPrototype;
+ private MotionEvent mRawEvent;
private int mPointerIdBits;
private int mPolicyFlags;
- public void post(MotionEvent prototype, int pointerIdBits, int policyFlags) {
+ public void post(
+ MotionEvent prototype, MotionEvent rawEvent, int pointerIdBits, int policyFlags) {
cancel();
mPrototype = MotionEvent.obtain(prototype);
+ mRawEvent = MotionEvent.obtain(rawEvent);
mPointerIdBits = pointerIdBits;
mPolicyFlags = policyFlags;
mHandler.postDelayed(this, mDetermineUserIntentTimeout);
@@ -993,8 +1026,14 @@
}
private void clear() {
- mPrototype.recycle();
+ if (mPrototype != null) {
+ mPrototype.recycle();
+ }
+ if (mRawEvent != null) {
+ mRawEvent.recycle();
+ }
mPrototype = null;
+ mRawEvent = null;
mPointerIdBits = -1;
mPolicyFlags = 0;
}
@@ -1011,8 +1050,12 @@
Slog.d(LOG_TAG_SEND_HOVER_DELAYED, "Injecting motion event:"
+ " ACTION_HOVER_EXIT");
}
- mDispatcher.sendMotionEvent(mPrototype, MotionEvent.ACTION_HOVER_EXIT,
- mPointerIdBits, mPolicyFlags);
+ mDispatcher.sendMotionEvent(
+ mPrototype,
+ MotionEvent.ACTION_HOVER_EXIT,
+ mRawEvent,
+ mPointerIdBits,
+ mPolicyFlags);
if (!mSendTouchExplorationEndDelayed.isPending()) {
mSendTouchExplorationEndDelayed.cancel();
mSendTouchExplorationEndDelayed.post();
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
index 49938fa..f463260 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
@@ -71,6 +71,7 @@
// Helper class to track received pointers.
// Todo: collapse or hide this class so multiple classes don't modify it.
private final ReceivedPointerTracker mReceivedPointerTracker;
+ private MotionEvent mLastReceivedEvent;
public TouchState() {
mReceivedPointerTracker = new ReceivedPointerTracker();
@@ -80,6 +81,10 @@
public void clear() {
setState(STATE_CLEAR);
// Reset the pointer trackers.
+ if (mLastReceivedEvent != null) {
+ mLastReceivedEvent.recycle();
+ mLastReceivedEvent = null;
+ }
mReceivedPointerTracker.clear();
}
@@ -89,6 +94,10 @@
* @param rawEvent The raw touch event.
*/
public void onReceivedMotionEvent(MotionEvent rawEvent) {
+ if (mLastReceivedEvent != null) {
+ mLastReceivedEvent.recycle();
+ }
+ mLastReceivedEvent = MotionEvent.obtain(rawEvent);
mReceivedPointerTracker.onMotionEvent(rawEvent);
}
@@ -216,6 +225,11 @@
return mReceivedPointerTracker;
}
+ /** @return The last received event. */
+ public MotionEvent getLastReceivedEvent() {
+ return mLastReceivedEvent;
+ }
+
/** This class tracks where and when a pointer went down. It does not track its movement. */
class ReceivedPointerTracker {
private static final String LOG_TAG_RECEIVED_POINTER_TRACKER = "ReceivedPointerTracker";
@@ -232,8 +246,6 @@
// or if it goes up the next one that most recently went down.
private int mPrimaryPointerId;
- // Keep track of the last up pointer data.
- private MotionEvent mLastReceivedEvent;
ReceivedPointerTracker() {
clear();
@@ -254,11 +266,6 @@
* @param event The event to process.
*/
public void onMotionEvent(MotionEvent event) {
- if (mLastReceivedEvent != null) {
- mLastReceivedEvent.recycle();
- }
- mLastReceivedEvent = MotionEvent.obtain(event);
-
final int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
@@ -279,11 +286,6 @@
}
}
- /** @return The last received event. */
- public MotionEvent getLastReceivedEvent() {
- return mLastReceivedEvent;
- }
-
/** @return The number of received pointers that are down. */
public int getReceivedPointerDownCount() {
return Integer.bitCount(mReceivedPointersDown);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
index f1142fd..36e854c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
@@ -46,7 +46,6 @@
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
-import android.util.Log;
import android.view.Display;
import android.view.InputDevice;
import android.view.KeyEvent;
@@ -55,6 +54,8 @@
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.accessibility.utils.MotionEventMatcher;
+
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
@@ -761,56 +762,6 @@
return next;
}
- static class MotionEventMatcher extends TypeSafeMatcher<MotionEvent> {
- long mDownTime;
- long mEventTime;
- long mActionMasked;
- int mX;
- int mY;
-
- MotionEventMatcher(long downTime, long eventTime, int actionMasked, int x, int y) {
- mDownTime = downTime;
- mEventTime = eventTime;
- mActionMasked = actionMasked;
- mX = x;
- mY = y;
- }
-
- MotionEventMatcher(MotionEvent event) {
- this(event.getDownTime(), event.getEventTime(), event.getActionMasked(),
- (int) event.getX(), (int) event.getY());
- }
-
- void offsetTimesBy(long timeOffset) {
- mDownTime += timeOffset;
- mEventTime += timeOffset;
- }
-
- @Override
- public boolean matchesSafely(MotionEvent event) {
- if ((event.getDownTime() == mDownTime) && (event.getEventTime() == mEventTime)
- && (event.getActionMasked() == mActionMasked) && ((int) event.getX() == mX)
- && ((int) event.getY() == mY)) {
- return true;
- }
- Log.e(LOG_TAG, "MotionEvent match failed");
- Log.e(LOG_TAG, "event.getDownTime() = " + event.getDownTime()
- + ", expected " + mDownTime);
- Log.e(LOG_TAG, "event.getEventTime() = " + event.getEventTime()
- + ", expected " + mEventTime);
- Log.e(LOG_TAG, "event.getActionMasked() = " + event.getActionMasked()
- + ", expected " + mActionMasked);
- Log.e(LOG_TAG, "event.getX() = " + event.getX() + ", expected " + mX);
- Log.e(LOG_TAG, "event.getY() = " + event.getY() + ", expected " + mY);
- return false;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("Motion event matcher");
- }
- }
-
private static class MotionEventActionMatcher extends TypeSafeMatcher<MotionEvent> {
int mAction;
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 104aacb..4b1ec6f 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
@@ -21,6 +21,7 @@
import static com.android.server.accessibility.gestures.TouchState.STATE_DRAGGING;
import static com.android.server.accessibility.gestures.TouchState.STATE_TOUCH_EXPLORING;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
@@ -36,6 +37,7 @@
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accessibility.EventStreamTransformation;
+import com.android.server.accessibility.utils.MotionEventMatcher;
import org.junit.Before;
import org.junit.Rule;
@@ -49,6 +51,7 @@
@RunWith(AndroidJUnit4.class)
public class TouchExplorerTest {
+ private static final String LOG_TAG = "TouchExplorerTest";
private static final int FLAG_1FINGER = 0x8000;
private static final int FLAG_2FINGERS = 0x0100;
private static final int FLAG_3FINGERS = 0x0200;
@@ -86,7 +89,9 @@
@Override
public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ MotionEventMatcher lastEventMatcher = new MotionEventMatcher(mLastEvent);
mEvents.add(0, event.copy());
+ assertThat(rawEvent, lastEventMatcher);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/utils/MotionEventMatcher.java b/services/tests/servicestests/src/com/android/server/accessibility/utils/MotionEventMatcher.java
new file mode 100644
index 0000000..2b6d385
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/utils/MotionEventMatcher.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 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.util.Log;
+import android.view.MotionEvent;
+
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+
+/**
+ * This class compares two motion events using a subset of their attributes: actionMasked, downTime,
+ * eventTime, and location. If two events match they are considered to be effectively equal.
+ */
+public class MotionEventMatcher extends TypeSafeMatcher<MotionEvent> {
+ private static final String LOG_TAG = "MotionEventMatcher";
+ long mDownTime;
+ long mEventTime;
+ long mActionMasked;
+ int mX;
+ int mY;
+
+ MotionEventMatcher(long downTime, long eventTime, int actionMasked, int x, int y) {
+ mDownTime = downTime;
+ mEventTime = eventTime;
+ mActionMasked = actionMasked;
+ mX = x;
+ mY = y;
+ }
+
+ public MotionEventMatcher(MotionEvent event) {
+ this(
+ event.getDownTime(),
+ event.getEventTime(),
+ event.getActionMasked(),
+ (int) event.getX(),
+ (int) event.getY());
+ }
+
+ void offsetTimesBy(long timeOffset) {
+ mDownTime += timeOffset;
+ mEventTime += timeOffset;
+ }
+
+ @Override
+ public boolean matchesSafely(MotionEvent event) {
+ if ((event.getDownTime() == mDownTime)
+ && (event.getEventTime() == mEventTime)
+ && (event.getActionMasked() == mActionMasked)
+ && ((int) event.getX() == mX)
+ && ((int) event.getY() == mY)) {
+ return true;
+ }
+ Log.e(LOG_TAG, "MotionEvent match failed");
+ Log.e(LOG_TAG, "event.getDownTime() = " + event.getDownTime() + ", expected " + mDownTime);
+ Log.e(
+ LOG_TAG,
+ "event.getEventTime() = " + event.getEventTime() + ", expected " + mEventTime);
+ Log.e(
+ LOG_TAG,
+ "event.getActionMasked() = "
+ + event.getActionMasked()
+ + ", expected "
+ + mActionMasked);
+ Log.e(LOG_TAG, "event.getX() = " + event.getX() + ", expected " + mX);
+ Log.e(LOG_TAG, "event.getY() = " + event.getY() + ", expected " + mY);
+ return false;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("Motion event matcher");
+ }
+}