Files
react-native/ReactAndroid/src/main/java/com/facebook/react/touch/JSResponderHandler.java
Martin Konicek 42eb5464fd Release React Native for Android
This is an early release and there are several things that are known
not to work if you're porting your iOS app to Android.

See the Known Issues guide on the website.

We will work with the community to reach platform parity with iOS.
2015-09-14 18:13:39 +01:00

78 lines
3.4 KiB
Java

/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.touch;
import javax.annotation.Nullable;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.ViewParent;
/**
* This class coordinates JSResponder commands for {@link UIManagerModule}. It should be set as
* OnInterceptTouchEventListener for all newly created native views that implements
* {@link CatalystInterceptingViewGroup} and thanks to the information whether JSResponder is set
* and to which view it will correctly coordinate the return values of
* {@link OnInterceptTouchEventListener} such that touch events will be dispatched to the view
* selected by JS gesture recognizer.
*
* Single {@link CatalystInstance} should reuse same instance of this class.
*/
public class JSResponderHandler implements OnInterceptTouchEventListener {
private static final int JS_RESPONDER_UNSET = -1;
private volatile int mCurrentJSResponder = JS_RESPONDER_UNSET;
// We're holding on to the ViewParent that blocked native responders so that we can clear it
// when we change or clear the current JS responder.
private @Nullable ViewParent mViewParentBlockingNativeResponder;
public void setJSResponder(int tag, @Nullable ViewParent viewParentBlockingNativeResponder) {
mCurrentJSResponder = tag;
// We need to unblock the native responder first, otherwise we can get in a bad state: a
// ViewParent sets requestDisallowInterceptTouchEvent to true, which sets this setting to true
// to all of its ancestors. Now, if one of its ancestors sets requestDisallowInterceptTouchEvent
// to false, it unsets the setting for itself and all of its ancestors, which means that they
// can intercept events again.
maybeUnblockNativeResponder();
if (viewParentBlockingNativeResponder != null) {
viewParentBlockingNativeResponder.requestDisallowInterceptTouchEvent(true);
mViewParentBlockingNativeResponder = viewParentBlockingNativeResponder;
}
}
public void clearJSResponder() {
mCurrentJSResponder = JS_RESPONDER_UNSET;
maybeUnblockNativeResponder();
}
private void maybeUnblockNativeResponder() {
if (mViewParentBlockingNativeResponder != null) {
mViewParentBlockingNativeResponder.requestDisallowInterceptTouchEvent(false);
mViewParentBlockingNativeResponder = null;
}
}
@Override
public boolean onInterceptTouchEvent(ViewGroup v, MotionEvent event) {
int currentJSResponder = mCurrentJSResponder;
if (currentJSResponder != JS_RESPONDER_UNSET && event.getAction() != MotionEvent.ACTION_UP) {
// Don't intercept ACTION_UP events. If we return true here than UP event will not be
// delivered. That is because intercepted touch events are converted into CANCEL events
// and make all further events to be delivered to the view that intercepted the event.
// Therefore since "UP" event is the last event in a gesture, we should just let it reach the
// original target that is a child view of {@param v}.
// http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent)
return v.getId() == currentJSResponder;
}
return false;
}
}