Skip to content

Commit c30a19c

Browse files
committed
[Android] Properly handle requestDisallowInterceptTouchEvent for v3
1 parent bd8e57a commit c30a19c

5 files changed

Lines changed: 78 additions & 16 deletions

File tree

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

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ class GestureHandlerOrchestrator(
5252
// `contains` method on HashSet has O(1) complexity, so calling it inside for loop won't result in O(n^2) (contrary to ArrayList)
5353
private val awaitingHandlersTags = HashSet<Int>()
5454

55-
private var isHandlingTouch = false
55+
var isHandlingTouch = false
56+
private set
5657
private var handlingChangeSemaphore = 0
5758
private var finishedHandlersCleanupScheduled = false
5859
private var activationIndex = 0
@@ -358,6 +359,30 @@ class GestureHandlerOrchestrator(
358359
event.recycle()
359360
}
360361

362+
/**
363+
* Cancels all handlers created using API v1 and v2
364+
*/
365+
fun cancelAllLegacyHandlers() {
366+
val handlersToProcess = obtainHandlerList()
367+
handlersToProcess.addAll(gestureHandlers)
368+
369+
try {
370+
handlersToProcess.forEach {
371+
if (it.actionType == GestureHandler.ACTION_TYPE_JS_FUNCTION_OLD_API ||
372+
it.actionType == GestureHandler.ACTION_TYPE_JS_FUNCTION_NEW_API ||
373+
it.actionType == GestureHandler.ACTION_TYPE_REANIMATED_WORKLET ||
374+
it.actionType == GestureHandler.ACTION_TYPE_NATIVE_ANIMATED_EVENT
375+
) {
376+
it.cancel()
377+
}
378+
}
379+
380+
scheduleFinishedHandlersCleanup()
381+
} finally {
382+
recycleHandlerList(handlersToProcess)
383+
}
384+
}
385+
361386
/**
362387
* isViewAttachedUnderWrapper checks whether all of parents for view related to handler
363388
* view are attached. Since there might be an issue rarely observed when view

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,24 @@ class RNGestureHandlerButtonViewManager :
783783
}
784784
}
785785

786+
override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
787+
super.requestDisallowInterceptTouchEvent(disallowIntercept)
788+
if (!disallowIntercept) {
789+
return
790+
}
791+
792+
val moduleId = moduleId ?: return
793+
val managedHandlerTag = managedHandlerTag ?: return
794+
795+
val orchestrator =
796+
RNGestureHandlerRootView.findGestureHandlerRootView(this)?.orchestrator ?: return
797+
val handler = RNGestureHandlerModule.registries[moduleId]?.getHandler(managedHandlerTag) ?: return
798+
799+
if (!orchestrator.isHandlingTouch && handler.view != null) {
800+
handler.cancel()
801+
}
802+
}
803+
786804
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
787805
if (super.onInterceptTouchEvent(event)) {
788806
return true

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,28 @@ class RNGestureHandlerDetectorView(context: Context) : ReactViewGroup(context) {
4646
super.onDetachedFromWindow()
4747
}
4848

49+
override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
50+
super.requestDisallowInterceptTouchEvent(disallowIntercept)
51+
if (!disallowIntercept) {
52+
return
53+
}
54+
55+
val orchestrator = RNGestureHandlerRootView.findGestureHandlerRootView(this)?.orchestrator ?: return
56+
57+
if (!orchestrator.isHandlingTouch) {
58+
val currentHandlers = attachedHandlers.mapNotNull { tag ->
59+
RNGestureHandlerModule.registries[this.moduleId]?.getHandler(tag)
60+
}.filter {
61+
// The handler has been recorded
62+
it.view != null
63+
}
64+
65+
currentHandlers.forEach {
66+
it.cancel()
67+
}
68+
}
69+
}
70+
4971
fun setModuleId(id: Int) {
5072
if (this.moduleId == id) {
5173
return

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

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import com.swmansion.gesturehandler.core.GestureHandlerOrchestrator
1616
import com.swmansion.gesturehandler.core.OnJSResponderCancelListener
1717

1818
class RNGestureHandlerRootHelper(private val context: ReactContext, wrappedView: ViewGroup, private val moduleId: Int) {
19-
private val orchestrator: GestureHandlerOrchestrator?
19+
val orchestrator: GestureHandlerOrchestrator?
2020
private val jsGestureHandler: GestureHandler?
2121
val rootView: ViewGroup
2222
private var shouldIntercept = false
@@ -57,7 +57,7 @@ class RNGestureHandlerRootHelper(private val context: ReactContext, wrappedView:
5757
}
5858
jsGestureHandler = RootViewGestureHandler(handlerTag = -wrappedViewTag)
5959
registry.registerHandler(jsGestureHandler)
60-
registry.attachHandlerToView(jsGestureHandler.tag, wrappedViewTag, GestureHandler.ACTION_TYPE_JS_FUNCTION_OLD_API)
60+
registry.attachHandlerToView(jsGestureHandler.tag, wrappedViewTag, GestureHandler.ACTION_TYPE_NONE)
6161
module.registerRootHelper(this)
6262
}
6363

@@ -120,7 +120,7 @@ class RNGestureHandlerRootHelper(private val context: ReactContext, wrappedView:
120120
if (orchestrator != null && !passingTouch) {
121121
// if we are in the process of delivering touch events via GH orchestrator, we don't want to
122122
// treat it as a native gesture capturing the lock
123-
tryCancelAllHandlers()
123+
orchestrator.cancelAllLegacyHandlers()
124124
}
125125
}
126126

@@ -142,17 +142,6 @@ class RNGestureHandlerRootHelper(private val context: ReactContext, wrappedView:
142142
return shouldIntercept
143143
}
144144

145-
private fun tryCancelAllHandlers() {
146-
// In order to cancel handlers we activate handler that is hooked to the root view
147-
jsGestureHandler?.apply {
148-
if (state == GestureHandler.STATE_BEGAN) {
149-
// Try activate main JS handler
150-
activate()
151-
end()
152-
}
153-
}
154-
}
155-
156145
fun activateNativeHandlers(view: View) {
157146
orchestrator?.activateNativeHandlersForView(view)
158147
}

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,17 @@ import com.facebook.react.common.ReactConstants
1212
import com.facebook.react.uimanager.RootView
1313
import com.facebook.react.views.view.ReactViewGroup
1414
import com.swmansion.gesturehandler.core.GestureHandler
15+
import com.swmansion.gesturehandler.core.GestureHandlerOrchestrator
1516

1617
class RNGestureHandlerRootView(context: Context?) : ReactViewGroup(context) {
1718
private var moduleId: Int = -1
1819
private var rootViewEnabled = false
1920
private var unstableForceActive = false
2021
private var rootHelper: RNGestureHandlerRootHelper? = null // TODO: resettable lateinit
2122

23+
val orchestrator: GestureHandlerOrchestrator?
24+
get() = rootHelper?.orchestrator
25+
2226
override fun onAttachedToWindow() {
2327
super.onAttachedToWindow()
2428
rootViewEnabled = unstableForceActive || !hasGestureHandlerEnabledRootView(this)
@@ -72,7 +76,7 @@ class RNGestureHandlerRootView(context: Context?) : ReactViewGroup(context) {
7276
}
7377

7478
override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
75-
if (rootViewEnabled) {
79+
if (rootViewEnabled && disallowIntercept) {
7680
rootHelper!!.requestDisallowInterceptTouchEvent()
7781
}
7882
super.requestDisallowInterceptTouchEvent(disallowIntercept)
@@ -114,6 +118,10 @@ class RNGestureHandlerRootView(context: Context?) : ReactViewGroup(context) {
114118
while (parent != null) {
115119
if (parent is RNGestureHandlerRootView) {
116120
gestureHandlerRootView = parent
121+
122+
if (parent.rootViewEnabled) {
123+
return parent
124+
}
117125
}
118126
parent = parent.parent
119127
}

0 commit comments

Comments
 (0)