How Android’s GestureDetector Detects Double‑Tap and Other Gestures
This article explains the inner workings of Android’s GestureDetector class, detailing how it creates listeners, processes MotionEvent actions, schedules handler messages, and determines the timing and conditions for callbacks such as onDown, onShowPress, onSingleTapUp, onScroll, onLongPress, onFling, and double‑tap events.
Overview
The Android GestureDetector class provides a high‑level way to recognize common gestures such as taps, double‑taps, scrolls, long presses, and flings. By implementing GestureDetector.OnGestureListener (and optionally OnDoubleTapListener) and passing the listener to the detector’s constructor, developers can receive callbacks that mirror the system’s own gesture handling.
Creating a GestureDetector
GestureDetector gestureDetector = new GestureDetector(this, new GestureDetector.OnGestureListener() {
@Override public boolean onDown(MotionEvent e) { return false; }
@Override public void onShowPress(MotionEvent e) {}
@Override public boolean onSingleTapUp(MotionEvent e) { return false; }
@Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; }
@Override public void onLongPress(MotionEvent e) {}
@Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return false; }
});Callback Timing for Each Gesture
onDown : invoked immediately when the system receives MotionEvent.ACTION_DOWN.
onShowPress : triggered 100 ms after ACTION_DOWN if the finger stays within the tap region and no other gesture cancels it.
onSingleTapUp : called on ACTION_UP when the gesture is still considered a tap (no double‑tap, no long press, and still in the tap region).
onScroll : fired during ACTION_MOVE once the finger moves beyond the touch‑slop distance.
onLongPress : dispatched after the long‑press timeout (default 500 ms) if the finger remains stationary.
onFling : executed on ACTION_UP when the computed velocity exceeds the minimum fling velocity.
Internal Implementation Details
The detector’s core logic lives in onTouchEvent(MotionEvent ev). It switches on ev.getAction() & MotionEvent.ACTION_MASK and forwards the event to the appropriate listener method. For timing‑based gestures, a private GestureHandler (a subclass of Handler) receives delayed messages: SHOW_PRESS is posted at downTime + TAP_TIMEOUT (100 ms). LONG_PRESS is posted at downTime + ViewConfiguration.getLongPressTimeout() (≈500 ms).
If the finger moves, a new ACTION_MOVE may cancel pending messages, causing the long‑press or show‑press callbacks to be skipped.
Tap Region Management
The boolean mAlwaysInTapRegion is set to true on the initial ACTION_DOWN. It becomes false when the finger moves beyond the touch‑slop distance or when a second pointer appears ( ACTION_POINTER_DOWN). Once false, onSingleTapUp will no longer be called.
Double‑Tap Detection
When a second ACTION_DOWN occurs, the detector calls isConsideredDoubleTap(firstDown, firstUp, secondDown). The method checks:
Whether the gesture is still in the larger tap region.
That the interval between the first UP and the second DOWN lies between DOUBLE_TAP_MIN_TIME (40 ms) and DOUBLE_TAP_TIMEOUT (300 ms).
That the squared distance between the two down events is less than mDoubleTapSlopSquare (the square of the system double‑tap slop).
If all conditions pass, mIsDoubleTapping is set to true and the detector invokes onDoubleTap and onDoubleTapEvent. Otherwise, a delayed TAP message is posted to eventually call onSingleTapConfirmed.
Single‑Tap Confirmation
The TAP message is processed by GestureHandler. If the finger has already been lifted ( !mStillDown), onSingleTapConfirmed is called immediately; otherwise the flag mDeferConfirmSingleTap is set, and the confirmation occurs after the subsequent ACTION_UP.
Fling Handling
During ACTION_UP, the detector obtains the velocity from a VelocityTracker. If either the X or Y velocity exceeds ViewConfiguration.getMinimumFlingVelocity() (default 50), onFling is invoked.
Key Takeaways
The detector relies heavily on timed Handler messages to differentiate between quick taps, long presses, and scrolls.
All distance checks use squared values to avoid costly square‑root calculations.
Understanding the internal state flags ( mAlwaysInTapRegion, mIsDoubleTapping, mInLongPress) helps developers predict when each callback will fire.
AI Code to Success
Focused on hardcore practical AI technologies (OpenClaw, ClaudeCode, LLMs, etc.) and HarmonyOS development. No hype—just real-world tips, pitfall chronicles, and productivity tools. Follow to transform workflows with code.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
