Skip to content

Commit 3f01ff6

Browse files
authored
[Android] Don't change state of handlers that haven't received any touches (#4549)
## Description Calling `GestureStateManager.fail()` on a v3 gesture that has never been touched crashes the app on the next touch of its view with a `NullPointerException` in `GestureHandler.isWithinBounds`. Such a handler isn't recorded in the orchestrator yet. `moveToState` then records it through the host detector with a `null` view (`prepare(null)`), and since `prepare` resets the state back to `UNDETERMINED`, the orchestrator never cleans it up. The first touch on the view tracks a pointer on this handler and `handle()` dereferences the missing view. ## Test plan <details> <summary>Tested on the following code:</summary> ```tsx import React from 'react'; import { StyleSheet, Text, View } from 'react-native'; import { GestureDetector, GestureStateManager, usePanGesture, useTapGesture, } from 'react-native-gesture-handler'; // #4539: tap blue once, then touch red. export default function EmptyExample() { const pan = usePanGesture({ onBegin: () => console.log('pan onBegin'), onFinalize: () => console.log('pan onFinalize'), }); const tap = useTapGesture({ onActivate: () => GestureStateManager.fail(pan.handlerTag), }); return ( <View style={styles.container}> <Text>1. Tap blue (fails the untouched pan)</Text> <GestureDetector gesture={tap}> <View style={[styles.box, { backgroundColor: '#3b82f6' }]} /> </GestureDetector> <Text>2. Touch red</Text> <GestureDetector gesture={pan}> <View style={[styles.box, { backgroundColor: '#ef4444' }]} /> </GestureDetector> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', gap: 16, }, box: { width: 160, height: 160, borderRadius: 12 }, }); ``` </details>
1 parent 33099d3 commit 3f01ff6

1 file changed

Lines changed: 4 additions & 0 deletions

File tree

‎packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerModule.kt‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ class RNGestureHandlerModule(reactContext: ReactApplicationContext?) :
145145
UiThreadUtil.assertOnUiThread()
146146

147147
registry.getHandler(handlerTag)?.let { handler ->
148+
if (handler.state == GestureHandler.STATE_UNDETERMINED && !handler.hasTrackedPointers) {
149+
return
150+
}
151+
148152
if (newState == GestureHandler.STATE_ACTIVE) {
149153
// The first touch event reaches JS before the handler begins, so a handler
150154
// that already tracks a pointer may still be UNDETERMINED here.

0 commit comments

Comments
 (0)