Skip to content

Commit

Permalink
Add onChildEndedNativeGesture to JSTouchDispatcher and ReactRootVie…
Browse files Browse the repository at this point in the history
…w to handle child gesture finishes event

Summary:
Changelog:
[Android][Added] Adding new API `onChildEndedNativeGesture` to the RootView interface to let its implementations notify the JS side that a child gesture is ended.

Reviewed By: javache

Differential Revision: D32228745

fbshipit-source-id: ad1f26546dd60f9c5a569b0bc3ad5020a01b90cc
  • Loading branch information
ryancat authored and facebook-github-bot committed Nov 9, 2021
1 parent e973b3a commit 9b33c31
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 8 deletions.
38 changes: 30 additions & 8 deletions ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
Original file line number Diff line number Diff line change
Expand Up @@ -185,14 +185,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

@Override
public void onChildStartedNativeGesture(MotionEvent ev) {
if (mReactInstanceManager == null
|| !mIsAttachedToInstance
|| mReactInstanceManager.getCurrentReactContext() == null) {
FLog.w(TAG, "Unable to dispatch touch to JS as the catalyst instance has not been attached");
return;
}
if (mJSTouchDispatcher == null) {
FLog.w(TAG, "Unable to dispatch touch to JS before the dispatcher is available");
if (!isDispatcherReady()) {
return;
}
ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
Expand All @@ -209,6 +202,35 @@ public void onChildStartedNativeGesture(View childView, MotionEvent ev) {
onChildStartedNativeGesture(ev);
}

@Override
public void onChildEndedNativeGesture(View childView, MotionEvent ev) {
if (!isDispatcherReady()) {
return;
}
ReactContext reactContext = mReactInstanceManager.getCurrentReactContext();
UIManager uiManager = UIManagerHelper.getUIManager(reactContext, getUIManagerType());

if (uiManager != null) {
EventDispatcher eventDispatcher = uiManager.getEventDispatcher();
mJSTouchDispatcher.onChildEndedNativeGesture(ev, eventDispatcher);
}
}

private boolean isDispatcherReady() {
if (mReactInstanceManager == null
|| !mIsAttachedToInstance
|| mReactInstanceManager.getCurrentReactContext() == null) {
FLog.w(TAG, "Unable to dispatch touch to JS as the catalyst instance has not been attached");
return false;
}
if (mJSTouchDispatcher == null) {
FLog.w(TAG, "Unable to dispatch touch to JS before the dispatcher is available");
return false;
}

return true;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
dispatchJSTouchEvent(ev);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ public void onChildStartedNativeGesture(
mTargetTag = -1;
}

public void onChildEndedNativeGesture(MotionEvent androidEvent, EventDispatcher eventDispatcher) {
// There should be only one child gesture at any given time. We can safely turn off the flag.
mChildIsHandlingNativeGesture = false;
}

/**
* Main catalyst view is responsible for collecting and sending touch events to JS. This method
* reacts for an incoming android native touch events ({@link MotionEvent}) and calls into {@link
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,11 @@ public interface RootView {
/** @deprecated */
void onChildStartedNativeGesture(MotionEvent ev);

/**
* Called when a child ends a native gesture. Should be called from the child's onTouchIntercepted
* implementation.
*/
void onChildEndedNativeGesture(View childView, MotionEvent ev);

void handleException(Throwable t);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,16 @@ public class NativeGestureUtil {
public static void notifyNativeGestureStarted(View view, MotionEvent event) {
RootViewUtil.getRootView(view).onChildStartedNativeGesture(view, event);
}

/**
* Helper method that should be called when a native view ends a native gesture (e.g. a native
* ScrollView takes control of a gesture stream and starts scrolling). This will handle
* dispatching the appropriate events to JS to make sure future gesture is not blocked.
*
* @param view the View ending the native gesture
* @param event the MotionEvent that caused the gesture to be ended
*/
public static void notifyNativeGestureEnded(View view, MotionEvent event) {
RootViewUtil.getRootView(view).onChildEndedNativeGesture(view, event);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,11 @@ public void onChildStartedNativeGesture(View childView, MotionEvent ev) {
mJSTouchDispatcher.onChildStartedNativeGesture(ev, mEventDispatcher);
}

@Override
public void onChildEndedNativeGesture(View childView, MotionEvent ev) {
mJSTouchDispatcher.onChildEndedNativeGesture(ev, mEventDispatcher);
}

@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
// No-op - override in order to still receive events to onInterceptTouchEvent
Expand Down

0 comments on commit 9b33c31

Please sign in to comment.