[Android] Fix handlers cancelled while awaiting leaking in the orchestrator - #4402
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe Android gesture orchestrator now clears ChangesAndroid awaiting handler cleanup
Suggested reviewers: 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
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. Comment |
There was a problem hiding this comment.
Pull request overview
Fixes an Android-side leak in GestureHandlerOrchestrator where a handler that gets cancelled/failed while isAwaiting could remain recorded indefinitely, eventually preventing RNGH-based touchables/gestures from beginning until app restart (as described in #4401).
Changes:
- Clear
handler.isAwaitingwhen the handler transitions toSTATE_CANCELLEDorSTATE_FAILEDinsideonHandlerStateChange. - Allow the existing
cleanupFinishedHandlers()logic to reset/remove these terminal-state handlers now that they’re no longer excluded by the!handler.isAwaitingguard.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Description
On Android, cancelling a handler while it is awaiting another one (e.g. the single tap in
Exclusive(doubleTap, singleTap)waiting for the double tap to fail) leaves it in the orchestrator forever. Both cleanup paths incleanupFinishedHandlersskip handlers withisAwaitingset, and the rescue loop inonHandlerStateChangenever reaches it becausedropGestureHandlerdrops interaction relations on the JS thread before the posted cancel runs on the UI thread, soshouldHandlerWaitForOtherno longer matches.The leaked handler stays in
gestureHandlers, which makesButtonViewGroup.shouldBeginWithRecordedHandlersreturnfalseon every subsequent touch. As a result all button-based touchables (Pressable,RectButton,BaseButton,Touchables) stop responding app-wide until the app process is restarted. The most common trigger is unmounting aGestureDetectorduring the wait window.This change clears
isAwaitingwhen a handler reachesSTATE_CANCELLEDorSTATE_FAILED, since such a handler can never be resolved by the one it was waiting for, letting the existing cleanup collect it.STATE_ENDstays pinned, asmakeActiverelies on it to send synthetic events. Going throughonHandlerStateChangealso covers cancel paths that never touch the registry, e.g.tryActivatecancelling an awaiting handler viashouldBeCancelledByFinishedHandler.Fixes #4401
Test plan
Tested on the following code