Merge "Use the standard GestureDetector to handle double tap and hold in TouchExplorer."
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index c3f5c43..f6b32f7 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -112,12 +112,6 @@
     // Timeout before trying to decide what the user is trying to do.
     private final int mDetermineUserIntentTimeout;
 
-    // Timeout within which we try to detect a tap.
-    private final int mTapTimeout;
-
-    // Slop between the down and up tap to be a tap.
-    private final int mTouchSlop;
-
     // Slop between the first and second tap to be a double tap.
     private final int mDoubleTapSlop;
 
@@ -142,9 +136,6 @@
     // Command for delayed sending of touch interaction end events.
     private final SendAccessibilityEventDelayed mSendTouchInteractionEndDelayed;
 
-    // Command for delayed sending of a long press.
-    private final PerformLongPressDelayed mPerformLongPressDelayed;
-
     // Command for exiting gesture detection mode after a timeout.
     private final ExitGestureDetectionModeDelayed mExitGestureDetectionModeDelayed;
 
@@ -173,9 +164,6 @@
     // Handle to the accessibility manager service.
     private final AccessibilityManagerService mAms;
 
-    // Temporary rectangle to avoid instantiation.
-    private final Rect mTempRect = new Rect();
-
     // Temporary point to avoid instantiation.
     private final Point mTempPoint = new Point();
 
@@ -226,12 +214,9 @@
         mAms = service;
         mReceivedPointerTracker = new ReceivedPointerTracker();
         mInjectedPointerTracker = new InjectedPointerTracker();
-        mTapTimeout = ViewConfiguration.getTapTimeout();
         mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout();
-        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
         mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop();
         mHandler = new Handler(context.getMainLooper());
-        mPerformLongPressDelayed = new PerformLongPressDelayed();
         mExitGestureDetectionModeDelayed = new ExitGestureDetectionModeDelayed();
         mGestureLibrary = GestureLibraries.fromRawResource(context, R.raw.accessibility_gestures);
         mGestureLibrary.setOrientationStyle(8);
@@ -299,7 +284,6 @@
         // Remove all pending callbacks.
         mSendHoverEnterAndMoveDelayed.cancel();
         mSendHoverExitDelayed.cancel();
-        mPerformLongPressDelayed.cancel();
         mExitGestureDetectionModeDelayed.cancel();
         mSendTouchExplorationEndDelayed.cancel();
         mSendTouchInteractionEndDelayed.cancel();
@@ -437,7 +421,6 @@
                 // we resent the delayed callback and wait again.
                 mSendHoverEnterAndMoveDelayed.cancel();
                 mSendHoverExitDelayed.cancel();
-                mPerformLongPressDelayed.cancel();
 
                 if (mSendTouchExplorationEndDelayed.isPending()) {
                     mSendTouchExplorationEndDelayed.forceSendAndRemove();
@@ -447,18 +430,7 @@
                     mSendTouchInteractionEndDelayed.forceSendAndRemove();
                 }
 
