From 32c19c1994d0355cef258423ee9a46377fc9a5de Mon Sep 17 00:00:00 2001 From: Andrei Coman Date: Wed, 18 Nov 2015 03:18:29 -0800 Subject: [PATCH] Fix setting js responder for null react view for tag Reviewed By: kmagiera Differential Revision: D2637015 fb-gh-sync-id: 03af870cee82519ed34a4bbbcbd2c72146fcf00f --- .../uimanager/NativeViewHierarchyManager.java | 19 ++++++++++++++++--- .../react/uimanager/UIManagerModule.java | 14 +++++++++----- .../react/uimanager/UIViewOperationQueue.java | 18 ++++++++++++++---- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java index 02095d7a6..68a1e567f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java @@ -442,13 +442,26 @@ import com.facebook.react.touch.JSResponderHandler; return TouchTargetHelper.findTargetTagForTouch(touchY, touchX, (ViewGroup) view); } - public void setJSResponder(int reactTag, boolean blockNativeResponder) { + public void setJSResponder(int reactTag, int initialReactTag, boolean blockNativeResponder) { + if (!blockNativeResponder) { + mJSResponderHandler.setJSResponder(initialReactTag, null); + return; + } + + View view = mTagsToViews.get(reactTag); + if (initialReactTag != reactTag && view instanceof ViewParent) { + // In this case, initialReactTag corresponds to a virtual/layout-only View, and we already + // have a parent of that View in reactTag, so we can use it. + mJSResponderHandler.setJSResponder(initialReactTag, (ViewParent) view); + return; + } + if (mRootTags.get(reactTag)) { SoftAssertions.assertUnreachable( "Cannot block native responder on " + reactTag + " that is a root view"); } - ViewParent viewParent = blockNativeResponder ? mTagsToViews.get(reactTag).getParent() : null; - mJSResponderHandler.setJSResponder(reactTag, viewParent); + mJSResponderHandler + .setJSResponder(initialReactTag, view.getParent()); } public void clearJSResponder() { diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java index 64f8ae6c5..81a3bd5f6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java @@ -20,16 +20,14 @@ import java.util.concurrent.TimeUnit; import android.util.DisplayMetrics; import com.facebook.csslayout.CSSLayoutContext; +import com.facebook.infer.annotation.Assertions; import com.facebook.react.animation.Animation; import com.facebook.react.animation.AnimationRegistry; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.uimanager.debug.NotThreadSafeUiManagerDebugListener; -import com.facebook.react.uimanager.events.EventDispatcher; -import com.facebook.infer.annotation.Assertions; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.OnBatchCompleteListener; +import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableArray; @@ -37,6 +35,8 @@ import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.SoftAssertions; import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.bridge.WritableArray; +import com.facebook.react.uimanager.debug.NotThreadSafeUiManagerDebugListener; +import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.systrace.Systrace; import com.facebook.systrace.SystraceMessage; @@ -664,7 +664,11 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements @ReactMethod public void setJSResponder(int reactTag, boolean blockNativeResponder) { assertViewExists(reactTag, "setJSResponder"); - mOperationsQueue.enqueueSetJSResponder(reactTag, blockNativeResponder); + ReactShadowNode node = mShadowNodeRegistry.getNode(reactTag); + while (node.isVirtual() || node.isLayoutOnly()) { + node = node.getParent(); + } + mOperationsQueue.enqueueSetJSResponder(node.getReactTag(), reactTag, blockNativeResponder); } @ReactMethod diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java index 067853045..739558938 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java @@ -186,14 +186,17 @@ public class UIViewOperationQueue { private final class ChangeJSResponderOperation extends ViewOperation { + private final int mInitialTag; private final boolean mBlockNativeResponder; private final boolean mClearResponder; public ChangeJSResponderOperation( int tag, + int initialTag, boolean clearResponder, boolean blockNativeResponder) { super(tag); + mInitialTag = initialTag; mClearResponder = clearResponder; mBlockNativeResponder = blockNativeResponder; } @@ -201,7 +204,7 @@ public class UIViewOperationQueue { @Override public void execute() { if (!mClearResponder) { - mNativeViewHierarchyManager.setJSResponder(mTag, mBlockNativeResponder); + mNativeViewHierarchyManager.setJSResponder(mTag, mInitialTag, mBlockNativeResponder); } else { mNativeViewHierarchyManager.clearJSResponder(); } @@ -450,14 +453,21 @@ public class UIViewOperationQueue { mOperations.add(new RemoveRootViewOperation(rootViewTag)); } - public void enqueueSetJSResponder(int reactTag, boolean blockNativeResponder) { + public void enqueueSetJSResponder( + int tag, + int initialTag, + boolean blockNativeResponder) { mOperations.add( - new ChangeJSResponderOperation(reactTag, false /*clearResponder*/, blockNativeResponder)); + new ChangeJSResponderOperation( + tag, + initialTag, + false /*clearResponder*/, + blockNativeResponder)); } public void enqueueClearJSResponder() { // Tag is 0 because JSResponderHandler doesn't need one in order to clear the responder. - mOperations.add(new ChangeJSResponderOperation(0, true /*clearResponder*/, false)); + mOperations.add(new ChangeJSResponderOperation(0, 0, true /*clearResponder*/, false)); } public void enqueueDispatchCommand(