Skip to content

Commit 45af84a

Browse files
committed
Touch explorer and magnifier do not work well together.
1. If tocuh exploration and screen magnification are enabled and the screen is currently magnified, gesture detection does not work well. The reason is because we are transforming the events if the screen is magnified before passing them to the touch explorer to compensate for the magnification so the user can poke what he thinks he pokes. However, when doing gesture detection/velocity computing this compensating shrinks the gestured shape/ decreases velocity leading to poor gesture reco/incorrect velocity. This change adds a onRawMotionEvent method in the event transformation chain which will process the raw touch events. In this method of the touch explorer we are passing events to the gesture recognized and the velocity tracker. 2. Velocity tracker was not cleared on transitions out of touch exploring state which is the only one that uses velocity. bug:7266617 Change-Id: I7887fe5f3c3bb6cfa203b7866a145c7341098a02
1 parent bfbf6e1 commit 45af84a

File tree

4 files changed

+64
-42
lines changed

4 files changed

+64
-42
lines changed

services/java/com/android/server/accessibility/AccessibilityInputFilter.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,13 +119,16 @@ public void onInputEvent(InputEvent event, int policyFlags) {
119119
mCurrentDeviceId = deviceId;
120120
}
121121
mPm.userActivity(event.getEventTime(), false);
122-
MotionEvent motionEvent = (MotionEvent) event;
123-
mEventHandler.onMotionEvent(motionEvent, policyFlags);
122+
MotionEvent rawEvent = (MotionEvent) event;
123+
MotionEvent transformedEvent = MotionEvent.obtain(rawEvent);
124+
mEventHandler.onMotionEvent(transformedEvent, rawEvent, policyFlags);
125+
transformedEvent.recycle();
124126
}
125127

