From d61651ce1e8caa5f57e9ee9f897e1b9928707eef Mon Sep 17 00:00:00 2001 From: liurenfei Date: Fri, 21 Dec 2018 20:00:15 +0800 Subject: [PATCH 1/5] [ReactAndroid] Fix the IndexOutOfBoundsException when setChildren/manageChildren an illegal ReactRawTextShadowNode to a non-ReactBaseTextShadowNode --- .../java/com/facebook/react/uimanager/BUCK | 1 + .../react/uimanager/UIImplementation.java | 196 +++++++++++++- .../react/uimanager/UIImplementationTest.java | 256 ++++++++++++++++++ 3 files changed, 449 insertions(+), 4 deletions(-) create mode 100644 ReactAndroid/src/test/java/com/facebook/react/uimanager/UIImplementationTest.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK index 9bb553e2e9aefe..e061fa3e21b250 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK @@ -38,6 +38,7 @@ rn_android_library( react_native_target("java/com/facebook/react/uimanager/annotations:annotations"), react_native_target("java/com/facebook/react/uimanager/util:util"), react_native_target("java/com/facebook/react/uimanager/common:common"), + react_native_target("java/com/facebook/react/views/text:text"), react_native_target("res:uimanager"), ], exported_deps = [ diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java index fd3448e8661020..747e7bdc8dc22d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java @@ -11,6 +11,7 @@ import static android.view.View.MeasureSpec.UNSPECIFIED; import android.os.SystemClock; +import android.text.TextUtils; import android.view.View.MeasureSpec; import com.facebook.common.logging.FLog; import com.facebook.infer.annotation.Assertions; @@ -28,9 +29,13 @@ import com.facebook.react.uimanager.common.SizeMonitoringFrameLayout; import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener; import com.facebook.react.uimanager.events.EventDispatcher; +import com.facebook.react.views.text.ReactBaseTextShadowNode; +import com.facebook.react.views.text.ReactRawTextManager; import com.facebook.systrace.Systrace; import com.facebook.systrace.SystraceMessage; import com.facebook.yoga.YogaDirection; + +import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -350,13 +355,148 @@ protected void handleUpdateView( /** * Invoked when there is a mutation in a node tree. * - * @param tag react tag of the node we want to manage - * @param indicesToRemove ordered (asc) list of indicies at which view should be removed - * @param viewsToAdd ordered (asc based on mIndex property) list of tag-index pairs that represent + * @param viewTag react tag of the node we want to manage + * @param removeFrom ordered (asc) list of indicies at which view should be removed + * @param addChildTags,addAtIndices ordered (asc based on mIndex property) list of tag-index pairs that represent * a view which should be added at the specified index - * @param tagsToDelete list of tags corresponding to views that should be removed + * @param moveFrom,moveTo list of indicies at which view that should be moveFrom and moveTo */ public void manageChildren( + int viewTag, + @Nullable ReadableArray moveFrom, + @Nullable ReadableArray moveTo, + @Nullable ReadableArray addChildTags, + @Nullable ReadableArray addAtIndices, + @Nullable ReadableArray removeFrom) { + ReactShadowNode cssNodeToManage = mShadowNodeRegistry.getNode(viewTag); + + int numToMove = moveFrom == null ? 0 : moveFrom.size(); + int numToAdd = addChildTags == null ? 0 : addChildTags.size(); + int numToRemove = removeFrom == null ? 0 : removeFrom.size(); + + if (numToMove != 0 && (moveTo == null || numToMove != moveTo.size())) { + throw new IllegalViewOperationException("Size of moveFrom != size of moveTo!"); + } + + if (numToAdd != 0 && (addAtIndices == null || numToAdd != addAtIndices.size())) { + throw new IllegalViewOperationException("Size of addChildTags != size of addAtIndices!"); + } + + // We treat moves as an add and a delete + ViewAtIndex[] viewsToAdd = new ViewAtIndex[numToMove + numToAdd]; + int[] indicesToRemove = new int[numToMove + numToRemove]; + int[] tagsToRemove = new int[indicesToRemove.length]; + int[] tagsToDelete = new int[numToRemove]; + + if (numToMove > 0) { + Assertions.assertNotNull(moveFrom); + Assertions.assertNotNull(moveTo); + for (int i = 0; i < numToMove; i++) { + int moveFromIndex = moveFrom.getInt(i); + int tagToMove = cssNodeToManage.getChildAt(moveFromIndex).getReactTag(); + viewsToAdd[i] = new ViewAtIndex( + tagToMove, + moveTo.getInt(i)); + indicesToRemove[i] = moveFromIndex; + tagsToRemove[i] = tagToMove; + } + } + + if (numToAdd > 0) { + Assertions.assertNotNull(addChildTags); + Assertions.assertNotNull(addAtIndices); + for (int i = 0; i < numToAdd; i++) { + int viewTagToAdd = addChildTags.getInt(i); + int indexToAddAt = addAtIndices.getInt(i); + viewsToAdd[numToMove + i] = new ViewAtIndex(viewTagToAdd, indexToAddAt); + } + } + + if (numToRemove > 0) { + Assertions.assertNotNull(removeFrom); + for (int i = 0; i < numToRemove; i++) { + int indexToRemove = removeFrom.getInt(i); + int tagToRemove = cssNodeToManage.getChildAt(indexToRemove).getReactTag(); + indicesToRemove[numToMove + i] = indexToRemove; + tagsToRemove[numToMove + i] = tagToRemove; + tagsToDelete[i] = tagToRemove; + } + } + + // NB: moveFrom and removeFrom are both relative to the starting state of the View's children. + // moveTo and addAt are both relative to the final state of the View's children. + // + // 1) Sort the views to add and indices to remove by index + // 2) Iterate the indices being removed from high to low and remove them. Going high to low + // makes sure we remove the correct index when there are multiple to remove. + // 3) Iterate the views being added by index low to high and add them. Like the view removal, + // iteration direction is important to preserve the correct index. + + Arrays.sort(viewsToAdd, ViewAtIndex.COMPARATOR); + Arrays.sort(indicesToRemove); + + // Apply changes to CSSNodeDEPRECATED hierarchy + int lastIndexRemoved = -1; + for (int i = indicesToRemove.length - 1; i >= 0; i--) { + int indexToRemove = indicesToRemove[i]; + if (indexToRemove == lastIndexRemoved) { + throw new IllegalViewOperationException("Repeated indices in Removal list for view tag: " + + viewTag); + } + cssNodeToManage.removeChildAt(indicesToRemove[i]); + lastIndexRemoved = indicesToRemove[i]; + } + ArrayList vais = new ArrayList<>(Arrays.asList(viewsToAdd)); + ArrayList illegals = new ArrayList<>(); + for (int i = 0; i < vais.size(); i++) { + ViewAtIndex viewAtIndex = vais.get(i); + ReactShadowNode cssNodeToAdd = mShadowNodeRegistry.getNode(viewAtIndex.mTag); + if (cssNodeToAdd == null) { + throw new IllegalViewOperationException("Trying to add unknown view tag: " + + viewAtIndex.mTag); + } + // If there is a RCTRawText child node, and the parent is not a ReactBaseTextShadowNode, donot add the illegal + // RCTRawText childNode to parent node. + if (TextUtils.equals(cssNodeToAdd.getViewClass(), ReactRawTextManager.REACT_CLASS) + && !(cssNodeToManage instanceof ReactBaseTextShadowNode)) { + illegals.add(viewAtIndex); + continue; + } + cssNodeToManage.addChildAt(cssNodeToAdd, viewAtIndex.mIndex - illegals.size()); + } + // Remove the illegal viewAtIndex, and correct the index of other viewAtIndexs. + if (illegals.size() > 0) { + for (int index = vais.size() - 1; index >= 0; index--) { + ViewAtIndex vai = vais.get(index); + if (illegals.size() > 0) { + // The index of ViewAtIndex is final, so we cannot edit it. + vais.remove(vai); + if (illegals.contains(vai)) { + illegals.remove(vai); + } else { + vais.add(index,new ViewAtIndex(vai.mTag,vai.mIndex-illegals.size())); + } + } + } + viewsToAdd = vais.toArray(new ViewAtIndex[0]); + } + + if (!cssNodeToManage.isVirtual() && !cssNodeToManage.isVirtualAnchor()) { + mNativeViewHierarchyOptimizer.handleManageChildren( + cssNodeToManage, + indicesToRemove, + tagsToRemove, + viewsToAdd, + tagsToDelete); + } + + for (int i = 0; i < tagsToDelete.length; i++) { + removeShadowNode(mShadowNodeRegistry.getNode(tagsToDelete[i])); + } + } + + @Deprecated + public void manageChildrenDeprecated( int viewTag, @Nullable ReadableArray moveFrom, @Nullable ReadableArray moveTo, @@ -466,6 +606,13 @@ public void manageChildren( } } + /** + * An optimized version of manageChildren that is used for initial setting of child views. + * The children are assumed to be in index order + * + * @param viewTag tag of the parent + * @param childrenTags tags of the children + */ /** * An optimized version of manageChildren that is used for initial setting of child views. * The children are assumed to be in index order @@ -476,6 +623,47 @@ public void manageChildren( public void setChildren( int viewTag, ReadableArray childrenTags) { + ReactShadowNode cssNodeToManage = mShadowNodeRegistry.getNode(viewTag); + + ArrayList illegalChildrendTags = new ArrayList<>(); + for (int i = 0; i < childrenTags.size(); i++) { + ReactShadowNode cssNodeToAdd = mShadowNodeRegistry.getNode(childrenTags.getInt(i)); + if (cssNodeToAdd == null) { + throw new IllegalViewOperationException("Trying to add unknown view tag: " + + childrenTags.getInt(i)); + } + // If there is a RCTRawText child node, and the parent is not a ReactBaseTextShadowNode, donot add the illegal + // RCTRawText childNode to parent node. + if (TextUtils.equals(cssNodeToAdd.getViewClass(), ReactRawTextManager.REACT_CLASS) + && !(cssNodeToManage instanceof ReactBaseTextShadowNode)) { + illegalChildrendTags.add(childrenTags.getInt(i)); + continue; + } + + cssNodeToManage.addChildAt(cssNodeToAdd, i - illegalChildrendTags.size()); + } + // Remove the illegal child node. + if (illegalChildrendTags.size() > 0) { + // Donot use childrenTags.toArrayList.It will cast Int to Double. + ArrayList children = new ArrayList<>(); + for (int i = 0; i < childrenTags.size(); i++) { + children.add(childrenTags.getInt(i)); + } + children.removeAll(illegalChildrendTags); + childrenTags = Arguments.fromList(children); + } + + if (!cssNodeToManage.isVirtual() && !cssNodeToManage.isVirtualAnchor()) { + mNativeViewHierarchyOptimizer.handleSetChildren( + cssNodeToManage, + childrenTags); + } + } + + @Deprecated + public void setChildrenDeprecated( + int viewTag, + ReadableArray childrenTags) { ReactShadowNode cssNodeToManage = mShadowNodeRegistry.getNode(viewTag); diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIImplementationTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIImplementationTest.java new file mode 100644 index 00000000000000..bbfb218ae9349e --- /dev/null +++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIImplementationTest.java @@ -0,0 +1,256 @@ +package com.facebook.react.uimanager; + +import static org.fest.assertions.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.rule.PowerMockRule; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +import com.facebook.react.ReactRootView; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.CatalystInstance; +import com.facebook.react.bridge.JavaOnlyArray; +import com.facebook.react.bridge.JavaOnlyMap; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactTestHelper; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.modules.core.ChoreographerCompat; +import com.facebook.react.modules.core.ReactChoreographer; +import com.facebook.react.views.text.ReactRawTextManager; +import com.facebook.react.views.text.ReactRawTextShadowNode; +import com.facebook.react.views.text.ReactTextViewManager; +import com.facebook.react.views.view.ReactViewManager; + +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +/** + * Tests for {@link UIImplementation} + * + * @author LiuRenfei + * @since 2018-12-20 + */ +@PrepareForTest ({Arguments.class, ReactChoreographer.class}) +@RunWith (RobolectricTestRunner.class) +@PowerMockIgnore ({"org.mockito.*", "org.robolectric.*", "android.*"}) +public class UIImplementationTest { + + /************************************************************* + * Test Case: FixBug - the children of view should not be + * Blank, Number, String, Object(not a Component) + ************************************************************* + * + * 123 + * '456' + * {"setChildren/manageChildren"} + * + * + ************************************************************* + */ + @Rule + public ExpectedException mException = ExpectedException.none(); + + private ReactApplicationContext mReactContext; + private CatalystInstance mCatalystInstanceMock; + private ArrayList mPendingFrameCallbacks; + + @Before + public void setUp() throws Exception { + PowerMockito.mockStatic(Arguments.class, ReactChoreographer.class); + + ReactChoreographer choreographerMock = mock(ReactChoreographer.class); + PowerMockito.when(Arguments.createArray()).thenAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + return new JavaOnlyArray(); + } + }); + PowerMockito.when(Arguments.createMap()).thenAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + return new JavaOnlyMap(); + } + }); + PowerMockito.when(ReactChoreographer.getInstance()).thenReturn(choreographerMock); + + mPendingFrameCallbacks = new ArrayList<>(); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + mPendingFrameCallbacks + .add((ChoreographerCompat.FrameCallback) invocation.getArguments()[1]); + return null; + } + }).when(choreographerMock).postFrameCallback( + any(ReactChoreographer.CallbackType.class), + any(ChoreographerCompat.FrameCallback.class)); + + mCatalystInstanceMock = ReactTestHelper.createMockCatalystInstance(); + mReactContext = new ReactApplicationContext(RuntimeEnvironment.application); + mReactContext.initializeWithInstance(mCatalystInstanceMock); + + UIManagerModule uiManagerModuleMock = mock(UIManagerModule.class); + when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class)) + .thenReturn(uiManagerModuleMock); + } + + /** + * execute pending frame callbacks. + */ + private void executePendingFrameCallbacks() { + ArrayList callbacks = + new ArrayList<>(mPendingFrameCallbacks); + mPendingFrameCallbacks.clear(); + for (ChoreographerCompat.FrameCallback frameCallback : callbacks) { + frameCallback.doFrame(0); + } + } + + /** + * create view hierarchy + * + * @param uiManager + * @param method + * + * @return + */ + private ViewGroup createSimpleViewHierarchy(UIManagerModule uiManager, Method method) + throws InvocationTargetException, IllegalAccessException { + /************************************************************* + * Test Case: FixBug - the children of view should not be + * Blank, Number, String, Object(not a Component) + ************************************************************* + * + * 123 + * '456' + * {"setChildren/manageChildren"} + * + * + ************************************************************* + */ + ReactRootView rootView = + new ReactRootView(RuntimeEnvironment.application.getApplicationContext()); + UIImplementation uiImplementation = uiManager.getUIImplementation(); + int rootTag = uiManager.addRootView(rootView); + int strTag = rootTag + 1; + int textTag = strTag + 1; + int rawTextTag = textTag + 1; + + uiImplementation.createView(strTag, ReactRawTextManager.REACT_CLASS, rootTag, + JavaOnlyMap.of(ReactRawTextShadowNode.PROP_TEXT, "123 '456'")); + + uiImplementation.createView(rawTextTag, ReactRawTextManager.REACT_CLASS, rootTag, + JavaOnlyMap.of(ReactRawTextShadowNode.PROP_TEXT, "setChildren/manageChildren")); + + uiImplementation.createView(textTag, ReactTextViewManager.REACT_CLASS, rootTag, + JavaOnlyMap.of("allowFontScaling", true, "ellipsizeMode", "tail", "accessible", true)); + + if (method.getName().startsWith("setChildren")) { + method.invoke(uiImplementation, textTag, JavaOnlyArray.of(rawTextTag)); + + method.invoke(uiImplementation, rootTag, JavaOnlyArray.of(strTag, textTag)); + + } else if (method.getName().startsWith("manageChildren")) { + method.invoke(uiImplementation, textTag, null, null, + JavaOnlyArray.of(rawTextTag), JavaOnlyArray.of(0), null); + + method.invoke(uiImplementation, rootTag, null, null, + JavaOnlyArray.of(strTag, textTag), JavaOnlyArray.of(0, 1), null); + } + + uiManager.onBatchComplete(); + executePendingFrameCallbacks(); + + return rootView; + } + + /** + * get UIManagerModule + * + * @return + */ + private UIManagerModule getUIManagerModule() { + List viewManagers = Arrays.asList( + new ReactViewManager(), + new ReactTextViewManager(), + new ReactRawTextManager()); + UIManagerModule uiManagerModule = + new UIManagerModule(mReactContext, viewManagers, 0); + uiManagerModule.onHostResume(); + return uiManagerModule; + } + + @Test + public void testManageChildren() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + UIManagerModule uiManager = getUIManagerModule(); + UIImplementation uiImplementation = uiManager.getUIImplementation(); + Method method = uiImplementation.getClass().getMethod("manageChildren", int.class, ReadableArray.class, + ReadableArray.class, ReadableArray.class, ReadableArray.class, ReadableArray.class); + ViewGroup rootView = createSimpleViewHierarchy(uiManager, method); + + assertThat(rootView.getChildCount()).isEqualTo(1); + + View firstChild = rootView.getChildAt(0); + assertThat(firstChild).isInstanceOf(TextView.class); + assertThat(((TextView) firstChild).getText().toString()).isEqualTo("setChildren/manageChildren"); + } + + @Test + public void testManageChildrenDeprecated() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + UIManagerModule uiManager = getUIManagerModule(); + UIImplementation uiImplementation = uiManager.getUIImplementation(); + Method method = uiImplementation.getClass().getMethod("manageChildrenDeprecated", int.class, + ReadableArray.class, ReadableArray.class, ReadableArray.class, ReadableArray.class, ReadableArray.class); + ViewGroup rootView = createSimpleViewHierarchy(uiManager, method); + + mException.expect(IndexOutOfBoundsException.class); + mException.expectMessage("index=" + 1 + " count=" + 0); + } + + @Test + public void setChildren() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + UIManagerModule uiManager = getUIManagerModule(); + UIImplementation uiImplementation = uiManager.getUIImplementation(); + Method method = uiImplementation.getClass().getMethod("setChildren", int.class, ReadableArray.class); + ViewGroup rootView = createSimpleViewHierarchy(uiManager, method); + + assertThat(rootView.getChildCount()).isEqualTo(1); + + View firstChild = rootView.getChildAt(0); + assertThat(firstChild).isInstanceOf(TextView.class); + assertThat(((TextView) firstChild).getText().toString()).isEqualTo("setChildren/manageChildren"); + } + + @Test + public void setChildrenDeprecated() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + UIManagerModule uiManager = getUIManagerModule(); + UIImplementation uiImplementation = uiManager.getUIImplementation(); + Method method = uiImplementation.getClass().getMethod("setChildrenDeprecated", int.class, ReadableArray.class); + ViewGroup rootView = createSimpleViewHierarchy(uiManager, method); + + mException.expect(IndexOutOfBoundsException.class); + mException.expectMessage("index=" + 1 + " count=" + 0); + } +} From ce79ef012abcc3415dcaf806bc9b6b1d040802e0 Mon Sep 17 00:00:00 2001 From: liurenfei Date: Sat, 22 Dec 2018 00:03:04 +0800 Subject: [PATCH 2/5] [Android][Fixed] Break the circular dependency text for uimanager --- .../src/main/java/com/facebook/react/uimanager/BUCK | 2 +- .../src/main/java/com/facebook/react/views/text/BUCK | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK index e061fa3e21b250..a07231ed8bb93c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK @@ -38,7 +38,7 @@ rn_android_library( react_native_target("java/com/facebook/react/uimanager/annotations:annotations"), react_native_target("java/com/facebook/react/uimanager/util:util"), react_native_target("java/com/facebook/react/uimanager/common:common"), - react_native_target("java/com/facebook/react/views/text:text"), + react_native_target("java/com/facebook/react/views/text:text_for_uimanager"), react_native_target("res:uimanager"), ], exported_deps = [ diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK index a4b6e0c3bab668..f1590b2ccffe9d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK @@ -19,3 +19,13 @@ rn_android_library( react_native_target("java/com/facebook/react/views/view:view"), ], ) +rn_android_library( + name = "text_for_uimanager", + srcs = glob(["ReactBaseTextShadowNode.java","ReactRawTextManager.java"]), + required_for_source_only_abi = True, + visibility = [ + "PUBLIC", + ], + deps = [ + ], +) From 70b9cc50155a1e1e46f2f8fcfc13fd6528555cae Mon Sep 17 00:00:00 2001 From: liurenfei Date: Sat, 22 Dec 2018 00:29:19 +0800 Subject: [PATCH 3/5] [Android][Fixed] Break the circular dependency --- .../java/com/facebook/react/uimanager/BUCK | 25 +++++++++++++++++++ .../java/com/facebook/react/views/text/BUCK | 3 +++ 2 files changed, 28 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK index a07231ed8bb93c..5c5eae7b651b8f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK @@ -63,3 +63,28 @@ rn_android_library( react_native_target("java/com/facebook/react/bridge:bridge"), ], ) + +rn_android_library( + name = "uimanager_for_text", + srcs = glob([ + "ReactShadowNode.java", + "ReactShadowNodeImpl.java", + "annotations/ReactProp.java", + "IllegalViewOperationException.java", + "LayoutShadowNode.java", + "PixelUtil.java", + "ReactShadowNode.java", + "ViewDefaults.java", + "ViewProps.java", + ]), + required_for_source_only_abi = True, + visibility = [ + "PUBLIC", + ], + deps = [ + YOGA_TARGET, + react_native_dep("third-party/java/infer-annotations:infer-annotations"), + react_native_target("java/com/facebook/react/uimanager/annotations:annotations"), + react_native_target("java/com/facebook/react/modules/i18nmanager:i18nmanager"), + ], +) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK index f1590b2ccffe9d..7b5d25b1eb9da7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK @@ -27,5 +27,8 @@ rn_android_library( "PUBLIC", ], deps = [ + react_native_target("java/com/facebook/react/common:common"), + react_native_target("java/com/facebook/react/uimanager:uimanager_for_text"), + react_native_target("java/com/facebook/react/uimanager/annotations:annotations"), ], ) From 723d30989de9cf3bd99c908abe4b54d4cee163bc Mon Sep 17 00:00:00 2001 From: liurenfei Date: Sat, 22 Dec 2018 00:36:48 +0800 Subject: [PATCH 4/5] [Android][Fixed] Break the circular dependency --- ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK | 1 - 1 file changed, 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK index 5c5eae7b651b8f..2943a31df16e75 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK @@ -69,7 +69,6 @@ rn_android_library( srcs = glob([ "ReactShadowNode.java", "ReactShadowNodeImpl.java", - "annotations/ReactProp.java", "IllegalViewOperationException.java", "LayoutShadowNode.java", "PixelUtil.java", From 3d3fdf0c273358bb3092cf47cddef7fd02c06634 Mon Sep 17 00:00:00 2001 From: liurenfei Date: Sat, 22 Dec 2018 00:36:48 +0800 Subject: [PATCH 5/5] [Android][Fixed] Break the circular dependency --- .../facebook/react/CoreModulesPackage.java | 3 +- .../java/com/facebook/react/uimanager/BUCK | 134 ++++++++++++++++-- .../react/uimanager/LayoutUpdateListener.java | 8 ++ .../react/uimanager/UIImplementation.java | 9 +- .../uimanager/UIImplementationProvider.java | 2 +- .../react/uimanager/UIManagerModule.java | 15 -- .../UIManagerModuleConstantsHelper.java | 2 +- .../react/uimanager/UIViewOperationQueue.java | 86 +++++------ .../react/uimanager/ViewManagerRegistry.java | 4 +- .../react/uimanager/ViewManagerResolver.java | 20 +++ ...dSafeViewHierarchyUpdateDebugListener.java | 2 - .../java/com/facebook/react/views/text/BUCK | 25 +++- .../java/com/facebook/react/views/view/BUCK | 22 +++ 13 files changed, 245 insertions(+), 87 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutUpdateListener.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerResolver.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java b/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java index 10260537294830..0a2ec959248de8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/CoreModulesPackage.java @@ -29,6 +29,7 @@ import com.facebook.react.uimanager.UIImplementationProvider; import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.ViewManager; +import com.facebook.react.uimanager.ViewManagerResolver; import com.facebook.systrace.Systrace; import java.util.Arrays; import java.util.List; @@ -149,7 +150,7 @@ private UIManagerModule createUIManager(final ReactApplicationContext reactConte Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createUIManagerModule"); try { if (mLazyViewManagersEnabled) { - UIManagerModule.ViewManagerResolver resolver = new UIManagerModule.ViewManagerResolver() { + ViewManagerResolver resolver = new ViewManagerResolver() { @Override public @Nullable ViewManager getViewManager(String viewManagerName) { return mReactInstanceManager.createViewManager(viewManagerName); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK index 5c5eae7b651b8f..128381afe74796 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK @@ -38,13 +38,13 @@ rn_android_library( react_native_target("java/com/facebook/react/uimanager/annotations:annotations"), react_native_target("java/com/facebook/react/uimanager/util:util"), react_native_target("java/com/facebook/react/uimanager/common:common"), - react_native_target("java/com/facebook/react/views/text:text_for_uimanager"), react_native_target("res:uimanager"), ], exported_deps = [ ":DisplayMetrics", react_native_dep("third-party/java/jsr-305:jsr-305"), react_native_target("java/com/facebook/react/uimanager/common:common"), + react_native_target("java/com/facebook/react/views/text:text_for_uimanager"), ], ) @@ -66,25 +66,135 @@ rn_android_library( rn_android_library( name = "uimanager_for_text", - srcs = glob([ - "ReactShadowNode.java", - "ReactShadowNodeImpl.java", - "annotations/ReactProp.java", - "IllegalViewOperationException.java", - "LayoutShadowNode.java", - "PixelUtil.java", - "ReactShadowNode.java", - "ViewDefaults.java", - "ViewProps.java", - ]), + srcs = glob( + [ + "debug/*.java", + "events/*.java", + "layoutanimation/*.java", + "PixelUtil.java", + "RootViewUtil.java", + "IllegalViewOperationException.java", + "RootView.java", + "LayoutShadowNode.java", + "ReactShadowNode.java", + "ViewDefaults.java", + "ViewProps.java", + "ReactShadowNodeImpl.java", + "ReactStylesDiffMap.java", + "Spacing.java", + "UIViewOperationQueue.java", + "NativeViewHierarchyOptimizer.java", + "ThemedReactContext.java", + "NativeViewHierarchyManager.java", + "GuardedFrameCallback.java", + "ViewAtIndex.java", + "LayoutUpdateListener.java", + "UIBlock.java", + "ShadowNodeRegistry.java", + "ViewManager.java", + "ViewManagerRegistry.java", + "RootViewManager.java", + "ViewGroupManager.java", + "ViewManagerResolver.java", + "BaseViewManager.java", + "AccessibilityDelegateUtil.java", + "MatrixMathHelper.java", + "ViewManagerPropertyUpdater.java", + "ViewManagersPropertyCache.java", + "ReactZIndexedViewGroup.java", + "AccessibilityHelper.java", + "TransformHelper.java", + "ReactYogaConfigProvider.java", + "YogaNodePool.java", + "NoSuchNativeViewException.java", + "FloatUtil.java", + "TouchTargetHelper.java", + "UIManagerModuleConstants.java", + "PointerEvents.java", + "ReactPointerEventsView.java", + "ReactCompoundView.java", + "ReactCompoundViewGroup.java", + ], + exclude = ["DisplayMetricsHolder.java"], + ), + provided_deps = [ + react_native_dep("third-party/android/support/v4:lib-support-v4"), + react_native_dep("third-party/android/support-annotations:android-support-annotations"), + ], required_for_source_only_abi = True, visibility = [ "PUBLIC", ], deps = [ YOGA_TARGET, + ":DisplayMetrics", + react_native_dep("java/com/facebook/systrace:systrace"), + react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"), react_native_dep("third-party/java/infer-annotations:infer-annotations"), + react_native_target("java/com/facebook/debug/tags:tags"), + react_native_target("java/com/facebook/debug/holder:holder"), + react_native_target("java/com/facebook/react/animation:animation"), + react_native_target("java/com/facebook/react/bridge:bridge"), + react_native_target("java/com/facebook/react/common:common"), + react_native_target("java/com/facebook/react/config:config"), + react_native_target("java/com/facebook/react/module/annotations:annotations"), + react_native_target("java/com/facebook/react/modules/core:core"), + react_native_target("java/com/facebook/react/modules/i18nmanager:i18nmanager"), + react_native_target("java/com/facebook/react/touch:touch"), react_native_target("java/com/facebook/react/uimanager/annotations:annotations"), + react_native_target("java/com/facebook/react/uimanager/util:util"), + react_native_target("java/com/facebook/react/uimanager/common:common"), + react_native_target("res:uimanager"), + ], + exported_deps = [ + ":DisplayMetrics", + react_native_dep("third-party/java/jsr-305:jsr-305"), + react_native_target("java/com/facebook/react/uimanager/common:common"), + ], +) + +rn_android_library( + name = "uimanager_for_view", + srcs = glob( + [ + "FloatUtil.java", + "Spacing.java", + ], + exclude = ["DisplayMetricsHolder.java"], + ), + provided_deps = [ + react_native_dep("third-party/android/support/v4:lib-support-v4"), + react_native_dep("third-party/android/support-annotations:android-support-annotations"), + ], + required_for_source_only_abi = True, + visibility = [ + "PUBLIC", + ], + deps = [ + YOGA_TARGET, + ":DisplayMetrics", + react_native_dep("java/com/facebook/systrace:systrace"), + react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"), + react_native_dep("third-party/java/infer-annotations:infer-annotations"), + react_native_target("java/com/facebook/debug/tags:tags"), + react_native_target("java/com/facebook/debug/holder:holder"), + react_native_target("java/com/facebook/react/animation:animation"), + react_native_target("java/com/facebook/react/bridge:bridge"), + react_native_target("java/com/facebook/react/common:common"), + react_native_target("java/com/facebook/react/config:config"), + react_native_target("java/com/facebook/react/module/annotations:annotations"), + react_native_target("java/com/facebook/react/modules/core:core"), react_native_target("java/com/facebook/react/modules/i18nmanager:i18nmanager"), + react_native_target("java/com/facebook/react/touch:touch"), + react_native_target("java/com/facebook/react/uimanager/annotations:annotations"), + react_native_target("java/com/facebook/react/uimanager/util:util"), + react_native_target("java/com/facebook/react/uimanager/common:common"), + react_native_target("res:uimanager"), + ], + exported_deps = [ + ":DisplayMetrics", + react_native_dep("third-party/java/jsr-305:jsr-305"), + react_native_target("java/com/facebook/react/uimanager/common:common"), ], ) + diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutUpdateListener.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutUpdateListener.java new file mode 100644 index 00000000000000..906e2328db797d --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutUpdateListener.java @@ -0,0 +1,8 @@ +package com.facebook.react.uimanager; + +/** Interface definition for a callback to be invoked when the layout has been updated */ +public interface LayoutUpdateListener { + + /** Called when the layout has been updated */ + void onLayoutUpdated(ReactShadowNode root); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java index 747e7bdc8dc22d..61020a996beba0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java @@ -61,16 +61,9 @@ public class UIImplementation { private long mLastCalculateLayoutTime = 0; protected @Nullable LayoutUpdateListener mLayoutUpdateListener; - /** Interface definition for a callback to be invoked when the layout has been updated */ - public interface LayoutUpdateListener { - - /** Called when the layout has been updated */ - void onLayoutUpdated(ReactShadowNode root); - } - public UIImplementation( ReactApplicationContext reactContext, - UIManagerModule.ViewManagerResolver viewManagerResolver, + ViewManagerResolver viewManagerResolver, EventDispatcher eventDispatcher, int minTimeLeftInFrameForNonBatchedOperationMs) { this( diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementationProvider.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementationProvider.java index 379bf971619ce7..b675b7cc452176 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementationProvider.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementationProvider.java @@ -18,7 +18,7 @@ public class UIImplementationProvider { public UIImplementation createUIImplementation( ReactApplicationContext reactContext, - UIManagerModule.ViewManagerResolver viewManagerResolver, + ViewManagerResolver viewManagerResolver, EventDispatcher eventDispatcher, int minTimeLeftInFrameForNonBatchedOperationMs) { return new UIImplementation( 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 bd2a3355522e0c..5eb43431bb94f4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java @@ -82,21 +82,6 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements OnBatchCompleteListener, LifecycleEventListener, UIManager { - /** Enables lazy discovery of a specific {@link ViewManager} by its name. */ - public interface ViewManagerResolver { - /** - * {@class UIManagerModule} class uses this method to get a ViewManager by its name. This is the - * same name that comes from JS by {@code UIManager.ViewManagerName} call. - */ - @Nullable - ViewManager getViewManager(String viewManagerName); - - /** - * Provides a list of view manager names to register in JS as {@code UIManager.ViewManagerName} - */ - List getViewManagerNames(); - } - /** Resolves a name coming from native side to a name of the event that is exposed to JS. */ public interface CustomEventNamesResolver { /** Returns custom event name by the provided event name. */ diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java index 8e993c1935cfe5..b074a3c935a97c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java @@ -33,7 +33,7 @@ * registered on the JS side with the help of {@code UIManagerModule.getConstantsForViewManager}. */ /* package */ static Map createConstants( - UIManagerModule.ViewManagerResolver resolver) { + ViewManagerResolver resolver) { Map constants = UIManagerModuleConstants.getConstants(); if (!ReactFeatureFlags.lazilyLoadViewManagers) { constants.put("ViewManagerNames", resolver.getViewManagerNames()); 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 68fec4b0737a31..c1a11d639d4618 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java @@ -96,38 +96,38 @@ public void execute() { } } - private final class EmitOnLayoutEventOperation extends ViewOperation { - - private final int mScreenX; - private final int mScreenY; - private final int mScreenWidth; - private final int mScreenHeight; - - public EmitOnLayoutEventOperation( - int tag, - int screenX, - int screenY, - int screenWidth, - int screenHeight) { - super(tag); - mScreenX = screenX; - mScreenY = screenY; - mScreenWidth = screenWidth; - mScreenHeight = screenHeight; - } - - @Override - public void execute() { - mReactApplicationContext.getNativeModule(UIManagerModule.class) - .getEventDispatcher() - .dispatchEvent(OnLayoutEvent.obtain( - mTag, - mScreenX, - mScreenY, - mScreenWidth, - mScreenHeight)); - } - } +// private final class EmitOnLayoutEventOperation extends ViewOperation { +// +// private final int mScreenX; +// private final int mScreenY; +// private final int mScreenWidth; +// private final int mScreenHeight; +// +// public EmitOnLayoutEventOperation( +// int tag, +// int screenX, +// int screenY, +// int screenWidth, +// int screenHeight) { +// super(tag); +// mScreenX = screenX; +// mScreenY = screenY; +// mScreenWidth = screenWidth; +// mScreenHeight = screenHeight; +// } +// +// @Override +// public void execute() { +// mReactApplicationContext.getNativeModule(UIManagerModule.class) +// .getEventDispatcher() +// .dispatchEvent(OnLayoutEvent.obtain( +// mTag, +// mScreenX, +// mScreenY, +// mScreenWidth, +// mScreenHeight)); +// } +// } private final class UpdateInstanceHandleOperation extends ViewOperation { @@ -559,9 +559,9 @@ public void execute() { private final class LayoutUpdateFinishedOperation implements UIOperation { private final ReactShadowNode mNode; - private final UIImplementation.LayoutUpdateListener mListener; + private final LayoutUpdateListener mListener; - private LayoutUpdateFinishedOperation(ReactShadowNode node, UIImplementation.LayoutUpdateListener listener) { + private LayoutUpdateFinishedOperation(ReactShadowNode node, LayoutUpdateListener listener) { mNode = node; mListener = listener; } @@ -756,14 +756,14 @@ public void enqueueUpdateProperties(int reactTag, String className, ReactStylesD mOperations.add(new UpdatePropertiesOperation(reactTag, props)); } - public void enqueueOnLayoutEvent( - int tag, - int screenX, - int screenY, - int screenWidth, - int screenHeight) { - mOperations.add(new EmitOnLayoutEventOperation(tag, screenX, screenY, screenWidth, screenHeight)); - } +// public void enqueueOnLayoutEvent( +// int tag, +// int screenX, +// int screenY, +// int screenWidth, +// int screenHeight) { +// mOperations.add(new EmitOnLayoutEventOperation(tag, screenX, screenY, screenWidth, screenHeight)); +// } public void enqueueUpdateLayout( @@ -847,7 +847,7 @@ public void enqueueSendAccessibilityEvent(int tag, int eventType) { mOperations.add(new SendAccessibilityEvent(tag, eventType)); } - public void enqueueLayoutUpdateFinished(ReactShadowNode node, UIImplementation.LayoutUpdateListener listener) { + public void enqueueLayoutUpdateFinished(ReactShadowNode node, LayoutUpdateListener listener) { mOperations.add(new LayoutUpdateFinishedOperation(node, listener)); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerRegistry.java index b657eb5918c0e5..dde8307c8cb5e6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerRegistry.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerRegistry.java @@ -19,9 +19,9 @@ public final class ViewManagerRegistry { private final Map mViewManagers; - private final @Nullable UIManagerModule.ViewManagerResolver mViewManagerResolver; + private final @Nullable ViewManagerResolver mViewManagerResolver; - public ViewManagerRegistry(UIManagerModule.ViewManagerResolver viewManagerResolver) { + public ViewManagerRegistry(ViewManagerResolver viewManagerResolver) { mViewManagers = MapBuilder.newHashMap(); mViewManagerResolver = viewManagerResolver; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerResolver.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerResolver.java new file mode 100644 index 00000000000000..c2af972b236604 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManagerResolver.java @@ -0,0 +1,20 @@ +package com.facebook.react.uimanager; + +import java.util.List; + +import javax.annotation.Nullable; + +/** Enables lazy discovery of a specific {@link ViewManager} by its name. */ +public interface ViewManagerResolver { + /** + * {@class UIManagerModule} class uses this method to get a ViewManager by its name. This is the + * same name that comes from JS by {@code UIManager.ViewManagerName} call. + */ + @Nullable + ViewManager getViewManager(String viewManagerName); + + /** + * Provides a list of view manager names to register in JS as {@code UIManager.ViewManagerName} + */ + List getViewManagerNames(); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/NotThreadSafeViewHierarchyUpdateDebugListener.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/NotThreadSafeViewHierarchyUpdateDebugListener.java index ff695b8db11a32..c5bd03463cf539 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/NotThreadSafeViewHierarchyUpdateDebugListener.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/debug/NotThreadSafeViewHierarchyUpdateDebugListener.java @@ -7,8 +7,6 @@ package com.facebook.react.uimanager.debug; -import com.facebook.react.uimanager.UIManagerModule; - /** * A listener that is notified about view hierarchy update events. This listener should only be * used for debug purposes and should not affect application state. diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK index 7b5d25b1eb9da7..78ae188fa7556b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/BUCK @@ -21,14 +21,35 @@ rn_android_library( ) rn_android_library( name = "text_for_uimanager", - srcs = glob(["ReactBaseTextShadowNode.java","ReactRawTextManager.java"]), + srcs = glob([ + "ReactBaseTextShadowNode.java", + "ReactRawTextShadowNode.java", + "ReactRawTextManager.java", + "ReactTextView.java", + "ReactTextUpdate.java", + "TextTransform.java", + "ReactTextInlineImageShadowNode.java", + "TextInlineImageSpan.java", + "CustomLetterSpacingSpan.java", + "*Span.java", + "ReactTextShadowNode.java", + "ReactFontManager.java", + "FontMetricsUtil.java", + ]), required_for_source_only_abi = True, visibility = [ "PUBLIC", ], deps = [ + YOGA_TARGET, + react_native_dep("third-party/java/infer-annotations:infer-annotations"), + react_native_target("java/com/facebook/react/bridge:bridge"), react_native_target("java/com/facebook/react/common:common"), - react_native_target("java/com/facebook/react/uimanager:uimanager_for_text"), react_native_target("java/com/facebook/react/uimanager/annotations:annotations"), + react_native_target("java/com/facebook/react/module/annotations:annotations"), + react_native_target("java/com/facebook/react/uimanager:uimanager_for_text"), + react_native_target("java/com/facebook/react/views/view:view_for_text"), + ], + exported_deps = [ ], ) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/view/BUCK index a7b4d74e8b01e5..66a207b8997406 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/BUCK @@ -20,3 +20,25 @@ rn_android_library( react_native_target("java/com/facebook/react/uimanager/annotations:annotations"), ], ) + +rn_android_library( + name = "view_for_text", + srcs = glob([ + "ReactViewBackgroundManager.java", + "ReactViewBackgroundDrawable.java", + "ColorUtil.java", + + ]), + visibility = [ + "PUBLIC", + ], + deps = [ + YOGA_TARGET, + react_native_dep("third-party/java/infer-annotations:infer-annotations"), + react_native_dep("third-party/java/jsr-305:jsr-305"), + react_native_target("java/com/facebook/react/common:common"), + react_native_target("java/com/facebook/react/views/common:common"), + react_native_target("java/com/facebook/react/uimanager:uimanager_for_view"), + react_native_target("java/com/facebook/react/modules/i18nmanager:i18nmanager"), + ], +)