-                // If we have the first tap, schedule a long press and break
-                // since we do not want to schedule hover enter because
-                // the delayed callback will kick in before the long click.
-                // This would lead to a state transition resulting in long
-                // pressing the item below the double taped area which is
-                // not necessary where accessibility focus is.
-                if (mDoubleTapDetector.firstTapDetected()) {
-                    // We got a tap now post a long press action.
-                    mPerformLongPressDelayed.post(event, policyFlags);
-                    break;
-                }
-                if (!mTouchExplorationInProgress) {
+                if (!mDoubleTapDetector.firstTapDetected() && !mTouchExplorationInProgress) {
                     if (!mSendHoverEnterAndMoveDelayed.isPending()) {
                         // Deliver hover enter with a delay to have a chance
                         // to detect what the user is trying to do.
@@ -478,7 +450,6 @@
                 // decide what we will actually do next.
                 mSendHoverEnterAndMoveDelayed.cancel();
                 mSendHoverExitDelayed.cancel();
-                mPerformLongPressDelayed.cancel();
             } break;
             case MotionEvent.ACTION_MOVE: {
                 final int pointerId = receivedTracker.getPrimaryPointerId();
@@ -521,7 +492,6 @@
                                     mVelocityTracker.clear();
                                     mSendHoverEnterAndMoveDelayed.cancel();
                                     mSendHoverExitDelayed.cancel();
-                                    mPerformLongPressDelayed.cancel();
                                     mExitGestureDetectionModeDelayed.post();
                                     // Send accessibility event to announce the start
                                     // of gesture recognition.
@@ -532,28 +502,12 @@
                                     // exploring so start sending events.
                                     mSendHoverEnterAndMoveDelayed.forceSendAndRemove();
                                     mSendHoverExitDelayed.cancel();
-                                    mPerformLongPressDelayed.cancel();
                                     sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE,
                                             pointerIdBits, policyFlags);
                                 }
                                 break;
                             }
                         } else {
-                            // Cancel the long press if pending and the user
-                            // moved more than the slop.
-                            if (mPerformLongPressDelayed.isPending()) {
-                                final float deltaX =
-                                        receivedTracker.getReceivedPointerDownX(pointerId)
-                                        - rawEvent.getX(pointerIndex);
-                                final float deltaY =
-                                        receivedTracker.getReceivedPointerDownY(pointerId)
-                                        - rawEvent.getY(pointerIndex);
-                                final double moveDelta = Math.hypot(deltaX, deltaY);
-                                // The user has moved enough for us to decide.
-                                if (moveDelta > mTouchSlop) {
-                                    mPerformLongPressDelayed.cancel();
-                                }
-                            }
                             if (mTouchExplorationInProgress) {
                                 sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags);
                                 sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits,
@@ -569,9 +523,7 @@
                             // scheduled sending events.
                             mSendHoverEnterAndMoveDelayed.cancel();
                             mSendHoverExitDelayed.cancel();
-                            mPerformLongPressDelayed.cancel();
                         } else {
-                            mPerformLongPressDelayed.cancel();
                             if (mTouchExplorationInProgress) {
                                 // If the user is touch exploring the second pointer may be
                                 // performing a double tap to activate an item without need
@@ -620,9 +572,7 @@
                             // scheduled sending events.
                             mSendHoverEnterAndMoveDelayed.cancel();
                             mSendHoverExitDelayed.cancel();
-                            mPerformLongPressDelayed.cancel();
                         } else {
-                            mPerformLongPressDelayed.cancel();
                             // We are sending events so send exit and gesture
                             // end since we transition to another state.
                             sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
@@ -643,7 +593,6 @@
                 final int pointerId = event.getPointerId(event.getActionIndex());
                 final int pointerIdBits = (1 << pointerId);
 
-                mPerformLongPressDelayed.cancel();
                 mVelocityTracker.clear();
 
                 if (mSendHoverEnterAndMoveDelayed.isPending()) {
@@ -1110,6 +1059,7 @@
         private final GestureDetector mGestureDetector;
         private boolean mFirstTapDetected;
         private boolean mDoubleTapDetected;
+        private int mPolicyFlags;
 
         DoubleTapDetector(Context context) {
             mGestureDetector = new GestureDetector(context, this);
@@ -1117,6 +1067,7 @@
         }
 
         public void onMotionEvent(MotionEvent event, int policyFlags) {
+            mPolicyFlags = policyFlags;
             switch (event.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN:
                     mDoubleTapDetected = false;
@@ -1135,6 +1086,11 @@
         }
 
         @Override
+        public void onLongPress(MotionEvent e) {
+            maybeSendLongPress(e, mPolicyFlags);
+        }
+
+        @Override
         public boolean onSingleTapUp(MotionEvent event) {
             mFirstTapDetected = true;
             return false;
@@ -1154,6 +1110,38 @@
             return true;
         }
 
+        private void maybeSendLongPress(MotionEvent event, int policyFlags) {
+            if (!mDoubleTapDetected) {
+                return;
+            }
+
+            clear();
+
+            // Pointers should not be zero when running this command.
+            if (mReceivedPointerTracker.getLastReceivedEvent().getPointerCount() == 0) {
+                return;
+            }
+
+            final int pointerIndex = event.getActionIndex();
+            final int pointerId = event.getPointerId(pointerIndex);
+
+            Point clickLocation = mTempPoint;
+            final int result = computeClickLocation(clickLocation);
+
+            if (result == CLICK_LOCATION_NONE) {
+                return;
+            }
+
+            mLongPressingPointerId = pointerId;
+            mLongPressingPointerDeltaX = (int) event.getX(pointerIndex) - clickLocation.x;
+            mLongPressingPointerDeltaY = (int) event.getY(pointerIndex) - clickLocation.y;
+
+            sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
+
+            mCurrentState = STATE_DELEGATING;
+            sendDownForAllNotInjectedPointers(event, policyFlags);
+        }
+
         private void maybeFinishDoubleTap(MotionEvent event, int policyFlags) {
             if (!mDoubleTapDetected) {
                 return;
@@ -1169,7 +1157,6 @@
             // Remove pending event deliveries.
             mSendHoverEnterAndMoveDelayed.cancel();
             mSendHoverExitDelayed.cancel();
-            mPerformLongPressDelayed.cancel();
 
             if (mSendTouchExplorationEndDelayed.isPending()) {
                 mSendTouchExplorationEndDelayed.forceSendAndRemove();
@@ -1178,8 +1165,8 @@
                 mSendTouchInteractionEndDelayed.forceSendAndRemove();
             }
 
-            final int pointerId = event.getPointerId(event.getActionIndex());
-            final int pointerIndex = event.findPointerIndex(pointerId);
+            final int pointerIndex = event.getActionIndex();
+            final int pointerId = event.getPointerId(pointerIndex);
 
             Point clickLocation = mTempPoint;
             final int result = computeClickLocation(clickLocation);
@@ -1306,65 +1293,6 @@
     }
 
     /**
-     * Class for delayed sending of long press.
-     */
-    private final class PerformLongPressDelayed implements Runnable {
-        private MotionEvent mEvent;
-        private int mPolicyFlags;
-
-        public void post(MotionEvent prototype, int policyFlags) {
-            mEvent = MotionEvent.obtain(prototype);
-            mPolicyFlags = policyFlags;
-            mHandler.postDelayed(this, ViewConfiguration.getLongPressTimeout());
-        }
-
-        public void cancel() {
-            if (mEvent != null) {
-                mHandler.removeCallbacks(this);
-                clear();
-            }
-        }
-
-        private boolean isPending() {
-            return mHandler.hasCallbacks(this);
-        }
-
-        @Override
-        public void run() {
-            // Pointers should not be zero when running this command.
-            if (mReceivedPointerTracker.getLastReceivedEvent().getPointerCount() == 0) {
-                return;
-            }
-
-            final int pointerId = mEvent.getPointerId(mEvent.getActionIndex());
-            final int pointerIndex = mEvent.findPointerIndex(pointerId);
-
-            Point clickLocation = mTempPoint;
-            final int result = computeClickLocation(clickLocation);
-
-            if (result == CLICK_LOCATION_NONE) {
-                return;
-            }
-
-            mLongPressingPointerId = pointerId;
-            mLongPressingPointerDeltaX = (int) mEvent.getX(pointerIndex) - clickLocation.x;
-            mLongPressingPointerDeltaY = (int) mEvent.getY(pointerIndex) - clickLocation.y;
-
-            sendHoverExitAndTouchExplorationGestureEndIfNeeded(mPolicyFlags);
-
-            mCurrentState = STATE_DELEGATING;
-            sendDownForAllNotInjectedPointers(mEvent, mPolicyFlags);
-            clear();
-        }
-
-        private void clear() {
-            mEvent.recycle();
-            mEvent = null;
-            mPolicyFlags = 0;
-        }
-    }
-
-    /**
      * Class for delayed sending of hover enter and move events.
      */
     class SendHoverEnterAndMoveDelayed implements Runnable {