Skip to content

[Android] Cancel native touches before terminal event cleanup - #4637

Merged
m-bert merged 3 commits into
software-mansion:mainfrom
huamurui:fix/android-terminal-touch-cancellation
Oct 28, 2026
Merged

m-bert merged 3 commits into
software-mansion:mainfrom
huamurui:fix/android-terminal-touch-cancellation

Conversation

@huamurui

Copy link
Copy Markdown
Contributor

Description

A short tap on a plain React Native Text selectable can select a word after the finger has lifted when a Tap gesture intercepts ACTION_UP.

This change runs native-touch cancellation before pointer coordinates and finished-handler state are cleared. It preserves native ownership and keeps cancellation inside touch dispatch to prevent reentrant interception requests from cancelling the winning gesture.

Reproduction

Environment: RNGH 3.4.0 · RN 0.88.0 · Fabric/Hermes · Android 16 (vivo V2509A).

  1. Run the example below.
  2. Briefly tap a word, release, and wait two seconds.
  3. Before: the word becomes selected after release.
  4. With this fix: it stays unselected; a genuine long press still selects normally.
Minimal v3 reproduction
import { Text, View } from 'react-native';
import {
  GestureDetector,
  GestureHandlerRootView,
  useTapGesture,
} from 'react-native-gesture-handler';

export default function App() {
  const tap = useTapGesture({ disableReanimated: true });

  return (
    <GestureHandlerRootView style={{ flex: 1, paddingTop: 100 }}>
      <GestureDetector gesture={tap}>
        <View collapsable={false} style={{ padding: 20 }}>
          <Text selectable style={{ fontSize: 20 }}>
            Tap a word briefly, lift, then wait two seconds.
          </Text>
        </View>
      </GestureDetector>
    </GestureHandlerRootView>
  );
}

Set enabled: false on the Tap for a control.

Test plan

  • Device comparison: short-tap selection fixed; genuine long press and disabled-Tap behavior preserved.
  • Scrolling: RN ScrollView with simultaneous Native/Tap gestures retains momentum after release, with no reported native gesture cancellation.
  • Local regression harness: 7/10 checks fail on the base revision; 10/10 pass with the fix (Robolectric API 28; harness kept outside this PR).
  • Checks: basic-example Android build (arm64, SDK 37), Kotlin formatting, workspace type checks, and git diff --check pass.

Copilot AI balanced review requested due to automatic review settings October 24, 2026 01:05
@coderabbitai

coderabbitai Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 6967614a-7a62-4fbe-b28e-041177a4ecae
Commits

Reviewing files that changed from the base of the PR and between 37fc93e and 02ee32d.

Files selected for processing: 2
  • packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt
  • packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.

📝 Summary

Summary by CodeRabbit

  • Bug Fixes
    • Improved touch handling when a gesture intercepts events. Touches in intercepted views are now cancelled after gesture handlers process the current event, helping prevent interference with that event.
    • Pointer tracking now removes released pointers after the cancellation sweep and clears all pointers when a touch sequence ends or is cancelled. This keeps gesture and touch state consistent throughout the sequence.

The Android root helper now schedules intercepted-view touch cancellation when interception starts. The orchestrator performs the cancellation after gesture handlers process the event and before it releases pointer tracking for that event.

Changes: Android touch cancellation

Layer / File(s) Summary
Schedule and process intercepted-view cancellation
packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt, packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt
The root helper schedules cancellation when interception starts and removes the previous dispatch-time transition check. After gesture handlers receive an event, the orchestrator performs pending cancellation, then updates pointer tracking. Pointer-up removes only the lifted pointer; up and cancel clear all tracked points.

Sequence Diagram(s)

sequenceDiagram
  participant RNGestureHandlerRootHelper
  participant GestureHandlerOrchestrator
  participant GestureHandlers
  participant InterceptedViews
  RNGestureHandlerRootHelper->>GestureHandlerOrchestrator: Schedule cancellation when interception starts
  GestureHandlerOrchestrator->>GestureHandlers: Deliver touch event
  GestureHandlerOrchestrator->>InterceptedViews: Cancel touches at tracked pointer positions
  GestureHandlerOrchestrator->>GestureHandlerOrchestrator: Update pointer tracking after cancellation
Loading

Possibly related issues

Possibly related PRs

Suggested reviewers: j-piasecki, m-bert

Priority: Normal

Merge Risk: Minimal · up to 02ee3

The change appears ready to merge after normal checks; the reviewed paths preserve touch cancellation timing and active native scrolling.

Pre-merge checks: Passed 3
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: cancelling native Android touches before terminal event cleanup.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The reentrancy-sensitive Android dispatch changes warrant human validation, especially because the reported regression harness is not included in the PR.

No open issues 🎉

What changed in this PR

This PR fixes delayed text selection after an intercepted short tap on Android by cancelling native touches before gesture cleanup removes the state needed for cancellation.

Changes:

  • Moves native-touch cancellation into orchestrator dispatch, keeping interception guards active during cancellation.
  • Defers pointer-position cleanup until after cancellation, while preserving native-handler ownership.
File Description
packages/​react-native-gesture-handler/​android/​src/​main/​java/​com/​swmansion/​gesturehandler/​react/​RNGestureHandlerRootHelper.kt Registers a callback to cancel native touches inside orchestrator dispatch.
packages/​react-native-gesture-handler/​android/​src/​main/​java/​com/​swmansion/​gesturehandler/​core/​GestureHandlerOrchestrator.kt Invokes the callback before terminal-event cleanup.

Review effort: Balanced

@huamurui

Copy link
Copy Markdown
Contributor Author

I've published the regression tests and run instructions on a separate test branch.

The branch contains two commits so the same suite can be run against both versions:

  • Parent commit: original implementation — 7 failures out of 10 tests.
  • Branch tip: this PR's fix — all 10 tests pass.

Coverage includes terminal-event cancellation, native-handler ownership, and reentrant requestDisallowInterceptTouchEvent calls during cancellation. The production changes are identical to this PR; the test infrastructure remains on the separate branch.

@m-bert

m-bert commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

Hi @huamurui! Thank you for spotting this issue and submitting a fix! I took the liberty of introducing some changes - could you please verify them and confirm that the PR still works?

@huamurui

huamurui commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor Author

Thanks for the changes! I tested the updated PR on my Android device and can confirm it still fixes the issue. Long-press text selection and scrolling also work as expected.

@m-bert
m-bert merged commit 7b3c647 into software-mansion:main Oct 28, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants