@@ -226,17 +226,12 @@ public boolean onSingleTapConfirmed(MotionEvent e) {
226226 */
227227 private boolean mIsDoubleTapping ;
228228
229- private float mLastMotionY ;
230- private float mLastMotionX ;
229+ private float mLastFocusX ;
230+ private float mLastFocusY ;
231+ private float mDownFocusX ;
232+ private float mDownFocusY ;
231233
232234 private boolean mIsLongpressEnabled ;
233-
234- /**
235- * True if we are at a target API level of >= Froyo or the developer can
236- * explicitly set it. If true, input events with > 1 pointer will be ignored
237- * so we can work side by side with multitouch gesture detectors.
238- */
239- private boolean mIgnoreMultitouch ;
240235
241236 /**
242237 * Determines speed during touch scrolling
@@ -349,8 +344,16 @@ public GestureDetector(Context context, OnGestureListener listener) {
349344 * @throws NullPointerException if {@code listener} is null.
350345 */
351346 public GestureDetector (Context context , OnGestureListener listener , Handler handler ) {
352- this (context , listener , handler , context != null &&
353- context .getApplicationInfo ().targetSdkVersion >= Build .VERSION_CODES .FROYO );
347+ if (handler != null ) {
348+ mHandler = new GestureHandler (handler );
349+ } else {
350+ mHandler = new GestureHandler ();
351+ }
352+ mListener = listener ;
353+ if (listener instanceof OnDoubleTapListener ) {
354+ setOnDoubleTapListener ((OnDoubleTapListener ) listener );
355+ }
356+ init (context );
354357 }
355358
356359 /**
@@ -362,31 +365,19 @@ public GestureDetector(Context context, OnGestureListener listener, Handler hand
362365 * @param listener the listener invoked for all the callbacks, this must
363366 * not be null.
364367 * @param handler the handler to use
365- * @param ignoreMultitouch whether events involving more than one pointer should
366- * be ignored.
367368 *
368369 * @throws NullPointerException if {@code listener} is null.
369370 */
370371 public GestureDetector (Context context , OnGestureListener listener , Handler handler ,
371- boolean ignoreMultitouch ) {
372- if (handler != null ) {
373- mHandler = new GestureHandler (handler );
374- } else {
375- mHandler = new GestureHandler ();
376- }
377- mListener = listener ;
378- if (listener instanceof OnDoubleTapListener ) {
379- setOnDoubleTapListener ((OnDoubleTapListener ) listener );
380- }
381- init (context , ignoreMultitouch );
372+ boolean unused ) {
373+ this (context , listener , handler );
382374 }
383375
384- private void init (Context context , boolean ignoreMultitouch ) {
376+ private void init (Context context ) {
385377 if (mListener == null ) {
386378 throw new NullPointerException ("OnGestureListener must not be null" );
387379 }
388380 mIsLongpressEnabled = true ;
389- mIgnoreMultitouch = ignoreMultitouch ;
390381
391382 // Fallback to support pre-donuts releases
392383 int touchSlop , doubleTapSlop , doubleTapTouchSlop ;
@@ -456,34 +447,40 @@ public boolean onTouchEvent(MotionEvent ev) {
456447 }
457448
458449 final int action = ev .getAction ();
459- final float y = ev .getY ();
460- final float x = ev .getX ();
461450
462451 if (mVelocityTracker == null ) {
463452 mVelocityTracker = VelocityTracker .obtain ();
464453 }
465454 mVelocityTracker .addMovement (ev );
466455
456+ final boolean pointerUp = action == MotionEvent .ACTION_POINTER_UP ;
457+ final int skipIndex = pointerUp ? ev .getActionIndex () : -1 ;
458+
459+ // Determine focal point
460+ float sumX = 0 , sumY = 0 ;
461+ final int count = ev .getPointerCount ();
462+ for (int i = 0 ; i < count ; i ++) {
463+ if (skipIndex == i ) continue ;
464+ sumX += ev .getX (i );
465+ sumY += ev .getY (i );
466+ }
467+ final int div = pointerUp ? count - 1 : count ;
468+ final float focusX = sumX / div ;
469+ final float focusY = sumY / div ;
470+
467471 boolean handled = false ;
468472
469473 switch (action & MotionEvent .ACTION_MASK ) {
470474 case MotionEvent .ACTION_POINTER_DOWN :
471- if ( mIgnoreMultitouch ) {
472- // Multitouch event - abort.
473- cancel ();
474- }
475+ mDownFocusX = mLastFocusX = focusX ;
476+ mDownFocusY = mLastFocusY = focusY ;
477+ // Cancel long press and taps
478+ cancelTaps ();
475479 break ;
476480
477481 case MotionEvent .ACTION_POINTER_UP :
478- // Ending a multitouch gesture and going back to 1 finger
479- if (mIgnoreMultitouch && ev .getPointerCount () == 2 ) {
480- int index = (((action & MotionEvent .ACTION_POINTER_INDEX_MASK )
481- >> MotionEvent .ACTION_POINTER_INDEX_SHIFT ) == 0 ) ? 1 : 0 ;
482- mLastMotionX = ev .getX (index );
483- mLastMotionY = ev .getY (index );
484- mVelocityTracker .recycle ();
485- mVelocityTracker = VelocityTracker .obtain ();
486- }
482+ mDownFocusX = mLastFocusX = focusX ;
483+ mDownFocusY = mLastFocusY = focusY ;
487484 break ;
488485
489486 case MotionEvent .ACTION_DOWN :
@@ -504,8 +501,8 @@ public boolean onTouchEvent(MotionEvent ev) {
504501 }
505502 }
506503
507- mLastMotionX = x ;
508- mLastMotionY = y ;
504+ mDownFocusX = mLastFocusX = focusX ;
505+ mDownFocusY = mLastFocusY = focusY ;
509506 if (mCurrentDownEvent != null ) {
510507 mCurrentDownEvent .recycle ();
511508 }
@@ -525,22 +522,22 @@ public boolean onTouchEvent(MotionEvent ev) {
525522 break ;
526523
527524 case MotionEvent .ACTION_MOVE :
528- if (mInLongPress || ( mIgnoreMultitouch && ev . getPointerCount () > 1 ) ) {
525+ if (mInLongPress ) {
529526 break ;
530527 }
531- final float scrollX = mLastMotionX - x ;
532- final float scrollY = mLastMotionY - y ;
528+ final float scrollX = mLastFocusX - focusX ;
529+ final float scrollY = mLastFocusY - focusY ;
533530 if (mIsDoubleTapping ) {
534531 // Give the move events of the double-tap
535532 handled |= mDoubleTapListener .onDoubleTapEvent (ev );
536533 } else if (mAlwaysInTapRegion ) {
537- final int deltaX = (int ) (x - mCurrentDownEvent . getX () );
538- final int deltaY = (int ) (y - mCurrentDownEvent . getY () );
534+ final int deltaX = (int ) (focusX - mDownFocusX );
535+ final int deltaY = (int ) (focusY - mDownFocusY );
539536 int distance = (deltaX * deltaX ) + (deltaY * deltaY );
540537 if (distance > mTouchSlopSquare ) {
541538 handled = mListener .onScroll (mCurrentDownEvent , ev , scrollX , scrollY );
542- mLastMotionX = x ;
543- mLastMotionY = y ;
539+ mLastFocusX = focusX ;
540+ mLastFocusY = focusY ;
544541 mAlwaysInTapRegion = false ;
545542 mHandler .removeMessages (TAP );
546543 mHandler .removeMessages (SHOW_PRESS );
@@ -551,8 +548,8 @@ public boolean onTouchEvent(MotionEvent ev) {
551548 }
552549 } else if ((Math .abs (scrollX ) >= 1 ) || (Math .abs (scrollY ) >= 1 )) {
553550 handled = mListener .onScroll (mCurrentDownEvent , ev , scrollX , scrollY );
554- mLastMotionX = x ;
555- mLastMotionY = y ;
551+ mLastFocusX = focusX ;
552+ mLastFocusY = focusY ;
556553 }
557554 break ;
558555
@@ -571,9 +568,10 @@ public boolean onTouchEvent(MotionEvent ev) {
571568
572569 // A fling must travel the minimum tap distance
573570 final VelocityTracker velocityTracker = mVelocityTracker ;
571+ final int pointerId = ev .getPointerId (0 );
574572 velocityTracker .computeCurrentVelocity (1000 , mMaximumFlingVelocity );
575- final float velocityY = velocityTracker .getYVelocity ();
576- final float velocityX = velocityTracker .getXVelocity ();
573+ final float velocityY = velocityTracker .getYVelocity (pointerId );
574+ final float velocityX = velocityTracker .getXVelocity (pointerId );
577575
578576 if ((Math .abs (velocityY ) > mMinimumFlingVelocity )
579577 || (Math .abs (velocityX ) > mMinimumFlingVelocity )){
@@ -622,6 +620,18 @@ private void cancel() {
622620 }
623621 }
624622
623+ private void cancelTaps () {
624+ mHandler .removeMessages (SHOW_PRESS );
625+ mHandler .removeMessages (LONG_PRESS );
626+ mHandler .removeMessages (TAP );
627+ mIsDoubleTapping = false ;
628+ mAlwaysInTapRegion = false ;
629+ mAlwaysInBiggerTapRegion = false ;
630+ if (mInLongPress ) {
631+ mInLongPress = false ;
632+ }
633+ }
634+
625635 private boolean isConsideredDoubleTap (MotionEvent firstDown , MotionEvent firstUp ,
626636 MotionEvent secondDown ) {
627637 if (!mAlwaysInBiggerTapRegion ) {
0 commit comments