Defines how touch input is recognized into gesture events and delivered to UI widgets of the app: a single recognition system with unified thresholds, the widget contract for receiving gestures, and the touch behavior of every migrated widget.
The system SHALL recognize touch input into a stream of gesture events:
Down and Up passthrough events delivered immediately at touch start and
end, Tap, LongPress, and a drag lifecycle of DragStart, DragMove, and
DragEnd carrying the release velocity. All gesture positions SHALL be
delivered in the receiving widget's local coordinate space.
Down event without waiting for any gesture
to resolveDragStart, zero or more
DragMove, and exactly one DragEnd whose velocity reflects the recent
movement history at releaseThe system SHALL use one set of recognition constants for all widgets: touch
slop bounding tap travel and long-press stationarity, a tap duration bound,
the system long-press timeout, a drag start threshold equal to touch slop, a
move delivery period of 20ms, and a velocity sample window of 40ms. A Tap
SHALL require travel within slop and duration within the bound.
Tap is deliveredTap fires and drag recognition proceeds insteadDragMove is delivered at most once per period while velocity
sampling still observes every moveLongPress SHALL fire while the finger is still down, once the system
long-press timeout elapses with travel within slop. It SHALL fire at most
once per touch and SHALL be cancelled by travel beyond slop before the
timeout or by touch cancellation.
LongPress is delivered while the touch is still downLongPress fires for that touchThe target of a touch SHALL be resolved by hit-testing the widget tree in priority order at touch start. All gesture events for that touch SHALL be delivered only to the resolved target chain until the touch ends or is cancelled. A touch that moves over a different widget mid-gesture SHALL NOT hand off ownership.
Gesture recognition SHALL observe every touch event regardless of which widget handles it, including touches that begin on widgets that previously claimed events synchronously. Secondary touches (additional simultaneous touch ids) SHALL NOT alter or cancel recognition of the primary touch.
When multiple widgets in the target chain accept competing gestures, the first recognizer to resolve SHALL claim the gesture and competing recognizers SHALL be cancelled. Within slop the descendant's tap wins over an ancestor's drag; beyond slop the ancestor's drag wins over the descendant's pending tap.
Tap and the menu's scroll is not engagedWidgets SHALL declare the gestures they accept and a hit-test region.
Widgets that declare no gestures SHALL receive only Down/Up passthrough;
widgets whose hit-test excludes a position SHALL receive no gesture events
for that touch.
Touch cancellation SHALL tear down all pending recognition state and timers for that touch, and no further gesture events SHALL be emitted for it after cancellation.
Tap,
LongPress, or DragEnd fires for itMouse-emulated touches on desktop SHALL produce the same gesture recognition and delivery as real touches on Android.
Tap is recognized and delivered as on deviceThe button SHALL emit its click signal on Tap within its hit region, and
the token table SHALL emit its row click signal on Tap within a row.
Activation by mouse remains unchanged.
Tap lands inside the button's hit regionThe emoji picker SHALL scroll one-to-one with vertical drag after slop,
clamped to its scroll bounds, and SHALL activate the emoji under a Tap.
Tap within slop the emoji under the position is activatedThe menu SHALL enter edit mode on LongPress, SHALL select or delete items
on Tap, and SHALL reorder items via a drag armed by touching the reorder
handle at touch start.
The chat view SHALL scroll one-to-one with vertical drag, SHALL drive its
scroll inertia from the DragEnd velocity, SHALL stop inertia when a new
drag starts, SHALL start line selection or show a URL toast on LongPress,
and on Tap SHALL forward to the message under the touch (opening URLs,
downloading files) or toggle line selection when selection is active.
Tap lands on a message URLThe text edit SHALL arm selection-handle dragging at Down by grabbing a
handle within its radius, SHALL select the word under the touch and show the
action menu on LongPress, SHALL set the cursor and request focus on Tap,
and SHALL scroll vertically on vertical drag while fingers move text-selection
handles.
After migration, widget touch interaction SHALL be expressed exclusively through the gesture stream. The per-widget raw phase handlers and the separate synchronous touch dispatch path SHALL NOT exist.