Loading services/accessibility/java/com/android/server/accessibility/TouchExplorer.java +64 −76 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.graphics.Rect; import android.os.Handler; import android.os.SystemClock; import android.util.Slog; import android.view.GestureDetector; import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; Loading Loading @@ -114,9 +115,6 @@ class TouchExplorer implements EventStreamTransformation { // Timeout within which we try to detect a tap. private final int mTapTimeout; // Timeout within which we try to detect a double tap. private final int mDoubleTapTimeout; // Slop between the down and up tap to be a tap. private final int mTouchSlop; Loading Loading @@ -230,7 +228,6 @@ class TouchExplorer implements EventStreamTransformation { mInjectedPointerTracker = new InjectedPointerTracker(); mTapTimeout = ViewConfiguration.getTapTimeout(); mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout(); mDoubleTapTimeout = ViewConfiguration.getDoubleTapTimeout(); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop(); mHandler = new Handler(context.getMainLooper()); Loading @@ -248,7 +245,7 @@ class TouchExplorer implements EventStreamTransformation { mSendTouchInteractionEndDelayed = new SendAccessibilityEventDelayed( AccessibilityEvent.TYPE_TOUCH_INTERACTION_END, mDetermineUserIntentTimeout); mDoubleTapDetector = new DoubleTapDetector(); mDoubleTapDetector = new DoubleTapDetector(mContext); final float density = context.getResources().getDisplayMetrics().density; mScaledMinPointerDistanceToUseMiddleLocation = (int) (MIN_POINTER_DISTANCE_TO_USE_MIDDLE_LOCATION_DIP * density); Loading Loading @@ -1109,66 +1106,63 @@ class TouchExplorer implements EventStreamTransformation { } } private class DoubleTapDetector { private MotionEvent mDownEvent; private MotionEvent mFirstTapEvent; private class DoubleTapDetector extends GestureDetector.SimpleOnGestureListener { private final GestureDetector mGestureDetector; private boolean mFirstTapDetected; private boolean mDoubleTapDetected; DoubleTapDetector(Context context) { mGestureDetector = new GestureDetector(context, this); mGestureDetector.setOnDoubleTapListener(this); } public void onMotionEvent(MotionEvent event, int policyFlags) { final int actionIndex = event.getActionIndex(); final int action = event.getActionMasked(); switch (action) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_DOWN: { if (mFirstTapEvent != null && !GestureUtils.isSamePointerContext(mFirstTapEvent, event)) { clear(); } mDownEvent = MotionEvent.obtain(event); } break; mDoubleTapDetected = false; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: { if (mDownEvent == null) { return; } if (!GestureUtils.isSamePointerContext(mDownEvent, event)) { clear(); return; maybeFinishDoubleTap(event, policyFlags); break; } if (GestureUtils.isTap(mDownEvent, event, mTapTimeout, mTouchSlop, actionIndex)) { if (mFirstTapEvent == null || GestureUtils.isTimedOut(mFirstTapEvent, event, mDoubleTapTimeout)) { mFirstTapEvent = MotionEvent.obtain(event); mDownEvent.recycle(); mDownEvent = null; return; mGestureDetector.onTouchEvent(event); } if (GestureUtils.isMultiTap(mFirstTapEvent, event, mDoubleTapTimeout, mDoubleTapSlop, actionIndex)) { onDoubleTap(event, policyFlags); mFirstTapEvent.recycle(); mFirstTapEvent = null; mDownEvent.recycle(); mDownEvent = null; return; @Override public boolean onDown(MotionEvent event) { return true; } mFirstTapEvent.recycle(); mFirstTapEvent = null; } else { if (mFirstTapEvent != null) { mFirstTapEvent.recycle(); mFirstTapEvent = null; @Override public boolean onSingleTapUp(MotionEvent event) { mFirstTapDetected = true; return false; } @Override public boolean onSingleTapConfirmed(MotionEvent event) { clear(); return false; } mDownEvent.recycle(); mDownEvent = null; } break; @Override public boolean onDoubleTap(MotionEvent event) { // The processing of the double tap is deferred until the finger is // lifted, so that we can detect a long press on the second tap. mDoubleTapDetected = true; return true; } private void maybeFinishDoubleTap(MotionEvent event, int policyFlags) { if (!mDoubleTapDetected) { return; } public void onDoubleTap(MotionEvent secondTapUp, int policyFlags) { clear(); // This should never be called when more than two pointers are down. if (secondTapUp.getPointerCount() > 2) { if (event.getPointerCount() > 2) { return; } Loading @@ -1184,8 +1178,8 @@ class TouchExplorer implements EventStreamTransformation { mSendTouchInteractionEndDelayed.forceSendAndRemove(); } final int pointerId = secondTapUp.getPointerId(secondTapUp.getActionIndex()); final int pointerIndex = secondTapUp.findPointerIndex(pointerId); final int pointerId = event.getPointerId(event.getActionIndex()); final int pointerIndex = event.findPointerIndex(pointerId); Point clickLocation = mTempPoint; final int result = computeClickLocation(clickLocation); Loading @@ -1196,34 +1190,28 @@ class TouchExplorer implements EventStreamTransformation { // Do the click. PointerProperties[] properties = new PointerProperties[1]; properties[0] = new PointerProperties(); secondTapUp.getPointerProperties(pointerIndex, properties[0]); event.getPointerProperties(pointerIndex, properties[0]); PointerCoords[] coords = new PointerCoords[1]; coords[0] = new PointerCoords(); coords[0].x = clickLocation.x; coords[0].y = clickLocation.y; MotionEvent event = MotionEvent.obtain(secondTapUp.getDownTime(), secondTapUp.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties, coords, 0, 0, 1.0f, 1.0f, secondTapUp.getDeviceId(), 0, secondTapUp.getSource(), secondTapUp.getFlags()); MotionEvent click_event = MotionEvent.obtain(event.getDownTime(), event.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties, coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0, event.getSource(), event.getFlags()); final boolean targetAccessibilityFocus = (result == CLICK_LOCATION_ACCESSIBILITY_FOCUS); sendActionDownAndUp(event, policyFlags, targetAccessibilityFocus); event.recycle(); sendActionDownAndUp(click_event, policyFlags, targetAccessibilityFocus); click_event.recycle(); return; } public void clear() { if (mDownEvent != null) { mDownEvent.recycle(); mDownEvent = null; } if (mFirstTapEvent != null) { mFirstTapEvent.recycle(); mFirstTapEvent = null; } mFirstTapDetected = false; mDoubleTapDetected = false; } public boolean firstTapDetected() { return mFirstTapEvent != null && SystemClock.uptimeMillis() - mFirstTapEvent.getEventTime() < mDoubleTapTimeout; return mFirstTapDetected; } } Loading Loading
services/accessibility/java/com/android/server/accessibility/TouchExplorer.java +64 −76 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.graphics.Rect; import android.os.Handler; import android.os.SystemClock; import android.util.Slog; import android.view.GestureDetector; import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; Loading Loading @@ -114,9 +115,6 @@ class TouchExplorer implements EventStreamTransformation { // Timeout within which we try to detect a tap. private final int mTapTimeout; // Timeout within which we try to detect a double tap. private final int mDoubleTapTimeout; // Slop between the down and up tap to be a tap. private final int mTouchSlop; Loading Loading @@ -230,7 +228,6 @@ class TouchExplorer implements EventStreamTransformation { mInjectedPointerTracker = new InjectedPointerTracker(); mTapTimeout = ViewConfiguration.getTapTimeout(); mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout(); mDoubleTapTimeout = ViewConfiguration.getDoubleTapTimeout(); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop(); mHandler = new Handler(context.getMainLooper()); Loading @@ -248,7 +245,7 @@ class TouchExplorer implements EventStreamTransformation { mSendTouchInteractionEndDelayed = new SendAccessibilityEventDelayed( AccessibilityEvent.TYPE_TOUCH_INTERACTION_END, mDetermineUserIntentTimeout); mDoubleTapDetector = new DoubleTapDetector(); mDoubleTapDetector = new DoubleTapDetector(mContext); final float density = context.getResources().getDisplayMetrics().density; mScaledMinPointerDistanceToUseMiddleLocation = (int) (MIN_POINTER_DISTANCE_TO_USE_MIDDLE_LOCATION_DIP * density); Loading Loading @@ -1109,66 +1106,63 @@ class TouchExplorer implements EventStreamTransformation { } } private class DoubleTapDetector { private MotionEvent mDownEvent; private MotionEvent mFirstTapEvent; private class DoubleTapDetector extends GestureDetector.SimpleOnGestureListener { private final GestureDetector mGestureDetector; private boolean mFirstTapDetected; private boolean mDoubleTapDetected; DoubleTapDetector(Context context) { mGestureDetector = new GestureDetector(context, this); mGestureDetector.setOnDoubleTapListener(this); } public void onMotionEvent(MotionEvent event, int policyFlags) { final int actionIndex = event.getActionIndex(); final int action = event.getActionMasked(); switch (action) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_POINTER_DOWN: { if (mFirstTapEvent != null && !GestureUtils.isSamePointerContext(mFirstTapEvent, event)) { clear(); } mDownEvent = MotionEvent.obtain(event); } break; mDoubleTapDetected = false; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: { if (mDownEvent == null) { return; } if (!GestureUtils.isSamePointerContext(mDownEvent, event)) { clear(); return; maybeFinishDoubleTap(event, policyFlags); break; } if (GestureUtils.isTap(mDownEvent, event, mTapTimeout, mTouchSlop, actionIndex)) { if (mFirstTapEvent == null || GestureUtils.isTimedOut(mFirstTapEvent, event, mDoubleTapTimeout)) { mFirstTapEvent = MotionEvent.obtain(event); mDownEvent.recycle(); mDownEvent = null; return; mGestureDetector.onTouchEvent(event); } if (GestureUtils.isMultiTap(mFirstTapEvent, event, mDoubleTapTimeout, mDoubleTapSlop, actionIndex)) { onDoubleTap(event, policyFlags); mFirstTapEvent.recycle(); mFirstTapEvent = null; mDownEvent.recycle(); mDownEvent = null; return; @Override public boolean onDown(MotionEvent event) { return true; } mFirstTapEvent.recycle(); mFirstTapEvent = null; } else { if (mFirstTapEvent != null) { mFirstTapEvent.recycle(); mFirstTapEvent = null; @Override public boolean onSingleTapUp(MotionEvent event) { mFirstTapDetected = true; return false; } @Override public boolean onSingleTapConfirmed(MotionEvent event) { clear(); return false; } mDownEvent.recycle(); mDownEvent = null; } break; @Override public boolean onDoubleTap(MotionEvent event) { // The processing of the double tap is deferred until the finger is // lifted, so that we can detect a long press on the second tap. mDoubleTapDetected = true; return true; } private void maybeFinishDoubleTap(MotionEvent event, int policyFlags) { if (!mDoubleTapDetected) { return; } public void onDoubleTap(MotionEvent secondTapUp, int policyFlags) { clear(); // This should never be called when more than two pointers are down. if (secondTapUp.getPointerCount() > 2) { if (event.getPointerCount() > 2) { return; } Loading @@ -1184,8 +1178,8 @@ class TouchExplorer implements EventStreamTransformation { mSendTouchInteractionEndDelayed.forceSendAndRemove(); } final int pointerId = secondTapUp.getPointerId(secondTapUp.getActionIndex()); final int pointerIndex = secondTapUp.findPointerIndex(pointerId); final int pointerId = event.getPointerId(event.getActionIndex()); final int pointerIndex = event.findPointerIndex(pointerId); Point clickLocation = mTempPoint; final int result = computeClickLocation(clickLocation); Loading @@ -1196,34 +1190,28 @@ class TouchExplorer implements EventStreamTransformation { // Do the click. PointerProperties[] properties = new PointerProperties[1]; properties[0] = new PointerProperties(); secondTapUp.getPointerProperties(pointerIndex, properties[0]); event.getPointerProperties(pointerIndex, properties[0]); PointerCoords[] coords = new PointerCoords[1]; coords[0] = new PointerCoords(); coords[0].x = clickLocation.x; coords[0].y = clickLocation.y; MotionEvent event = MotionEvent.obtain(secondTapUp.getDownTime(), secondTapUp.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties, coords, 0, 0, 1.0f, 1.0f, secondTapUp.getDeviceId(), 0, secondTapUp.getSource(), secondTapUp.getFlags()); MotionEvent click_event = MotionEvent.obtain(event.getDownTime(), event.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties, coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0, event.getSource(), event.getFlags()); final boolean targetAccessibilityFocus = (result == CLICK_LOCATION_ACCESSIBILITY_FOCUS); sendActionDownAndUp(event, policyFlags, targetAccessibilityFocus); event.recycle(); sendActionDownAndUp(click_event, policyFlags, targetAccessibilityFocus); click_event.recycle(); return; } public void clear() { if (mDownEvent != null) { mDownEvent.recycle(); mDownEvent = null; } if (mFirstTapEvent != null) { mFirstTapEvent.recycle(); mFirstTapEvent = null; } mFirstTapDetected = false; mDoubleTapDetected = false; } public boolean firstTapDetected() { return mFirstTapEvent != null && SystemClock.uptimeMillis() - mFirstTapEvent.getEventTime() < mDoubleTapTimeout; return mFirstTapDetected; } } Loading