126128
@Override
127-
public void onMotionEvent(MotionEvent event, int policyFlags) {
128-
sendInputEvent(event, policyFlags);
129+
public void onMotionEvent(MotionEvent transformedEvent, MotionEvent rawEvent,
130+
int policyFlags) {
131+
sendInputEvent(transformedEvent, policyFlags);
129132
}
130133

131134
@Override

services/java/com/android/server/accessibility/EventStreamTransformation.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,15 @@
5757
interface EventStreamTransformation {
5858

5959
/**
60-
* Receives a motion event.
60+
* Receives motion event. Passed are the event transformed by previous
61+
* transformations and the raw event to which no transformations have
62+
* been applied.
6163
*
62-
* @param event The motion event.
64+
* @param event The transformed motion event.
65+
* @param rawEvent The raw motion event.
6366
* @param policyFlags Policy flags for the event.
6467
*/
65-
public void onMotionEvent(MotionEvent event, int policyFlags);
68+
public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags);
6669

6770
/**
6871
* Receives an accessibility event.

services/java/com/android/server/accessibility/ScreenMagnifier.java

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -203,14 +203,15 @@ public ScreenMagnifier(Context context) {
203203
}
204204

205205
@Override
206-
public void onMotionEvent(MotionEvent event, int policyFlags) {
206+
public void onMotionEvent(MotionEvent event, MotionEvent rawEvent,
207+
int policyFlags) {
207208
mMagnifiedContentInteractonStateHandler.onMotionEvent(event);
208209
switch (mCurrentState) {
209210
case STATE_DELEGATING: {
210-
handleMotionEventStateDelegating(event, policyFlags);
211+
handleMotionEventStateDelegating(event, rawEvent, policyFlags);
211212
} break;
212213
case STATE_DETECTING: {
213-
mDetectingStateHandler.onMotionEvent(event, policyFlags);
214+
mDetectingStateHandler.onMotionEvent(event, rawEvent, policyFlags);
214215
} break;
215216
case STATE_VIEWPORT_DRAGGING: {
216217
mStateViewportDraggingHandler.onMotionEvent(event, policyFlags);
@@ -259,7 +260,8 @@ public void onDestroy() {
259260
mScreenStateObserver.destroy();
260261
}
261262

262-
private void handleMotionEventStateDelegating(MotionEvent event, int policyFlags) {
263+
private void handleMotionEventStateDelegating(MotionEvent event,
264+
MotionEvent rawEvent, int policyFlags) {
263265
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
264266
if (mDetectingStateHandler.mDelayedEventQueue == null) {
265267
transitionToState(STATE_DETECTING);
@@ -290,7 +292,7 @@ private void handleMotionEventStateDelegating(MotionEvent event, int policyFlags
290292
coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0, event.getSource(),
291293
event.getFlags());
292294
}
293-
mNext.onMotionEvent(event, policyFlags);
295+
mNext.onMotionEvent(event, rawEvent, policyFlags);
294296
}
295297
}
296298

@@ -533,8 +535,8 @@ public void handleMessage(Message message) {
533535
}
534536
};
535537

536-
public void onMotionEvent(MotionEvent event, int policyFlags) {
537-
cacheDelayedMotionEvent(event, policyFlags);
538+
public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
539+
cacheDelayedMotionEvent(event, rawEvent, policyFlags);
538540
final int action = event.getActionMasked();
539541
switch (action) {
540542
case MotionEvent.ACTION_DOWN: {
@@ -640,8 +642,10 @@ private void clearLastDownEvent() {
640642
}
641643
}
642644

643-
private void cacheDelayedMotionEvent(MotionEvent event, int policyFlags) {
644-
MotionEventInfo info = MotionEventInfo.obtain(event, policyFlags);
645+
private void cacheDelayedMotionEvent(MotionEvent event, MotionEvent rawEvent,
646+
int policyFlags) {
647+
MotionEventInfo info = MotionEventInfo.obtain(event, rawEvent,
648+
policyFlags);
645649
if (mDelayedEventQueue == null) {
646650
mDelayedEventQueue = info;
647651
} else {
@@ -657,7 +661,8 @@ private void sendDelayedMotionEvents() {
657661
while (mDelayedEventQueue != null) {
658662
MotionEventInfo info = mDelayedEventQueue;
659663
mDelayedEventQueue = info.mNext;
660-
ScreenMagnifier.this.onMotionEvent(info.mEvent, info.mPolicyFlags);
664+
ScreenMagnifier.this.onMotionEvent(info.mEvent, info.mRawEvent,
665+
info.mPolicyFlags);
661666
info.recycle();
662667
}
663668
}
@@ -738,9 +743,11 @@ private static final class MotionEventInfo {
738743
private boolean mInPool;
739744

740745
public MotionEvent mEvent;
746+
public MotionEvent mRawEvent;
741747
public int mPolicyFlags;
742748

743-
public static MotionEventInfo obtain(MotionEvent event, int policyFlags) {
749+
public static MotionEventInfo obtain(MotionEvent event, MotionEvent rawEvent,
750+
int policyFlags) {
744751
synchronized (sLock) {
745752
MotionEventInfo info;
746753
if (sPoolSize > 0) {
@@ -752,13 +759,15 @@ public static MotionEventInfo obtain(MotionEvent event, int policyFlags) {
752759
} else {
753760
info = new MotionEventInfo();
754761
}
755-
info.initialize(event, policyFlags);
762+
info.initialize(event, rawEvent, policyFlags);
756763
return info;
757764
}
758765
}
759766

760-
private void initialize(MotionEvent event, int policyFlags) {
767+
private void initialize(MotionEvent event, MotionEvent rawEvent,
768+
int policyFlags) {
761769
mEvent = MotionEvent.obtain(event);
770+
mRawEvent = MotionEvent.obtain(rawEvent);
762771
mPolicyFlags = policyFlags;
763772
}
764773

@@ -780,6 +789,8 @@ public void recycle() {
780789
private void clear() {
781790
mEvent.recycle();
782791
mEvent = null;
792+
mRawEvent.recycle();
793+
mRawEvent = null;
783794
mPolicyFlags = 0;
784795
}
785796
}

services/java/com/android/server/accessibility/TouchExplorer.java

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ class TouchExplorer implements EventStreamTransformation {
162162
private EventStreamTransformation mNext;
163163

164164
// Helper to track gesture velocity.
165-
private VelocityTracker mVelocityTracker;
165+
private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
166166

167167
// Helper class to track received pointers.
168168
private final ReceivedPointerTracker mReceivedPointerTracker;
@@ -309,18 +309,18 @@ public void setNext(EventStreamTransformation next) {
309309
}
310310

311311
@Override
312-
public void onMotionEvent(MotionEvent event, int policyFlags) {
312+
public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
313313
if (DEBUG) {
314314
Slog.d(LOG_TAG, "Received event: " + event + ", policyFlags=0x"
315315
+ Integer.toHexString(policyFlags));
316316
Slog.d(LOG_TAG, getStateSymbolicName(mCurrentState));
317317
}
318318

319-
mReceivedPointerTracker.onMotionEvent(event);
319+
mReceivedPointerTracker.onMotionEvent(rawEvent);
320320

321321
switch(mCurrentState) {
322322
case STATE_TOUCH_EXPLORING: {
323-
handleMotionEventStateTouchExploring(event, policyFlags);
323+
handleMotionEventStateTouchExploring(event, rawEvent, policyFlags);
324324
} break;
325325
case STATE_DRAGGING: {
326326
handleMotionEventStateDragging(event, policyFlags);
@@ -329,7 +329,7 @@ public void onMotionEvent(MotionEvent event, int policyFlags) {
329329
handleMotionEventStateDelegating(event, policyFlags);
330330
} break;
331331
case STATE_GESTURE_DETECTING: {
332-
handleMotionEventGestureDetecting(event, policyFlags);
332+
handleMotionEventGestureDetecting(rawEvent, policyFlags);
333333
} break;
334334
default:
335335
throw new IllegalStateException("Illegal state: " + mCurrentState);
@@ -382,16 +382,15 @@ public void onAccessibilityEvent(AccessibilityEvent event) {
382382
* Handles a motion event in touch exploring state.
383383
*
384384
* @param event The event to be handled.
385+
* @param rawEvent The raw (unmodified) motion event.
385386
* @param policyFlags The policy flags associated with the event.
386387
*/
387-
private void handleMotionEventStateTouchExploring(MotionEvent event, int policyFlags) {
388+
private void handleMotionEventStateTouchExploring(MotionEvent event, MotionEvent rawEvent,
389+
int policyFlags) {
388390
ReceivedPointerTracker receivedTracker = mReceivedPointerTracker;
389391
final int activePointerCount = receivedTracker.getActivePointerCount();
390392

391-
if (mVelocityTracker == null) {
392-
mVelocityTracker = VelocityTracker.obtain();
393-
}
394-
mVelocityTracker.addMovement(event);
393+
mVelocityTracker.addMovement(rawEvent);
395394

396395
mDoubleTapDetector.onMotionEvent(event, policyFlags);
397396

@@ -410,7 +409,7 @@ private void handleMotionEventStateTouchExploring(MotionEvent event, int policyF
410409
// have a distance slop before getting into gesture detection
411410
// mode and not using the points within this slop significantly
412411
// decreases the quality of gesture recognition.
413-
handleMotionEventGestureDetecting(event, policyFlags);
412+
handleMotionEventGestureDetecting(rawEvent, policyFlags);
414413
//$FALL-THROUGH$
415414
case MotionEvent.ACTION_POINTER_DOWN: {
416415
switch (activePointerCount) {
@@ -471,12 +470,13 @@ private void handleMotionEventStateTouchExploring(MotionEvent event, int policyF
471470
// have a distance slop before getting into gesture detection
472471
// mode and not using the points within this slop significantly
473472
// decreases the quality of gesture recognition.
474-
handleMotionEventGestureDetecting(event, policyFlags);
475-
473+
handleMotionEventGestureDetecting(rawEvent, policyFlags);
474+
// It is *important* to use the distance traveled by the pointers
475+
// on the screen which may or may not be magnified.
476476
final float deltaX = receivedTracker.getReceivedPointerDownX(pointerId)
477-
- event.getX(pointerIndex);
477+
- rawEvent.getX(pointerIndex);
478478
final float deltaY = receivedTracker.getReceivedPointerDownY(pointerId)
479-
- event.getY(pointerIndex);
479+
- rawEvent.getY(pointerIndex);
480480
final double moveDelta = Math.hypot(deltaX, deltaY);
481481
// The user has moved enough for us to decide.
482482
if (moveDelta > mDoubleTapSlop) {
@@ -491,6 +491,7 @@ private void handleMotionEventStateTouchExploring(MotionEvent event, int policyF
491491
// We have to perform gesture detection, so
492492
// clear the current state and try to detect.
493493
mCurrentState = STATE_GESTURE_DETECTING;
494+
mVelocityTracker.clear();
494495
mSendHoverEnterDelayed.remove();
495496
mSendHoverExitDelayed.remove();
496497
mPerformLongPressDelayed.remove();
@@ -535,10 +536,12 @@ private void handleMotionEventStateTouchExploring(MotionEvent event, int policyF
535536
// If the user is touch exploring the second pointer may be
536537
// performing a double tap to activate an item without need
537538
// for the user to lift his exploring finger.
539+
// It is *important* to use the distance traveled by the pointers
540+
// on the screen which may or may not be magnified.
538541
final float deltaX = receivedTracker.getReceivedPointerDownX(pointerId)
539-
- event.getX(pointerIndex);
542+
- rawEvent.getX(pointerIndex);
540543
final float deltaY = receivedTracker.getReceivedPointerDownY(pointerId)
541-
- event.getY(pointerIndex);
544+
- rawEvent.getY(pointerIndex);
542545
final double moveDelta = Math.hypot(deltaX, deltaY);
543546
if (moveDelta < mDoubleTapSlop) {
544547
break;
@@ -565,6 +568,7 @@ private void handleMotionEventStateTouchExploring(MotionEvent event, int policyF
565568
mCurrentState = STATE_DELEGATING;
566569
sendDownForAllActiveNotInjectedPointers(event, policyFlags);
567570
}
571+
mVelocityTracker.clear();
568572
} break;
569573
default: {
570574
// More than one pointer so the user is not touch exploring
@@ -585,6 +589,7 @@ private void handleMotionEventStateTouchExploring(MotionEvent event, int policyF
585589
// More than two pointers are delegated to the view hierarchy.
586590
mCurrentState = STATE_DELEGATING;
587591
sendDownForAllActiveNotInjectedPointers(event, policyFlags);
592+
mVelocityTracker.clear();
588593
}
589594
}
590595
} break;
@@ -615,10 +620,7 @@ private void handleMotionEventStateTouchExploring(MotionEvent event, int policyF
615620
}
616621
} break;
617622
}
618-
if (mVelocityTracker != null) {
619-
mVelocityTracker.clear();
620-
mVelocityTracker = null;
621-
}
623+
mVelocityTracker.clear();
622624
} break;
623625
case MotionEvent.ACTION_CANCEL: {
624626
clear(event, policyFlags);
@@ -1046,7 +1048,10 @@ private void sendMotionEvent(MotionEvent prototype, int action, int pointerIdBit
10461048
// Make sure that the user will see the event.
10471049
policyFlags |= WindowManagerPolicy.FLAG_PASS_TO_USER;
10481050
if (mNext != null) {
1049-
mNext.onMotionEvent(event, policyFlags);
1051+
// TODO: For now pass null for the raw event since the touch
1052+
// explorer is the last event transformation and it does
1053+
// not care about the raw event.
1054+
mNext.onMotionEvent(event, null, policyFlags);
10501055
}
10511056

10521057
mInjectedPointerTracker.onMotionEvent(event);

0 commit comments

Comments
 (0)