/** * 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.uimanager; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import android.graphics.Color; import android.view.Choreographer; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.facebook.react.ReactRootView; import com.facebook.react.animation.Animation; import com.facebook.react.animation.AnimationPropertyUpdater; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Callback; 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.views.text.ReactRawTextManager; import com.facebook.react.views.text.ReactTextShadowNode; import com.facebook.react.views.text.ReactTextViewManager; import com.facebook.react.views.view.ReactViewGroup; import com.facebook.react.views.view.ReactViewManager; import org.junit.Before; import org.junit.Rule; import org.junit.Test; 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 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.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** * Tests for {@link UIManagerModule}. */ @PrepareForTest({Arguments.class, ReactChoreographer.class}) @RunWith(RobolectricTestRunner.class) @PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"}) public class UIManagerModuleTest { @Rule public PowerMockRule rule = new PowerMockRule(); private ReactApplicationContext mReactContext; private CatalystInstance mCatalystInstanceMock; private ArrayList<Choreographer.FrameCallback> mPendingChoreographerCallbacks; @Before public void setUp() { PowerMockito.mockStatic(Arguments.class, ReactChoreographer.class); ReactChoreographer choreographerMock = mock(ReactChoreographer.class); PowerMockito.when(Arguments.createArray()).thenAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { return new JavaOnlyArray(); } }); PowerMockito.when(Arguments.createMap()).thenAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { return new JavaOnlyMap(); } }); PowerMockito.when(ReactChoreographer.getInstance()).thenReturn(choreographerMock); mPendingChoreographerCallbacks = new ArrayList<>(); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { mPendingChoreographerCallbacks .add((Choreographer.FrameCallback) invocation.getArguments()[1]); return null; } }).when(choreographerMock).postFrameCallback( any(ReactChoreographer.CallbackType.class), any(Choreographer.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); } @Test public void testCreateSimpleHierarchy() { UIManagerModule uiManager = getUIManagerModule(); ViewGroup rootView = createSimpleTextHierarchy(uiManager, "Some text"); assertThat(rootView.getChildCount()).isEqualTo(1); View firstChild = rootView.getChildAt(0); assertThat(firstChild).isInstanceOf(TextView.class); assertThat(((TextView) firstChild).getText().toString()).isEqualTo("Some text"); } @Test public void testUpdateSimpleHierarchy() { UIManagerModule uiManager = getUIManagerModule(); ViewGroup rootView = createSimpleTextHierarchy(uiManager, "Some text"); TextView textView = (TextView) rootView.getChildAt(0); int rawTextTag = 3; uiManager.updateView( rawTextTag, ReactRawTextManager.REACT_CLASS, JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, "New text")); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); assertThat(textView.getText().toString()).isEqualTo("New text"); } @Test public void testHierarchyWithView() { UIManagerModule uiManager = getUIManagerModule(); ReactRootView rootView = new ReactRootView(RuntimeEnvironment.application.getApplicationContext()); int rootTag = uiManager.addMeasuredRootView(rootView); int viewTag = rootTag + 1; int subViewTag = viewTag + 1; uiManager.createView( viewTag, ReactViewManager.REACT_CLASS, rootTag, JavaOnlyMap.of("collapsable", false)); uiManager.createView( subViewTag, ReactViewManager.REACT_CLASS, rootTag, JavaOnlyMap.of("collapsable", false)); uiManager.manageChildren( viewTag, null, null, JavaOnlyArray.of(subViewTag), JavaOnlyArray.of(0), null); uiManager.manageChildren( rootTag, null, null, JavaOnlyArray.of(viewTag), JavaOnlyArray.of(0), null); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); assertThat(rootView.getChildCount()).isEqualTo(1); ViewGroup child = (ViewGroup) rootView.getChildAt(0); assertThat(child.getChildCount()).isEqualTo(1); ViewGroup grandchild = (ViewGroup) child.getChildAt(0); assertThat(grandchild).isInstanceOf(ViewGroup.class); assertThat(grandchild.getChildCount()).isEqualTo(0); } @Test public void testMoveViews() { UIManagerModule uiManager = getUIManagerModule(); TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager); View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(1); View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(2); View expectedViewAt2 = hierarchy.nativeRootView.getChildAt(0); View expectedViewAt3 = hierarchy.nativeRootView.getChildAt(3); uiManager.manageChildren( hierarchy.rootView, JavaOnlyArray.of(1, 0, 2), JavaOnlyArray.of(0, 2, 1), null, null, null); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); assertChildrenAreExactly( hierarchy.nativeRootView, expectedViewAt0, expectedViewAt1, expectedViewAt2, expectedViewAt3); } @Test public void testDeleteViews() { UIManagerModule uiManager = getUIManagerModule(); TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager); View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(1); View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(2); uiManager.manageChildren( hierarchy.rootView, null, null, null, null, JavaOnlyArray.of(0, 3)); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); assertChildrenAreExactly( hierarchy.nativeRootView, expectedViewAt0, expectedViewAt1); } @Test public void testMoveAndDeleteViews() { UIManagerModule uiManager = getUIManagerModule(); TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager); View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(0); View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(3); View expectedViewAt2 = hierarchy.nativeRootView.getChildAt(2); uiManager.manageChildren( hierarchy.rootView, JavaOnlyArray.of(3), JavaOnlyArray.of(1), null, null, JavaOnlyArray.of(1)); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); assertChildrenAreExactly( hierarchy.nativeRootView, expectedViewAt0, expectedViewAt1, expectedViewAt2); } @Test(expected = IllegalViewOperationException.class) public void testMoveAndDeleteRemoveViewsDuplicateRemove() { UIManagerModule uiManager = getUIManagerModule(); TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager); uiManager.manageChildren( hierarchy.rootView, JavaOnlyArray.of(3), JavaOnlyArray.of(1), null, null, JavaOnlyArray.of(3)); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); } @Test(expected = IllegalViewOperationException.class) public void testDuplicateRemove() { UIManagerModule uiManager = getUIManagerModule(); TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager); uiManager.manageChildren( hierarchy.rootView, null, null, null, null, JavaOnlyArray.of(3, 3)); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); } @Test public void testMoveAndAddViews() { UIManagerModule uiManager = getUIManagerModule(); TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager); int textViewTag = 1000; uiManager.createView( textViewTag, ReactTextViewManager.REACT_CLASS, hierarchy.rootView, JavaOnlyMap.of("collapsable", false)); View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(0); View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(3); View expectedViewAt3 = hierarchy.nativeRootView.getChildAt(1); View expectedViewAt4 = hierarchy.nativeRootView.getChildAt(2); uiManager.manageChildren( hierarchy.rootView, JavaOnlyArray.of(1, 2, 3), JavaOnlyArray.of(3, 4, 1), JavaOnlyArray.of(textViewTag), JavaOnlyArray.of(2), null); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); assertThat(hierarchy.nativeRootView.getChildCount()).isEqualTo(5); assertThat(hierarchy.nativeRootView.getChildAt(0)).isEqualTo(expectedViewAt0); assertThat(hierarchy.nativeRootView.getChildAt(1)).isEqualTo(expectedViewAt1); assertThat(hierarchy.nativeRootView.getChildAt(3)).isEqualTo(expectedViewAt3); assertThat(hierarchy.nativeRootView.getChildAt(4)).isEqualTo(expectedViewAt4); } @Test public void testMoveViewsWithChildren() { UIManagerModule uiManager = getUIManagerModule(); TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager); View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(0); View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(2); View expectedViewAt2 = hierarchy.nativeRootView.getChildAt(1); View expectedViewAt3 = hierarchy.nativeRootView.getChildAt(3); uiManager.manageChildren( hierarchy.rootView, JavaOnlyArray.of(1, 2), JavaOnlyArray.of(2, 1), null, null, null); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); assertChildrenAreExactly( hierarchy.nativeRootView, expectedViewAt0, expectedViewAt1, expectedViewAt2, expectedViewAt3); assertThat(((ViewGroup) hierarchy.nativeRootView.getChildAt(2)).getChildCount()).isEqualTo(2); } @Test public void testDeleteViewsWithChildren() { UIManagerModule uiManager = getUIManagerModule(); TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager); View expectedViewAt0 = hierarchy.nativeRootView.getChildAt(0); View expectedViewAt1 = hierarchy.nativeRootView.getChildAt(2); View expectedViewAt2 = hierarchy.nativeRootView.getChildAt(3); uiManager.manageChildren( hierarchy.rootView, null, null, null, null, JavaOnlyArray.of(1)); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); assertChildrenAreExactly( hierarchy.nativeRootView, expectedViewAt0, expectedViewAt1, expectedViewAt2); } @Test public void testLayoutAppliedToNodes() throws Exception { UIManagerModule uiManager = getUIManagerModule(); TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager); int newViewTag = 10000; uiManager.createView( newViewTag, ReactViewManager.REACT_CLASS, hierarchy.rootView, JavaOnlyMap .of("left", 10.0, "top", 20.0, "width", 30.0, "height", 40.0, "collapsable", false)); uiManager.manageChildren( hierarchy.rootView, null, null, JavaOnlyArray.of(newViewTag), JavaOnlyArray.of(4), null); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); View newView = hierarchy.nativeRootView.getChildAt(4); assertThat(newView.getLeft()).isEqualTo(10); assertThat(newView.getTop()).isEqualTo(20); assertThat(newView.getWidth()).isEqualTo(30); assertThat(newView.getHeight()).isEqualTo(40); } /** * This is to make sure we execute enqueued operations in the order given by JS. */ @Test public void testAddUpdateRemoveInSingleBatch() { UIManagerModule uiManager = getUIManagerModule(); TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager); int newViewTag = 10000; uiManager.createView( newViewTag, ReactViewManager.REACT_CLASS, hierarchy.rootView, JavaOnlyMap.of("collapsable", false)); uiManager.manageChildren( hierarchy.rootView, null, null, JavaOnlyArray.of(newViewTag), JavaOnlyArray.of(4), null); uiManager.updateView( newViewTag, ReactViewManager.REACT_CLASS, JavaOnlyMap.of("backgroundColor", Color.RED)); uiManager.manageChildren( hierarchy.rootView, null, null, null, null, JavaOnlyArray.of(4)); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); assertThat(hierarchy.nativeRootView.getChildCount()).isEqualTo(4); } @Test public void testTagsAssignment() { UIManagerModule uiManager = getUIManagerModule(); TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager); View view0 = hierarchy.nativeRootView.getChildAt(0); assertThat(view0.getId()).isEqualTo(hierarchy.view0); View viewWithChildren1 = hierarchy.nativeRootView.getChildAt(1); assertThat(viewWithChildren1.getId()).isEqualTo(hierarchy.viewWithChildren1); View childView0 = ((ViewGroup) viewWithChildren1).getChildAt(0); assertThat(childView0.getId()).isEqualTo(hierarchy.childView0); View childView1 = ((ViewGroup) viewWithChildren1).getChildAt(1); assertThat(childView1.getId()).isEqualTo(hierarchy.childView1); View view2 = hierarchy.nativeRootView.getChildAt(2); assertThat(view2.getId()).isEqualTo(hierarchy.view2); View view3 = hierarchy.nativeRootView.getChildAt(3); assertThat(view3.getId()).isEqualTo(hierarchy.view3); } @Test public void testLayoutPropertyUpdatingOnlyOnLayoutChange() { UIManagerModule uiManager = getUIManagerModule(); TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager); // Update layout to some values, this way we can verify it hasn't been updated, because the // update process would normally reset it back to some non-negative value View view0 = hierarchy.nativeRootView.getChildAt(0); view0.layout(1, 2, 3, 4); // verify that X get updated when we update layout properties uiManager.updateView( hierarchy.view0, ReactViewManager.REACT_CLASS, JavaOnlyMap.of("left", 10.0, "top", 20.0, "width", 30.0, "height", 40.0)); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); assertThat(view0.getLeft()).isGreaterThan(2); // verify that the layout doesn't get updated when we update style property not affecting the // position (e.g., background-color) view0.layout(1, 2, 3, 4); uiManager.updateView( hierarchy.view0, ReactViewManager.REACT_CLASS, JavaOnlyMap.of("backgroundColor", Color.RED)); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); assertThat(view0.getLeft()).isEqualTo(1); } private static class AnimationStub extends Animation { public AnimationStub(int animationID, AnimationPropertyUpdater propertyUpdater) { super(animationID, propertyUpdater); } @Override public void run() { } } @Test public void testAddAndRemoveAnimation() { UIManagerModule uiManagerModule = getUIManagerModule(); TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManagerModule); AnimationPropertyUpdater mockPropertyUpdater = mock(AnimationPropertyUpdater.class); Animation mockAnimation = spy(new AnimationStub(1000, mockPropertyUpdater)); Callback callbackMock = mock(Callback.class); int rootTag = hierarchy.rootView; uiManagerModule.createView( hierarchy.rootView, ReactViewManager.REACT_CLASS, rootTag, JavaOnlyMap.of("collapsable", false)); uiManagerModule.registerAnimation(mockAnimation); uiManagerModule.addAnimation(hierarchy.rootView, 1000, callbackMock); uiManagerModule.removeAnimation(hierarchy.rootView, 1000); uiManagerModule.onBatchComplete(); executePendingChoreographerCallbacks(); verify(callbackMock, times(1)).invoke(false); verify(mockAnimation).run(); verify(mockAnimation).cancel(); } /** * Makes sure replaceExistingNonRootView by replacing a view with a new view that has a background * color set. */ @Test public void testReplaceExistingNonRootView() { UIManagerModule uiManager = getUIManagerModule(); TestMoveDeleteHierarchy hierarchy = createMoveDeleteHierarchy(uiManager); int newViewTag = 1234; uiManager.createView( newViewTag, ReactViewManager.REACT_CLASS, hierarchy.rootView, JavaOnlyMap.of("backgroundColor", Color.RED)); uiManager.replaceExistingNonRootView(hierarchy.view2, newViewTag); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); assertThat(hierarchy.nativeRootView.getChildCount()).isEqualTo(4); assertThat(hierarchy.nativeRootView.getChildAt(2)).isInstanceOf(ReactViewGroup.class); ReactViewGroup view = (ReactViewGroup) hierarchy.nativeRootView.getChildAt(2); assertThat(view.getBackgroundColor()).isEqualTo(Color.RED); } /** * Verifies removeSubviewsFromContainerWithID works by adding subviews, removing them, and * checking that the final number of children is correct. */ @Test public void testRemoveSubviewsFromContainerWithID() { UIManagerModule uiManager = getUIManagerModule(); ReactRootView rootView = new ReactRootView(RuntimeEnvironment.application.getApplicationContext()); int rootTag = uiManager.addMeasuredRootView(rootView); final int containerTag = rootTag + 1; final int containerSiblingTag = containerTag + 1; uiManager.createView( containerTag, ReactViewManager.REACT_CLASS, rootTag, JavaOnlyMap.of("collapsable", false)); uiManager.createView( containerSiblingTag, ReactViewManager.REACT_CLASS, rootTag, JavaOnlyMap.of("collapsable", false)); addChild(uiManager, rootTag, containerTag, 0); addChild(uiManager, rootTag, containerSiblingTag, 1); uiManager.createView( containerTag + 2, ReactTextViewManager.REACT_CLASS, rootTag, JavaOnlyMap.of("collapsable", false)); uiManager.createView( containerTag + 3, ReactTextViewManager.REACT_CLASS, rootTag, JavaOnlyMap.of("collapsable", false)); addChild(uiManager, containerTag, containerTag + 2, 0); addChild(uiManager, containerTag, containerTag + 3, 1); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); assertThat(rootView.getChildCount()).isEqualTo(2); assertThat(((ViewGroup) rootView.getChildAt(0)).getChildCount()).isEqualTo(2); uiManager.removeSubviewsFromContainerWithID(containerTag); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); assertThat(rootView.getChildCount()).isEqualTo(2); assertThat(((ViewGroup) rootView.getChildAt(0)).getChildCount()).isEqualTo(0); } /** * Assuming no other views have been created, the root view will have tag 1, Text tag 2, and * RawText tag 3. */ private ViewGroup createSimpleTextHierarchy(UIManagerModule uiManager, String text) { ReactRootView rootView = new ReactRootView(RuntimeEnvironment.application.getApplicationContext()); int rootTag = uiManager.addMeasuredRootView(rootView); int textTag = rootTag + 1; int rawTextTag = textTag + 1; uiManager.createView( textTag, ReactTextViewManager.REACT_CLASS, rootTag, JavaOnlyMap.of("collapsable", false)); uiManager.createView( rawTextTag, ReactRawTextManager.REACT_CLASS, rootTag, JavaOnlyMap.of(ReactTextShadowNode.PROP_TEXT, text, "collapsable", false)); uiManager.manageChildren( textTag, null, null, JavaOnlyArray.of(rawTextTag), JavaOnlyArray.of(0), null); uiManager.manageChildren( rootTag, null, null, JavaOnlyArray.of(textTag), JavaOnlyArray.of(0), null); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); return rootView; } private TestMoveDeleteHierarchy createMoveDeleteHierarchy(UIManagerModule uiManager) { ReactRootView rootView = new ReactRootView(mReactContext); int rootTag = uiManager.addMeasuredRootView(rootView); TestMoveDeleteHierarchy hierarchy = new TestMoveDeleteHierarchy(rootView, rootTag); uiManager.createView( hierarchy.view0, ReactViewManager.REACT_CLASS, rootTag, JavaOnlyMap.of("collapsable", false)); uiManager.createView( hierarchy.viewWithChildren1, ReactViewManager.REACT_CLASS, rootTag, JavaOnlyMap.of("collapsable", false)); uiManager.createView( hierarchy.view2, ReactViewManager.REACT_CLASS, rootTag, JavaOnlyMap.of("collapsable", false)); uiManager.createView( hierarchy.view3, ReactViewManager.REACT_CLASS, rootTag, JavaOnlyMap.of("collapsable", false)); uiManager.createView( hierarchy.childView0, ReactViewManager.REACT_CLASS, rootTag, JavaOnlyMap.of("collapsable", false)); uiManager.createView( hierarchy.childView1, ReactViewManager.REACT_CLASS, rootTag, JavaOnlyMap.of("collapsable", false)); addChild(uiManager, rootTag, hierarchy.view0, 0); addChild(uiManager, rootTag, hierarchy.viewWithChildren1, 1); addChild(uiManager, rootTag, hierarchy.view2, 2); addChild(uiManager, rootTag, hierarchy.view3, 3); addChild(uiManager, hierarchy.viewWithChildren1, hierarchy.childView0, 0); addChild(uiManager, hierarchy.viewWithChildren1, hierarchy.childView1, 1); uiManager.onBatchComplete(); executePendingChoreographerCallbacks(); return hierarchy; } private void addChild(UIManagerModule uiManager, int parentTag, int childTag, int index) { uiManager.manageChildren( parentTag, null, null, JavaOnlyArray.of(childTag), JavaOnlyArray.of(index), null); } private void assertChildrenAreExactly(ViewGroup parent, View... views) { assertThat(parent.getChildCount()).isEqualTo(views.length); for (int i = 0; i < views.length; i++) { assertThat(parent.getChildAt(i)) .describedAs("View at " + i) .isEqualTo(views[i]); } } /** * Holder for the tags that represent that represent views in the following hierarchy: * - View rootView * - View view0 * - View viewWithChildren1 * - View childView0 * - View childView1 * - View view2 * - View view3 * * This hierarchy is used to test move/delete functionality in manageChildren. */ private static class TestMoveDeleteHierarchy { public ReactRootView nativeRootView; public int rootView; public int view0; public int viewWithChildren1; public int view2; public int view3; public int childView0; public int childView1; public TestMoveDeleteHierarchy(ReactRootView nativeRootView, int rootViewTag) { this.nativeRootView = nativeRootView; rootView = rootViewTag; view0 = rootView + 1; viewWithChildren1 = rootView + 2; view2 = rootView + 3; view3 = rootView + 4; childView0 = rootView + 5; childView1 = rootView + 6; } } private void executePendingChoreographerCallbacks() { ArrayList<Choreographer.FrameCallback> callbacks = new ArrayList<>(mPendingChoreographerCallbacks); mPendingChoreographerCallbacks.clear(); for (Choreographer.FrameCallback frameCallback : callbacks) { frameCallback.doFrame(0); } } private UIManagerModule getUIManagerModule() { List<ViewManager> viewManagers = Arrays.<ViewManager>asList( new ReactViewManager(), new ReactTextViewManager(), new ReactRawTextManager()); UIManagerModule uiManagerModule = new UIManagerModule( mReactContext, viewManagers, new UIImplementationProvider()); uiManagerModule.onHostResume(); return uiManagerModule; } }