Skip to content

Conversation

coolsoftwaretyler
Copy link

Summary:

Fixes #54187 by intercepting TalkBack hover events inside dispatchGenericMotionEvent and checking if the tap falls inside the child's hitSlop area. If the tap occurs in the hitSlop zone, the method now requests accessibility focus on that child view.

Changelog:

Pick one each for the category and type tags:

[ANDROID] [FIXED] - fix hitSlop prop not providing full hitSlop boundaries to TalkBack

Test Plan:

You can test this in the "Pressable Hit Slop" segment of the rn-tester app on Android.

  1. Run install: yarn install
  2. Open RN tester app: yarn android
  3. Go to "Pressable"
  4. Scroll to "Pressable Hit Slop"
  5. Turn on TalkBack
  6. Tap in the hitSlop area (not on the pressable itself). With the fix, the pressable should be highlighted. before the fix, it would not be, and would need to be tapped directly.

Screen recording of fixed behavior in this branch

fixed.mov

Screen recording of broken behavior on main

broken.mov

@meta-cla meta-cla bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 18, 2025
@facebook-github-bot facebook-github-bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Oct 18, 2025
Comment on lines 309 to 310
if (ev.isFromSource(android.view.InputDevice.SOURCE_CLASS_POINTER) &&
(ev.action == MotionEvent.ACTION_HOVER_ENTER || ev.action == MotionEvent.ACTION_HOVER_MOVE)) {
Copy link
Member

Choose a reason for hiding this comment

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

Hover actions are not only used by TalkBack, but also by many other platforms (eg VR).

Is there a way to scope this changes more, or ideally, reuse logic from TouchTargetHelper?

Copy link
Author

Choose a reason for hiding this comment

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

Oh sure that makes sense. I will take another look and see what I can find.

Copy link
Author

Choose a reason for hiding this comment

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

I think the simplest way to do this here was just to check if touch exploration is enabled and keep the rest of the changes, like this: 3550da1.

I looked at TouchTargetHelper and I see there's methods to do hitSlop checking, which we could reuse, but I think we'd have to make them public? If that works, or you had something else in mind, let me know and I'll keep iterating.

Copy link
Member

@javache javache left a comment

Choose a reason for hiding this comment

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

Let's make the change to expose the API - once we have code thats working and not duplicating logic, we can figure out how to reduce visibility changes.

We shouldn't be getting the accessibilitymanager or calling isTouchExplorationEnabled per frame though, as that will cause us to drop frames.

Comment on lines 311 to 312
val accessibilityManager = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as? AccessibilityManager
if (accessibilityManager?.isTouchExplorationEnabled == true &&
Copy link
Member

Choose a reason for hiding this comment

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

This is still pretty expensive to do on a per-input basis (I think it needs to a Binder call)

Copy link
Author

Choose a reason for hiding this comment

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

Ah yeah that makes sense. I've added some internal state to ReactViewGroup and a TouchExplorationStateChangeListener to manage it.

fix: clean up unncessary bounds checking

fix: use listener instead
@coolsoftwaretyler
Copy link
Author

@javache - thanks again for your time reviewing. I exposed the isTouchPointInView method, pulled it in, dropped the normal bounds check (I think that was maybe superfluous), and then set up faster tracking for the touch exploration state. Let me know what you think now. My demo case continues to work as shown in the recordings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

hitSlop does not surface to Android TalkBack

3 participants