diff --git a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/FlingGestureHandler.kt b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/FlingGestureHandler.kt index ca8aaffa76..b5f9c580ed 100644 --- a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/FlingGestureHandler.kt +++ b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/FlingGestureHandler.kt @@ -88,7 +88,7 @@ class FlingGestureHandler : GestureHandler() { } override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) { - if (!shouldActivateWithMouse(sourceEvent)) { + if (shouldSkipEvent(sourceEvent)) { return } diff --git a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt index 88eab51842..4dab48acc4 100644 --- a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt +++ b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandler.kt @@ -4,7 +4,6 @@ import android.app.Activity import android.content.Context import android.content.ContextWrapper import android.graphics.PointF -import android.os.Build import android.view.MotionEvent import android.view.MotionEvent.PointerCoords import android.view.MotionEvent.PointerProperties @@ -823,44 +822,38 @@ open class GestureHandler { return clickedButton and mouseButton != 0 } - protected fun shouldActivateWithMouse(sourceEvent: MotionEvent): Boolean { - // While using mouse, we get both sets of events, for example ACTION_DOWN and ACTION_BUTTON_PRESS. That's why we want to take actions to only one of them. - // On API >= 23, we will use events with infix BUTTON, otherwise we use standard action events (like ACTION_DOWN). + // Decides whether the gesture should ignore this event. While using a mouse we receive both the + // touch-compatible stream (ACTION_DOWN/UP/...) and the BUTTON_* events, so we act on only the + // latter, and we drop events coming from a button other than the configured `mouseButton`. + // Non-mouse input is never skipped here. + protected fun shouldSkipEvent(sourceEvent: MotionEvent): Boolean { + if (sourceEvent.getToolType(0) != MotionEvent.TOOL_TYPE_MOUSE) { + return false + } with(sourceEvent) { - // To use actionButton, we need API >= 23. - if (getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE && - Build.VERSION.SDK_INT >= Build.VERSION_CODES.M + // While using mouse, we want to ignore default events for touch. + if (actionMasked == MotionEvent.ACTION_DOWN || + actionMasked == MotionEvent.ACTION_UP || + actionMasked == MotionEvent.ACTION_POINTER_UP || + actionMasked == MotionEvent.ACTION_POINTER_DOWN ) { - // While using mouse, we want to ignore default events for touch. - if (action == MotionEvent.ACTION_DOWN || - action == MotionEvent.ACTION_UP || - action == MotionEvent.ACTION_POINTER_UP || - action == MotionEvent.ACTION_POINTER_DOWN - ) { - return@shouldActivateWithMouse false - } + return@shouldSkipEvent true + } - // We don't want to do anything if wrong button was clicked. If we received event for BUTTON, we have to use actionButton to get which one was clicked. - if (action != MotionEvent.ACTION_MOVE && !isButtonInConfig(actionButton)) { - return@shouldActivateWithMouse false - } + // Skip events from a button other than the configured one. For BUTTON_* events the clicked + // button is read from `actionButton`. + if (actionMasked != MotionEvent.ACTION_MOVE && !isButtonInConfig(actionButton)) { + return@shouldSkipEvent true + } - // When we receive ACTION_MOVE, we have to check buttonState field. - if (action == MotionEvent.ACTION_MOVE && !isButtonInConfig(buttonState)) { - return@shouldActivateWithMouse false - } - } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - // We do not fully support mouse below API 23, so we will ignore BUTTON events. - if (action == MotionEvent.ACTION_BUTTON_PRESS || - action == MotionEvent.ACTION_BUTTON_RELEASE - ) { - return@shouldActivateWithMouse false - } + // For ACTION_MOVE the pressed button is read from `buttonState`. + if (actionMasked == MotionEvent.ACTION_MOVE && !isButtonInConfig(buttonState)) { + return@shouldSkipEvent true } } - return true + return false } /** diff --git a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/LongPressGestureHandler.kt b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/LongPressGestureHandler.kt index b0910c3fa2..96d49c1a00 100644 --- a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/LongPressGestureHandler.kt +++ b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/LongPressGestureHandler.kt @@ -71,7 +71,7 @@ class LongPressGestureHandler(context: Context) : GestureHandler() { } override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) { - if (!shouldActivateWithMouse(sourceEvent)) { + if (shouldSkipEvent(sourceEvent)) { return } @@ -108,7 +108,8 @@ class LongPressGestureHandler(context: Context) : GestureHandler() { currentPointers == numberOfPointersRequired && ( sourceEvent.actionMasked == MotionEvent.ACTION_DOWN || - sourceEvent.actionMasked == MotionEvent.ACTION_POINTER_DOWN + sourceEvent.actionMasked == MotionEvent.ACTION_POINTER_DOWN || + sourceEvent.actionMasked == MotionEvent.ACTION_BUTTON_PRESS ) ) { handler = Handler(Looper.getMainLooper()) diff --git a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/PanGestureHandler.kt b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/PanGestureHandler.kt index a1215e64c9..afb8feedff 100644 --- a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/PanGestureHandler.kt +++ b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/PanGestureHandler.kt @@ -160,7 +160,7 @@ class PanGestureHandler(context: Context?) : GestureHandler() { } override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) { - if (!shouldActivateWithMouse(sourceEvent)) { + if (shouldSkipEvent(sourceEvent)) { return } diff --git a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/TapGestureHandler.kt b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/TapGestureHandler.kt index 30b46d177f..7a74a08048 100644 --- a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/TapGestureHandler.kt +++ b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/TapGestureHandler.kt @@ -89,7 +89,7 @@ class TapGestureHandler : GestureHandler() { } override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) { - if (!shouldActivateWithMouse(sourceEvent)) { + if (shouldSkipEvent(sourceEvent)) { return } diff --git a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/Extensions.kt b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/Extensions.kt index 5f54c2d961..ef058ab66c 100644 --- a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/Extensions.kt +++ b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/Extensions.kt @@ -17,6 +17,9 @@ fun MotionEvent.isHoverAction(): Boolean = action == MotionEvent.ACTION_HOVER_MO action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_EXIT +fun MotionEvent.isButtonAction(): Boolean = actionMasked == MotionEvent.ACTION_BUTTON_PRESS || + actionMasked == MotionEvent.ACTION_BUTTON_RELEASE + val Display.minimumFrameTime: Float get() { val supportedModes = this.supportedModes diff --git a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.kt b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.kt index c7df067e83..51427927b5 100644 --- a/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.kt +++ b/packages/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootView.kt @@ -62,12 +62,14 @@ class RNGestureHandlerRootView(context: Context?) : ReactViewGroup(context) { } } - override fun dispatchGenericMotionEvent(ev: MotionEvent) = - if (rootViewEnabled && ev.isHoverAction() && rootHelper!!.dispatchTouchEvent(ev)) { - true - } else { - super.dispatchGenericMotionEvent(ev) - } + override fun dispatchGenericMotionEvent(ev: MotionEvent) = if (rootViewEnabled && + (ev.isHoverAction() || ev.isButtonAction()) && + rootHelper!!.dispatchTouchEvent(ev) + ) { + true + } else { + super.dispatchGenericMotionEvent(ev) + } override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) { if (rootViewEnabled) {