Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In Android touchMove is cancelled when intercepted by native gesture from child #44594

Open
AndriusZal opened this issue May 16, 2024 · 4 comments
Labels
Needs: Attention Issues where the author has responded to feedback. Needs: Triage 🔍 Platform: Android Android applications.

Comments

@AndriusZal
Copy link

AndriusZal commented May 16, 2024

Description

Hey! I'm not sure if you can call this a bug, but I might be missing some of the functionality in touch event handling. Currently, on Android touchMove event seems to be cancelled when native gesture is recognized and intercepted in child component. While going through your source code, I have noticed that it is done intentionally in JSTouchDispatcher.java:

public void onChildStartedNativeGesture(
      MotionEvent androidEvent, EventDispatcher eventDispatcher) {
    if (mChildIsHandlingNativeGesture) {
      // This means we previously had another child start handling this native gesture and now a
      // different native parent of that child has decided to intercept the touch stream and handle
      // the gesture itself. Example where this can happen: HorizontalScrollView in a ScrollView.
      return;
    }

    dispatchCancelEvent(androidEvent, eventDispatcher);
    mChildIsHandlingNativeGesture = true;
    mTargetTag = -1;
  }

I would still like to receive touchMove and specifically touchEnd events when the gesture starts and ends. However, now I would only get a few touchMove events and touchCancelled. It doesn't seem to be difficult to implement, but maybe there is a reason why this approach is chosen?

Steps to reproduce

  1. Initialize the app simply npx react-native@latest init AwesomeProject22
  2. Add a simple onTouchMove to the top view onTouchMove={()=>console.log("moving")}
  3. Run the app with npx react-native run-android
  4. Try to trigger touch move event. When moving to the sides, everything seems okay. When you start dragging to the top or bottom, only a few touchMove events are triggered and then cancelled until the next touchStart event.

React Native Version

0.74.1

Affected Platforms

Runtime - Android

Output of npx react-native info

info Fetching system and libraries information...
(node:2310) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
System:
  OS: macOS 14.4.1
  CPU: (12) arm64 Apple M2 Pro
  Memory: 118.08 MB / 16.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 22.1.0
    path: ~/.nvm/versions/node/v22.1.0/bin/node
  Yarn:
    version: 3.6.4
    path: /opt/homebrew/bin/yarn
  npm:
    version: 10.3.0
    path: ~/.nvm/versions/node/v22.1.0/bin/npm
  Watchman:
    version: 2024.04.29.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods:
    version: 1.14.3
    path: /Users/andrius.zaleckis/.rvm/gems/ruby-3.2.2/bin/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 23.4
      - iOS 17.4
      - macOS 14.4
      - tvOS 17.4
      - visionOS 1.1
      - watchOS 10.4
  Android SDK:
    API Levels:
      - "34"
    Build Tools:
      - 34.0.0
      - 35.0.0
    System Images:
      - android-34 | Google APIs ARM 64 v8a
      - android-34 | Google Play ARM 64 v8a
    Android NDK: Not Found
IDEs:
  Android Studio: 2023.3 AI-233.14808.21.2331.11709847
  Xcode:
    version: 15.3/15E204a
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.11
    path: /opt/homebrew/opt/openjdk@17/bin/javac
  Ruby:
    version: 3.2.2
    path: /Users/andrius.zaleckis/.rvm/rubies/ruby-3.2.2/bin/ruby
npmPackages:
  "@react-native-community/cli": Not Found
  react:
    installed: 18.2.0
    wanted: 18.2.0
  react-native:
    installed: 0.74.1
    wanted: 0.74.1
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: false
iOS:
  hermesEnabled: true
  newArchEnabled: false

Stacktrace or Logs

No crashes or failures recorded.

Reproducer

https://github.com/AndriusZal/44594-Reproducer

Screenshots and Videos

No response

@github-actions github-actions bot added Platform: Android Android applications. Needs: Author Feedback Needs: Repro This issue could be improved with a clear list of steps to reproduce the issue. labels May 16, 2024
@AndriusZal
Copy link
Author

I don't think a reproducer is necessary in this example, but I can create it on further request.

@github-actions github-actions bot added Needs: Attention Issues where the author has responded to feedback. and removed Needs: Author Feedback labels May 16, 2024
@cortinico
Copy link
Contributor

I don't think a reproducer is necessary in this example, but I can create it on further request.

Please do. It will save us time when we get to investigating this issue

@github-actions github-actions bot removed the Needs: Repro This issue could be improved with a clear list of steps to reproduce the issue. label May 20, 2024
@AndriusZal
Copy link
Author

Have added a reproducer: https://github.com/AndriusZal/44594-Reproducer

Within the Metro you will notice that when you touch move, the log will print a message with a counter. This counter resets when touch ends. The issue occurs when dragging is recognized by native recognizer within scroll view and touch move event is replaced with dragging event and scroll is happening. Then the touch is cancelled and we are not getting the touch end event. We can trigger touch cancelled event, but I still need to see all touch move events which are happening during drag.

I don't mind to providing the fix myself, I just might need some backstory why this approach is chosen.

@Robert6321
Copy link

My comment maybe unrelated to the above issue but I have a doubt regarding the usage of onChildStartedNativeGesture. Is this method supposed to be called by the framework or can this be manually called as well ? I have a use case where I have react native views on top of native views. Whenever a touch event is intercepted by ReactRootView it starts dispatching it to JavaScript but if that touch event is to be handled by one of my Native Views, I only want the Native Views to handle it. But in the correct scenario due to this implementation, it ends up being handled by both. How do I handle this gracefully ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs: Attention Issues where the author has responded to feedback. Needs: Triage 🔍 Platform: Android Android applications.
Projects
None yet
Development

No branches or pull requests

3 participants