diff --git a/React/Views/ScrollView/RCTScrollContentView.m b/React/Views/ScrollView/RCTScrollContentView.m index cf6a0b1f17953d..8006540a70f136 100644 --- a/React/Views/ScrollView/RCTScrollContentView.m +++ b/React/Views/ScrollView/RCTScrollContentView.m @@ -26,7 +26,7 @@ - (void)reactSetFrame:(CGRect)frame RCTAssert([scrollView isKindOfClass:[RCTScrollView class]], @"Unexpected view hierarchy of RCTScrollView component."); - [scrollView updateContentOffsetIfNeeded]; + [scrollView updateContentSizeIfNeeded]; } @end diff --git a/React/Views/ScrollView/RCTScrollView.h b/React/Views/ScrollView/RCTScrollView.h index 4a508ee1e9d8a2..765d3b3378a5a6 100644 --- a/React/Views/ScrollView/RCTScrollView.h +++ b/React/Views/ScrollView/RCTScrollView.h @@ -28,12 +28,6 @@ */ @property (nonatomic, readonly) UIView *contentView; -/** - * If the `contentSize` is not specified (or is specified as {0, 0}, then the - * `contentSize` will automatically be determined by the size of the subview. - */ -@property (nonatomic, assign) CGSize contentSize; - /** * The underlying scrollView (TODO: can we remove this?) */ @@ -68,7 +62,7 @@ @interface RCTScrollView (Internal) -- (void)updateContentOffsetIfNeeded; +- (void)updateContentSizeIfNeeded; @end diff --git a/React/Views/ScrollView/RCTScrollView.m b/React/Views/ScrollView/RCTScrollView.m index c52f449c730015..c9fe67bb9edbbe 100644 --- a/React/Views/ScrollView/RCTScrollView.m +++ b/React/Views/ScrollView/RCTScrollView.m @@ -301,7 +301,6 @@ - (instancetype)initWithEventDispatcher:(id)eventDis _automaticallyAdjustContentInsets = YES; _contentInset = UIEdgeInsetsZero; - _contentSize = CGSizeZero; _lastClippedToRect = CGRectNull; _scrollEventThrottle = 0.0; @@ -381,7 +380,7 @@ - (void)didUpdateReactSubviews - (void)didSetProps:(NSArray *)changedProps { if ([changedProps containsObject:@"contentSize"]) { - [self updateContentOffsetIfNeeded]; + [self updateContentSizeIfNeeded]; } } @@ -799,8 +798,6 @@ - (UIView *)viewForZoomingInScrollView:(__unused UIScrollView *)scrollView return _contentView; } -#pragma mark - Setters - - (CGSize)_calculateViewportSize { CGSize viewportSize = self.bounds.size; @@ -813,71 +810,16 @@ - (CGSize)_calculateViewportSize return viewportSize; } -- (CGPoint)calculateOffsetForContentSize:(CGSize)newContentSize -{ - CGPoint oldOffset = _scrollView.contentOffset; - CGPoint newOffset = oldOffset; - - CGSize oldContentSize = _scrollView.contentSize; - CGSize viewportSize = [self _calculateViewportSize]; - - BOOL fitsinViewportY = oldContentSize.height <= viewportSize.height && newContentSize.height <= viewportSize.height; - if (newContentSize.height < oldContentSize.height && !fitsinViewportY) { - CGFloat offsetHeight = oldOffset.y + viewportSize.height; - if (oldOffset.y < 0) { - // overscrolled on top, leave offset alone - } else if (offsetHeight > oldContentSize.height) { - // overscrolled on the bottom, preserve overscroll amount - newOffset.y = MAX(0, oldOffset.y - (oldContentSize.height - newContentSize.height)); - } else if (offsetHeight > newContentSize.height) { - // offset falls outside of bounds, scroll back to end of list - newOffset.y = MAX(0, newContentSize.height - viewportSize.height); - } - } - - BOOL fitsinViewportX = oldContentSize.width <= viewportSize.width && newContentSize.width <= viewportSize.width; - if (newContentSize.width < oldContentSize.width && !fitsinViewportX) { - CGFloat offsetHeight = oldOffset.x + viewportSize.width; - if (oldOffset.x < 0) { - // overscrolled at the beginning, leave offset alone - } else if (offsetHeight > oldContentSize.width && newContentSize.width > viewportSize.width) { - // overscrolled at the end, preserve overscroll amount as much as possible - newOffset.x = MAX(0, oldOffset.x - (oldContentSize.width - newContentSize.width)); - } else if (offsetHeight > newContentSize.width) { - // offset falls outside of bounds, scroll back to end - newOffset.x = MAX(0, newContentSize.width - viewportSize.width); - } - } - - // all other cases, offset doesn't change - return newOffset; -} - -/** - * Once you set the `contentSize`, to a nonzero value, it is assumed to be - * managed by you, and we'll never automatically compute the size for you, - * unless you manually reset it back to {0, 0} - */ - (CGSize)contentSize { - if (!CGSizeEqualToSize(_contentSize, CGSizeZero)) { - return _contentSize; - } - return _contentView.frame.size; } -- (void)updateContentOffsetIfNeeded +- (void)updateContentSizeIfNeeded { CGSize contentSize = self.contentSize; if (!CGSizeEqualToSize(_scrollView.contentSize, contentSize)) { - // When contentSize is set manually, ScrollView internals will reset - // contentOffset to {0, 0}. Since we potentially set contentSize whenever - // anything in the ScrollView updates, we workaround this issue by manually - // adjusting contentOffset whenever this happens - CGPoint newOffset = [self calculateOffsetForContentSize:contentSize]; _scrollView.contentSize = contentSize; - _scrollView.contentOffset = newOffset; } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeMap.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeMap.java index d6693e1d87d9d2..a2e4319224abcc 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeMap.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableNativeMap.java @@ -12,7 +12,6 @@ import com.facebook.infer.annotation.Assertions; import com.facebook.jni.HybridData; import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.react.config.ReactFeatureFlags; import java.util.HashMap; import java.util.Iterator; import java.util.Map; @@ -89,64 +88,6 @@ private HashMap getLocalMap() { return mLocalTypeMap; } - private Iterator> createExperimentalIterator() { - if (mKeys == null) { - mKeys = Assertions.assertNotNull(importKeys()); - } - final String[] iteratorKeys = mKeys; - final Object[] iteratorValues = Assertions.assertNotNull(importValues()); - return new Iterator>() { - int currentIndex = 0; - - @Override - public boolean hasNext() { - return currentIndex < iteratorKeys.length; - } - - @Override - public Map.Entry next() { - final int index = currentIndex++; - return new Map.Entry() { - @Override - public String getKey() { - return iteratorKeys[index]; - } - - @Override - public Object getValue() { - return iteratorValues[index]; - } - - @Override - public Object setValue(Object value) { - throw new UnsupportedOperationException( - "Can't set a value while iterating over a ReadableNativeMap"); - } - }; - } - }; - } - - private ReadableMapKeySetIterator createExperimentalKeySetIterator() { - if (mKeys == null) { - mKeys = Assertions.assertNotNull(importKeys()); - } - final String[] iteratorKeys = mKeys; - return new ReadableMapKeySetIterator() { - int currentIndex = 0; - - @Override - public boolean hasNextKey() { - return currentIndex < iteratorKeys.length; - } - - @Override - public String nextKey() { - return iteratorKeys[currentIndex++]; - } - }; - } - private native Object[] importTypes(); @Override @@ -246,16 +187,62 @@ public int getInt(@NonNull String name) { @Override public @NonNull Iterator> getEntryIterator() { - return ReactFeatureFlags.enableExperimentalReadableNativeMapIterator - ? createExperimentalIterator() - : getLocalMap().entrySet().iterator(); + if (mKeys == null) { + mKeys = Assertions.assertNotNull(importKeys()); + } + final String[] iteratorKeys = mKeys; + final Object[] iteratorValues = Assertions.assertNotNull(importValues()); + return new Iterator>() { + int currentIndex = 0; + + @Override + public boolean hasNext() { + return currentIndex < iteratorKeys.length; + } + + @Override + public Map.Entry next() { + final int index = currentIndex++; + return new Map.Entry() { + @Override + public String getKey() { + return iteratorKeys[index]; + } + + @Override + public Object getValue() { + return iteratorValues[index]; + } + + @Override + public Object setValue(Object value) { + throw new UnsupportedOperationException( + "Can't set a value while iterating over a ReadableNativeMap"); + } + }; + } + }; } @Override public @NonNull ReadableMapKeySetIterator keySetIterator() { - return ReactFeatureFlags.enableExperimentalReadableNativeMapIterator - ? createExperimentalKeySetIterator() - : new ReadableNativeMapKeySetIterator(this); + if (mKeys == null) { + mKeys = Assertions.assertNotNull(importKeys()); + } + final String[] iteratorKeys = mKeys; + return new ReadableMapKeySetIterator() { + int currentIndex = 0; + + @Override + public boolean hasNextKey() { + return currentIndex < iteratorKeys.length; + } + + @Override + public String nextKey() { + return iteratorKeys[currentIndex++]; + } + }; } @Override diff --git a/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java b/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java index d1318d9237d469..2fddf14715c8ea 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java +++ b/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java @@ -57,9 +57,6 @@ public class ReactFeatureFlags { /** Feature flag to configure eager initialization of Fabric */ public static boolean eagerInitializeFabric = false; - /** Use lock-free data structures for Fabric MountItems. */ - public static boolean enableLockFreeMountInstructions = false; - /** Disable UI update operations in non-Fabric renderer after catalyst instance was destroyed */ public static boolean disableNonFabricViewOperationsOnCatalystDestroy = false; @@ -69,9 +66,6 @@ public class ReactFeatureFlags { */ public static boolean enableStartSurfaceRaceConditionFix = false; - /** Enables the usage of an experimental optimized iterator for ReadableNativeMaps. */ - public static boolean enableExperimentalReadableNativeMapIterator = false; - /** Enables Static ViewConfig in RN Android native code. */ public static boolean enableExperimentalStaticViewConfigs = false; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java index 91fe11b20cd55e..4ffef756aa1410 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java @@ -8,7 +8,6 @@ package com.facebook.react.fabric; import androidx.annotation.NonNull; -import com.facebook.infer.annotation.Assertions; import com.facebook.react.bridge.JSIModuleProvider; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.UIManager; @@ -18,25 +17,18 @@ import com.facebook.react.fabric.events.FabricEventEmitter; import com.facebook.react.fabric.mounting.LayoutMetricsConversions; import com.facebook.react.fabric.mounting.MountingManager; -import com.facebook.react.fabric.mounting.mountitems.BatchMountItem; -import com.facebook.react.fabric.mounting.mountitems.CreateMountItem; import com.facebook.react.fabric.mounting.mountitems.DispatchCommandMountItem; import com.facebook.react.fabric.mounting.mountitems.DispatchIntCommandMountItem; import com.facebook.react.fabric.mounting.mountitems.DispatchStringCommandMountItem; -import com.facebook.react.fabric.mounting.mountitems.InsertMountItem; +import com.facebook.react.fabric.mounting.mountitems.IntBufferBatchMountItem; import com.facebook.react.fabric.mounting.mountitems.MountItem; import com.facebook.react.fabric.mounting.mountitems.PreAllocateViewMountItem; -import com.facebook.react.fabric.mounting.mountitems.RemoveDeleteMultiMountItem; import com.facebook.react.fabric.mounting.mountitems.SendAccessibilityEvent; -import com.facebook.react.fabric.mounting.mountitems.UpdateEventEmitterMountItem; -import com.facebook.react.fabric.mounting.mountitems.UpdateLayoutMountItem; -import com.facebook.react.fabric.mounting.mountitems.UpdatePaddingMountItem; -import com.facebook.react.fabric.mounting.mountitems.UpdatePropsMountItem; -import com.facebook.react.fabric.mounting.mountitems.UpdateStateMountItem; import com.facebook.react.uimanager.StateWrapper; -import com.facebook.react.uimanager.UIManagerModule; +import com.facebook.react.uimanager.ViewManagerRegistry; import com.facebook.react.uimanager.events.BatchEventDispatchedListener; import com.facebook.react.uimanager.events.EventDispatcher; +import com.facebook.react.uimanager.events.EventDispatcherImpl; import com.facebook.systrace.Systrace; public class FabricJSIModuleProvider implements JSIModuleProvider { @@ -44,14 +36,17 @@ public class FabricJSIModuleProvider implements JSIModuleProvider { @NonNull private final ReactApplicationContext mReactApplicationContext; @NonNull private final ComponentFactory mComponentFactory; @NonNull private final ReactNativeConfig mConfig; + @NonNull private final ViewManagerRegistry mViewManagerRegistry; public FabricJSIModuleProvider( @NonNull ReactApplicationContext reactApplicationContext, @NonNull ComponentFactory componentFactory, - @NonNull ReactNativeConfig config) { + @NonNull ReactNativeConfig config, + @NonNull ViewManagerRegistry viewManagerRegistry) { mReactApplicationContext = reactApplicationContext; mComponentFactory = componentFactory; mConfig = config; + mViewManagerRegistry = viewManagerRegistry; } @Override @@ -87,15 +82,10 @@ public UIManager get() { private FabricUIManager createUIManager(@NonNull EventBeatManager eventBeatManager) { Systrace.beginSection( Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "FabricJSIModuleProvider.createUIManager"); - UIManagerModule nativeModule = - Assertions.assertNotNull(mReactApplicationContext.getNativeModule(UIManagerModule.class)); - EventDispatcher eventDispatcher = nativeModule.getEventDispatcher(); + EventDispatcher eventDispatcher = new EventDispatcherImpl(mReactApplicationContext); FabricUIManager fabricUIManager = new FabricUIManager( - mReactApplicationContext, - nativeModule.getViewManagerRegistry_DO_NOT_USE(), - eventDispatcher, - eventBeatManager); + mReactApplicationContext, mViewManagerRegistry, eventDispatcher, eventBeatManager); Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); return fabricUIManager; @@ -107,21 +97,12 @@ private static void loadClasses() { EventBeatManager.class.getClass(); EventEmitterWrapper.class.getClass(); FabricEventEmitter.class.getClass(); - BatchMountItem.class.getClass(); - CreateMountItem.class.getClass(); DispatchCommandMountItem.class.getClass(); DispatchIntCommandMountItem.class.getClass(); DispatchStringCommandMountItem.class.getClass(); - InsertMountItem.class.getClass(); MountItem.class.getClass(); PreAllocateViewMountItem.class.getClass(); - RemoveDeleteMultiMountItem.class.getClass(); SendAccessibilityEvent.class.getClass(); - UpdateEventEmitterMountItem.class.getClass(); - UpdateLayoutMountItem.class.getClass(); - UpdatePaddingMountItem.class.getClass(); - UpdatePropsMountItem.class.getClass(); - UpdateStateMountItem.class.getClass(); LayoutMetricsConversions.class.getClass(); MountingManager.class.getClass(); Binding.class.getClass(); @@ -134,5 +115,6 @@ private static void loadClasses() { StateWrapperImpl.class.getClass(); BatchEventDispatchedListener.class.getClass(); ReactNativeConfig.class.getClass(); + IntBufferBatchMountItem.class.getClass(); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index 82f743be08536f..60aca9feefb7d2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -26,7 +26,6 @@ import android.os.SystemClock; import android.view.View; import androidx.annotation.AnyThread; -import androidx.annotation.GuardedBy; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.UiThread; @@ -58,22 +57,13 @@ import com.facebook.react.fabric.events.EventEmitterWrapper; import com.facebook.react.fabric.events.FabricEventEmitter; import com.facebook.react.fabric.mounting.MountingManager; -import com.facebook.react.fabric.mounting.mountitems.BatchMountItem; -import com.facebook.react.fabric.mounting.mountitems.CreateMountItem; import com.facebook.react.fabric.mounting.mountitems.DispatchCommandMountItem; import com.facebook.react.fabric.mounting.mountitems.DispatchIntCommandMountItem; import com.facebook.react.fabric.mounting.mountitems.DispatchStringCommandMountItem; -import com.facebook.react.fabric.mounting.mountitems.InsertMountItem; import com.facebook.react.fabric.mounting.mountitems.IntBufferBatchMountItem; import com.facebook.react.fabric.mounting.mountitems.MountItem; import com.facebook.react.fabric.mounting.mountitems.PreAllocateViewMountItem; -import com.facebook.react.fabric.mounting.mountitems.RemoveDeleteMultiMountItem; import com.facebook.react.fabric.mounting.mountitems.SendAccessibilityEvent; -import com.facebook.react.fabric.mounting.mountitems.UpdateEventEmitterMountItem; -import com.facebook.react.fabric.mounting.mountitems.UpdateLayoutMountItem; -import com.facebook.react.fabric.mounting.mountitems.UpdatePaddingMountItem; -import com.facebook.react.fabric.mounting.mountitems.UpdatePropsMountItem; -import com.facebook.react.fabric.mounting.mountitems.UpdateStateMountItem; import com.facebook.react.modules.core.ReactChoreographer; import com.facebook.react.modules.i18nmanager.I18nUtil; import com.facebook.react.uimanager.PixelUtil; @@ -87,7 +77,6 @@ import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.react.views.text.TextLayoutManager; import com.facebook.systrace.Systrace; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -133,7 +122,6 @@ public class FabricUIManager implements UIManager, LifecycleEventListener { @NonNull private final CopyOnWriteArrayList mListeners = new CopyOnWriteArrayList<>(); - // Concurrent MountItem data-structures, experimental. TODO: T79662803 @NonNull private final ConcurrentLinkedQueue mViewCommandMountItemsConcurrent = new ConcurrentLinkedQueue<>(); @@ -146,24 +134,6 @@ public class FabricUIManager implements UIManager, LifecycleEventListener { private final ConcurrentLinkedQueue mPreMountItemsConcurrent = new ConcurrentLinkedQueue<>(); - // Non-concurrent MountItem data-structures - @NonNull private final Object mViewCommandMountItemsLock = new Object(); - @NonNull private final Object mMountItemsLock = new Object(); - @NonNull private final Object mPreMountItemsLock = new Object(); - - @GuardedBy("mViewCommandMountItemsLock") - @NonNull - private List mViewCommandMountItems = new ArrayList<>(); - - @GuardedBy("mMountItemsLock") - @NonNull - private List mMountItems = new ArrayList<>(); - - @GuardedBy("mPreMountItemsLock") - @NonNull - private ArrayDeque mPreMountItems = - new ArrayDeque<>(PRE_MOUNT_ITEMS_INITIAL_SIZE_ARRAY); - @ThreadConfined(UI) @NonNull private final DispatchUIFrameCallback mDispatchUIFrameCallback; @@ -373,100 +343,6 @@ private void preallocateView( isLayoutable)); } - @DoNotStrip - @SuppressWarnings("unused") - @AnyThread - @ThreadConfined(ANY) - private MountItem createMountItem( - String componentName, - @Nullable ReadableMap props, - @Nullable Object stateWrapper, - int reactRootTag, - int reactTag, - boolean isLayoutable) { - String component = getFabricComponentName(componentName); - - // This could be null if teardown/navigation away from a surface on the main thread happens - // while a commit is being processed in a different thread. By contract we expect this to be - // possible at teardown, but this race should *never* happen at startup. - @Nullable ThemedReactContext reactContext = mReactContextForRootTag.get(reactRootTag); - - return new CreateMountItem( - reactContext, - reactRootTag, - reactTag, - component, - props, - (StateWrapper) stateWrapper, - isLayoutable); - } - - @DoNotStrip - @SuppressWarnings("unused") - @AnyThread - @ThreadConfined(ANY) - private MountItem insertMountItem(int reactTag, int parentReactTag, int index) { - return new InsertMountItem(reactTag, parentReactTag, index); - } - - @DoNotStrip - @SuppressWarnings("unused") - @AnyThread - @ThreadConfined(ANY) - private MountItem removeDeleteMultiMountItem(int[] metadata) { - return new RemoveDeleteMultiMountItem(metadata); - } - - @DoNotStrip - @SuppressWarnings("unused") - @AnyThread - @ThreadConfined(ANY) - private MountItem updateLayoutMountItem( - int reactTag, int x, int y, int width, int height, int layoutDirection) { - return new UpdateLayoutMountItem(reactTag, x, y, width, height, layoutDirection); - } - - @DoNotStrip - @SuppressWarnings("unused") - @AnyThread - @ThreadConfined(ANY) - private MountItem updatePaddingMountItem(int reactTag, int left, int top, int right, int bottom) { - return new UpdatePaddingMountItem(reactTag, left, top, right, bottom); - } - - @DoNotStrip - @SuppressWarnings("unused") - @AnyThread - @ThreadConfined(ANY) - private MountItem updatePropsMountItem(int reactTag, ReadableMap map) { - return new UpdatePropsMountItem(reactTag, map); - } - - @DoNotStrip - @SuppressWarnings("unused") - @AnyThread - @ThreadConfined(ANY) - private MountItem updateStateMountItem(int reactTag, @Nullable Object stateWrapper) { - return new UpdateStateMountItem(reactTag, (StateWrapper) stateWrapper); - } - - @DoNotStrip - @SuppressWarnings("unused") - @AnyThread - @ThreadConfined(ANY) - private MountItem updateEventEmitterMountItem(int reactTag, Object eventEmitter) { - return new UpdateEventEmitterMountItem(reactTag, (EventEmitterWrapper) eventEmitter); - } - - @DoNotStrip - @SuppressWarnings("unused") - @AnyThread - @ThreadConfined(ANY) - private MountItem createBatchMountItem( - int rootTag, MountItem[] items, int size, int commitNumber) { - return new BatchMountItem(rootTag, items, size, commitNumber); - } - @DoNotStrip @SuppressWarnings("unused") @AnyThread @@ -620,7 +496,7 @@ public void synchronouslyUpdateViewOnUIThread( @Override public void execute(@NonNull MountingManager mountingManager) { try { - updatePropsMountItem(reactTag, props).execute(mountingManager); + mountingManager.updateProps(reactTag, props); } catch (Exception ex) { // TODO T42943890: Fix animations in Fabric and remove this try/catch ReactSoftException.logSoftException( @@ -685,12 +561,9 @@ private void scheduleMountItem( // When Binding.cpp calls scheduleMountItems during a commit phase, it always calls with // a BatchMountItem. No other sites call into this with a BatchMountItem, and Binding.cpp only // calls scheduleMountItems with a BatchMountItem. - boolean isClassicBatchMountItem = mountItem instanceof BatchMountItem; - boolean isIntBufferMountItem = mountItem instanceof IntBufferBatchMountItem; - boolean isBatchMountItem = isClassicBatchMountItem || isIntBufferMountItem; + boolean isBatchMountItem = mountItem instanceof IntBufferBatchMountItem; boolean shouldSchedule = - (isClassicBatchMountItem && ((BatchMountItem) mountItem).shouldSchedule()) - || (isIntBufferMountItem && ((IntBufferBatchMountItem) mountItem).shouldSchedule()) + (isBatchMountItem && ((IntBufferBatchMountItem) mountItem).shouldSchedule()) || (!isBatchMountItem && mountItem != null); // In case of sync rendering, this could be called on the UI thread. Otherwise, @@ -807,50 +680,17 @@ private List drainConcurrentItemQueue(ConcurrentLinkedQ @UiThread @ThreadConfined(UI) private List getAndResetViewCommandMountItems() { - if (ReactFeatureFlags.enableLockFreeMountInstructions) { - return drainConcurrentItemQueue(mViewCommandMountItemsConcurrent); - } - - synchronized (mViewCommandMountItemsLock) { - List result = mViewCommandMountItems; - if (result.isEmpty()) { - return null; - } - mViewCommandMountItems = new ArrayList<>(); - return result; - } + return drainConcurrentItemQueue(mViewCommandMountItemsConcurrent); } @UiThread @ThreadConfined(UI) private List getAndResetMountItems() { - if (ReactFeatureFlags.enableLockFreeMountInstructions) { - return drainConcurrentItemQueue(mMountItemsConcurrent); - } - - synchronized (mMountItemsLock) { - List result = mMountItems; - if (result.isEmpty()) { - return null; - } - mMountItems = new ArrayList<>(); - return result; - } + return drainConcurrentItemQueue(mMountItemsConcurrent); } private Collection getAndResetPreMountItems() { - if (ReactFeatureFlags.enableLockFreeMountInstructions) { - return drainConcurrentItemQueue(mPreMountItemsConcurrent); - } - - synchronized (mPreMountItemsLock) { - ArrayDeque result = mPreMountItems; - if (result.isEmpty()) { - return null; - } - mPreMountItems = new ArrayDeque<>(PRE_MOUNT_ITEMS_INITIAL_SIZE_ARRAY); - return result; - } + return drainConcurrentItemQueue(mPreMountItemsConcurrent); } /** @@ -993,16 +833,6 @@ private boolean dispatchMountItems() { } try { - // Make sure surface associated with this MountItem has been started, and not stopped. - // TODO T68118357: clean up this logic and simplify this method overall - if (mountItem instanceof BatchMountItem) { - BatchMountItem batchMountItem = (BatchMountItem) mountItem; - if (!isSurfaceActiveForExecution( - batchMountItem.getRootTag(), "dispatchMountItems BatchMountItem")) { - continue; - } - } - // Make sure surface associated with this MountItem has been started, and not stopped. // TODO T68118357: clean up this logic and simplify this method overall if (mountItem instanceof IntBufferBatchMountItem) { @@ -1051,16 +881,8 @@ private void dispatchPreMountItems(long frameTimeNanos) { break; } - PreAllocateViewMountItem preMountItemToDispatch = null; - if (ReactFeatureFlags.enableLockFreeMountInstructions) { - preMountItemToDispatch = mPreMountItemsConcurrent.poll(); - } else { - synchronized (mPreMountItemsLock) { - if (!mPreMountItems.isEmpty()) { - preMountItemToDispatch = mPreMountItems.pollFirst(); - } - } - } + PreAllocateViewMountItem preMountItemToDispatch = mPreMountItemsConcurrent.poll(); + // If list is empty, `poll` will return null, or var will never be set if (preMountItemToDispatch == null) { break; @@ -1268,13 +1090,7 @@ public Map getPerformanceCounters() { * @param mountItem */ private void addMountItem(MountItem mountItem) { - if (ReactFeatureFlags.enableLockFreeMountInstructions) { - mMountItemsConcurrent.add(mountItem); - } else { - synchronized (mMountItemsLock) { - mMountItems.add(mountItem); - } - } + mMountItemsConcurrent.add(mountItem); } /** @@ -1283,13 +1099,7 @@ private void addMountItem(MountItem mountItem) { * @param mountItem */ private void addPreAllocateMountItem(PreAllocateViewMountItem mountItem) { - if (ReactFeatureFlags.enableLockFreeMountInstructions) { - mPreMountItemsConcurrent.add(mountItem); - } else { - synchronized (mPreMountItemsLock) { - mPreMountItems.add(mountItem); - } - } + mPreMountItemsConcurrent.add(mountItem); } /** @@ -1298,13 +1108,7 @@ private void addPreAllocateMountItem(PreAllocateViewMountItem mountItem) { * @param mountItem */ private void addViewCommandMountItem(DispatchCommandMountItem mountItem) { - if (ReactFeatureFlags.enableLockFreeMountInstructions) { - mViewCommandMountItemsConcurrent.add(mountItem); - } else { - synchronized (mViewCommandMountItemsLock) { - mViewCommandMountItems.add(mountItem); - } - } + mViewCommandMountItemsConcurrent.add(mountItem); } private class DispatchUIFrameCallback extends GuardedFrameCallback { diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp index 3800b495bb5de0..41388f46f10461 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp @@ -437,9 +437,6 @@ void Binding::installFabricUIManager( // Keep reference to config object and cache some feature flags here reactNativeConfig_ = config; - useIntBufferBatchMountItem_ = reactNativeConfig_->getBool( - "react_fabric:use_int_buffer_batch_mountitem_android"); - disablePreallocateViews_ = reactNativeConfig_->getBool( "react_fabric:disabled_view_preallocation_android"); @@ -506,226 +503,7 @@ local_ref getPlatformComponentName(const ShadowView &shadowView) { return componentName; } -local_ref createUpdateEventEmitterMountItem( - const jni::global_ref &javaUIManager, - const ShadowViewMutation &mutation) { - if (!mutation.newChildShadowView.eventEmitter) { - return nullptr; - } - SharedEventEmitter eventEmitter = mutation.newChildShadowView.eventEmitter; - - // Do not hold a reference to javaEventEmitter from the C++ side. - auto javaEventEmitter = EventEmitterWrapper::newObjectJavaArgs(); - EventEmitterWrapper *cEventEmitter = cthis(javaEventEmitter); - cEventEmitter->eventEmitter = eventEmitter; - - static auto updateEventEmitterInstruction = - jni::findClassStatic(Binding::UIManagerJavaDescriptor) - ->getMethod(jint, jobject)>( - "updateEventEmitterMountItem"); - - return updateEventEmitterInstruction( - javaUIManager, mutation.newChildShadowView.tag, javaEventEmitter.get()); -} - -local_ref createUpdatePropsMountItem( - const jni::global_ref &javaUIManager, - const ShadowViewMutation &mutation) { - auto shadowView = mutation.newChildShadowView; - - // TODO: move props from map to a typed object. - auto newProps = shadowView.props->rawProps; - - local_ref readableMap = - castReadableMap(ReadableNativeMap::newObjectCxxArgs(newProps)); - static auto updatePropsInstruction = - jni::findClassStatic(Binding::UIManagerJavaDescriptor) - ->getMethod(jint, ReadableMap::javaobject)>( - "updatePropsMountItem"); - - return updatePropsInstruction( - javaUIManager, mutation.newChildShadowView.tag, readableMap.get()); -} - -local_ref createUpdateLayoutMountItem( - const jni::global_ref &javaUIManager, - const ShadowViewMutation &mutation) { - auto oldChildShadowView = mutation.oldChildShadowView; - auto newChildShadowView = mutation.newChildShadowView; - - if (newChildShadowView.layoutMetrics != EmptyLayoutMetrics && - oldChildShadowView.layoutMetrics != newChildShadowView.layoutMetrics) { - static auto updateLayoutInstruction = - jni::findClassStatic(Binding::UIManagerJavaDescriptor) - ->getMethod( - jint, jint, jint, jint, jint, jint)>("updateLayoutMountItem"); - auto layoutMetrics = newChildShadowView.layoutMetrics; - auto pointScaleFactor = layoutMetrics.pointScaleFactor; - auto frame = layoutMetrics.frame; - - int x = round(frame.origin.x * pointScaleFactor); - int y = round(frame.origin.y * pointScaleFactor); - int w = round(frame.size.width * pointScaleFactor); - int h = round(frame.size.height * pointScaleFactor); - auto layoutDirection = - toInt(newChildShadowView.layoutMetrics.layoutDirection); - return updateLayoutInstruction( - javaUIManager, newChildShadowView.tag, x, y, w, h, layoutDirection); - } - - return nullptr; -} - -local_ref createUpdatePaddingMountItem( - const jni::global_ref &javaUIManager, - const ShadowViewMutation &mutation) { - auto oldChildShadowView = mutation.oldChildShadowView; - auto newChildShadowView = mutation.newChildShadowView; - - if (oldChildShadowView.layoutMetrics.contentInsets == - newChildShadowView.layoutMetrics.contentInsets && - mutation.type != ShadowViewMutation::Type::Insert) { - return nullptr; - } - - static auto updatePaddingInstruction = - jni::findClassStatic(Binding::UIManagerJavaDescriptor) - ->getMethod(jint, jint, jint, jint, jint)>( - "updatePaddingMountItem"); - - auto layoutMetrics = newChildShadowView.layoutMetrics; - auto pointScaleFactor = layoutMetrics.pointScaleFactor; - auto contentInsets = layoutMetrics.contentInsets; - - int left = floor(contentInsets.left * pointScaleFactor); - int top = floor(contentInsets.top * pointScaleFactor); - int right = floor(contentInsets.right * pointScaleFactor); - int bottom = floor(contentInsets.bottom * pointScaleFactor); - - return updatePaddingInstruction( - javaUIManager, newChildShadowView.tag, left, top, right, bottom); -} - -local_ref createInsertMountItem( - const jni::global_ref &javaUIManager, - const ShadowViewMutation &mutation) { - static auto insertInstruction = - jni::findClassStatic(Binding::UIManagerJavaDescriptor) - ->getMethod(jint, jint, jint)>( - "insertMountItem"); - - return insertInstruction( - javaUIManager, - mutation.newChildShadowView.tag, - mutation.parentShadowView.tag, - mutation.index); -} - -local_ref createUpdateStateMountItem( - const jni::global_ref &javaUIManager, - const ShadowViewMutation &mutation) { - static auto updateStateInstruction = - jni::findClassStatic(Binding::UIManagerJavaDescriptor) - ->getMethod(jint, jobject)>( - "updateStateMountItem"); - - auto state = mutation.newChildShadowView.state; - - // Do not hold onto Java object from C - // We DO want to hold onto C object from Java, since we don't know the - // lifetime of the Java object - local_ref javaStateWrapper = nullptr; - if (state != nullptr) { - javaStateWrapper = StateWrapperImpl::newObjectJavaArgs(); - StateWrapperImpl *cStateWrapper = cthis(javaStateWrapper); - cStateWrapper->state_ = state; - } - - return updateStateInstruction( - javaUIManager, - mutation.newChildShadowView.tag, - (javaStateWrapper != nullptr ? javaStateWrapper.get() : nullptr)); -} - -local_ref createRemoveAndDeleteMultiMountItem( - const jni::global_ref &javaUIManager, - const std::vector &metadata) { - auto env = Environment::current(); - auto removeAndDeleteArray = env->NewIntArray(metadata.size() * 4); - int position = 0; - jint temp[4]; - for (const auto &x : metadata) { - temp[0] = x.tag; - temp[1] = x.parentTag; - temp[2] = x.index; - temp[3] = (x.shouldRemove ? 1 : 0) | (x.shouldDelete ? 2 : 0); - env->SetIntArrayRegion(removeAndDeleteArray, position, 4, temp); - position += 4; - } - - static auto removeDeleteMultiInstruction = - jni::findClassStatic(Binding::UIManagerJavaDescriptor) - ->getMethod(jintArray)>( - "removeDeleteMultiMountItem"); - - auto ret = removeDeleteMultiInstruction(javaUIManager, removeAndDeleteArray); - - // It is not strictly necessary to manually delete the ref here, in this - // particular case. If JNI memory is being allocated in a loop, it's easy to - // overload the localref table and crash; this is not possible in this case - // since the JNI would automatically clear this ref when it goes out of scope, - // anyway. However, this is being left here as a reminder of good hygiene and - // to be careful with JNI-allocated memory in general. - env->DeleteLocalRef(removeAndDeleteArray); - - return ret; -} - -// TODO T48019320: because we pass initial props and state to the Create (and -// preallocate) mount instruction, we technically don't need to pass the first -// Update to any components. Dedupe? -local_ref createCreateMountItem( - const jni::global_ref &javaUIManager, - const ShadowViewMutation &mutation, - const Tag surfaceId) { - static auto createJavaInstruction = - jni::findClassStatic(Binding::UIManagerJavaDescriptor) - ->getMethod( - jstring, ReadableMap::javaobject, jobject, jint, jint, jboolean)>( - "createMountItem"); - - auto newChildShadowView = mutation.newChildShadowView; - - local_ref componentName = - getPlatformComponentName(newChildShadowView); - - jboolean isLayoutable = - newChildShadowView.layoutMetrics != EmptyLayoutMetrics; - - local_ref props = castReadableMap( - ReadableNativeMap::newObjectCxxArgs(newChildShadowView.props->rawProps)); - - // Do not hold onto Java object from C - // We DO want to hold onto C object from Java, since we don't know the - // lifetime of the Java object - local_ref javaStateWrapper = nullptr; - if (newChildShadowView.state != nullptr) { - javaStateWrapper = StateWrapperImpl::newObjectJavaArgs(); - StateWrapperImpl *cStateWrapper = cthis(javaStateWrapper); - cStateWrapper->state_ = newChildShadowView.state; - } - - return createJavaInstruction( - javaUIManager, - componentName.get(), - props.get(), - (javaStateWrapper != nullptr ? javaStateWrapper.get() : nullptr), - surfaceId, - newChildShadowView.tag, - isLayoutable); -} - -void Binding::schedulerDidFinishTransactionIntBuffer( +void Binding::schedulerDidFinishTransaction( MountingCoordinator::Shared const &mountingCoordinator) { std::lock_guard lock(commitMutex_); @@ -1183,251 +961,6 @@ void Binding::schedulerDidFinishTransactionIntBuffer( env->DeleteLocalRef(intBufferArray); } -void Binding::schedulerDidFinishTransaction( - MountingCoordinator::Shared const &mountingCoordinator) { - std::lock_guard lock(commitMutex_); - - if (useIntBufferBatchMountItem_) { - return schedulerDidFinishTransactionIntBuffer(mountingCoordinator); - } - - SystraceSection s("FabricUIManagerBinding::schedulerDidFinishTransaction"); - auto finishTransactionStartTime = telemetryTimePointNow(); - - jni::global_ref localJavaUIManager = getJavaUIManager(); - if (!localJavaUIManager) { - LOG(ERROR) - << "Binding::schedulerDidFinishTransaction: JavaUIManager disappeared"; - return; - } - - auto mountingTransaction = mountingCoordinator->pullTransaction(); - - if (!mountingTransaction.has_value()) { - return; - } - - auto telemetry = mountingTransaction->getTelemetry(); - auto surfaceId = mountingTransaction->getSurfaceId(); - auto &mutations = mountingTransaction->getMutations(); - - auto revisionNumber = telemetry.getRevisionNumber(); - - std::vector> queue; - // Upper bound estimation of mount items to be delivered to Java side. - int size = mutations.size() * 3 + 42; - - local_ref> mountItemsArray = - JArrayClass::newArray(size); - - auto mountItems = *(mountItemsArray); - std::unordered_set deletedViewTags; - - // Find the set of tags that are removed and deleted in one block - std::vector toRemove; - - int position = 0; - for (const auto &mutation : mutations) { - auto oldChildShadowView = mutation.oldChildShadowView; - auto newChildShadowView = mutation.newChildShadowView; - - bool isVirtual = newChildShadowView.layoutMetrics == EmptyLayoutMetrics && - oldChildShadowView.layoutMetrics == EmptyLayoutMetrics; - - // Handle accumulated removals/deletions - if (mutation.type != ShadowViewMutation::Remove && - mutation.type != ShadowViewMutation::Delete) { - if (toRemove.size() > 0) { - mountItems[position++] = - createRemoveAndDeleteMultiMountItem(localJavaUIManager, toRemove); - toRemove.clear(); - } - } - - switch (mutation.type) { - case ShadowViewMutation::Create: { - if (disablePreallocateViews_ || - mutation.newChildShadowView.props->revision > 1 || - deletedViewTags.find(mutation.newChildShadowView.tag) != - deletedViewTags.end()) { - mountItems[position++] = - createCreateMountItem(localJavaUIManager, mutation, surfaceId); - } - break; - } - case ShadowViewMutation::Remove: { - if (!isVirtual) { - toRemove.push_back( - RemoveDeleteMetadata{mutation.oldChildShadowView.tag, - mutation.parentShadowView.tag, - mutation.index, - true, - false}); - } - break; - } - case ShadowViewMutation::Delete: { - // It is impossible to delete without removing node first - const auto &it = std::find_if( - std::begin(toRemove), - std::end(toRemove), - [&mutation](const auto &x) { - return x.tag == mutation.oldChildShadowView.tag; - }); - - if (it != std::end(toRemove)) { - it->shouldDelete = true; - } else { - toRemove.push_back(RemoveDeleteMetadata{ - mutation.oldChildShadowView.tag, -1, -1, false, true}); - } - - deletedViewTags.insert(mutation.oldChildShadowView.tag); - break; - } - case ShadowViewMutation::Update: { - if (!isVirtual) { - if (mutation.oldChildShadowView.props != - mutation.newChildShadowView.props) { - mountItems[position++] = - createUpdatePropsMountItem(localJavaUIManager, mutation); - } - if (mutation.oldChildShadowView.state != - mutation.newChildShadowView.state) { - mountItems[position++] = - createUpdateStateMountItem(localJavaUIManager, mutation); - } - - // Padding: padding mountItems must be executed before layout props - // are updated in the view. This is necessary to ensure that events - // (resulting from layout changes) are dispatched with the correct - // padding information. - auto updatePaddingMountItem = - createUpdatePaddingMountItem(localJavaUIManager, mutation); - if (updatePaddingMountItem) { - mountItems[position++] = updatePaddingMountItem; - } - - auto updateLayoutMountItem = - createUpdateLayoutMountItem(localJavaUIManager, mutation); - if (updateLayoutMountItem) { - mountItems[position++] = updateLayoutMountItem; - } - } - - if (mutation.oldChildShadowView.eventEmitter != - mutation.newChildShadowView.eventEmitter) { - auto updateEventEmitterMountItem = - createUpdateEventEmitterMountItem(localJavaUIManager, mutation); - if (updateEventEmitterMountItem) { - mountItems[position++] = updateEventEmitterMountItem; - } - } - break; - } - case ShadowViewMutation::Insert: { - if (!isVirtual) { - // Insert item - mountItems[position++] = - createInsertMountItem(localJavaUIManager, mutation); - - if (disablePreallocateViews_ || - mutation.newChildShadowView.props->revision > 1 || - deletedViewTags.find(mutation.newChildShadowView.tag) != - deletedViewTags.end()) { - mountItems[position++] = - createUpdatePropsMountItem(localJavaUIManager, mutation); - } - - // State - if (mutation.newChildShadowView.state) { - mountItems[position++] = - createUpdateStateMountItem(localJavaUIManager, mutation); - } - - // Padding: padding mountItems must be executed before layout props - // are updated in the view. This is necessary to ensure that events - // (resulting from layout changes) are dispatched with the correct - // padding information. - auto updatePaddingMountItem = - createUpdatePaddingMountItem(localJavaUIManager, mutation); - if (updatePaddingMountItem) { - mountItems[position++] = updatePaddingMountItem; - } - - // Layout - auto updateLayoutMountItem = - createUpdateLayoutMountItem(localJavaUIManager, mutation); - if (updateLayoutMountItem) { - mountItems[position++] = updateLayoutMountItem; - } - } - - // EventEmitter - auto updateEventEmitterMountItem = - createUpdateEventEmitterMountItem(localJavaUIManager, mutation); - if (updateEventEmitterMountItem) { - mountItems[position++] = updateEventEmitterMountItem; - } - - break; - } - default: { - break; - } - } - } - - // Handle remaining removals and deletions - if (toRemove.size() > 0) { - mountItems[position++] = - createRemoveAndDeleteMultiMountItem(localJavaUIManager, toRemove); - toRemove.clear(); - } - - static auto createMountItemsBatchContainer = - jni::findClassStatic(Binding::UIManagerJavaDescriptor) - ->getMethod( - jint, jtypeArray, jint, jint)>( - "createBatchMountItem"); - - // If there are no items, we pass a nullptr instead of passing the object - // through the JNI - auto batch = createMountItemsBatchContainer( - localJavaUIManager, - surfaceId, - position == 0 ? nullptr : mountItemsArray.get(), - position, - revisionNumber); - - static auto scheduleMountItem = - jni::findClassStatic(Binding::UIManagerJavaDescriptor) - ->getMethod("scheduleMountItem"); - - auto finishTransactionEndTime = telemetryTimePointNow(); - - scheduleMountItem( - localJavaUIManager, - batch.get(), - telemetry.getRevisionNumber(), - telemetryTimePointToMilliseconds(telemetry.getCommitStartTime()), - telemetryTimePointToMilliseconds(telemetry.getDiffStartTime()), - telemetryTimePointToMilliseconds(telemetry.getDiffEndTime()), - telemetryTimePointToMilliseconds(telemetry.getLayoutStartTime()), - telemetryTimePointToMilliseconds(telemetry.getLayoutEndTime()), - telemetryTimePointToMilliseconds(finishTransactionStartTime), - telemetryTimePointToMilliseconds(finishTransactionEndTime)); -} - void Binding::setPixelDensity(float pointScaleFactor) { pointScaleFactor_ = pointScaleFactor; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h index 61e2e2b783bd34..377762eb806af5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h @@ -169,14 +169,9 @@ class Binding : public jni::HybridClass, float pointScaleFactor_ = 1; std::shared_ptr reactNativeConfig_{nullptr}; - bool useIntBufferBatchMountItem_{false}; bool disablePreallocateViews_{false}; bool disableVirtualNodePreallocation_{false}; bool enableFabricLogs_{false}; - - private: - void schedulerDidFinishTransactionIntBuffer( - MountingCoordinator::Shared const &mountingCoordinator); }; } // namespace react diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java index 2ea54f35e42bb3..fe00e5d35b9dfb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java @@ -533,7 +533,7 @@ public void createView( // View Managers are responsible for dealing with initial state and props. view = viewManager.createView( - themedReactContext, propsDiffMap, stateWrapper, mJSResponderHandler); + reactTag, themedReactContext, propsDiffMap, stateWrapper, mJSResponderHandler); view.setId(reactTag); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/BatchMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/BatchMountItem.java deleted file mode 100644 index 9a7e573edd0581..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/BatchMountItem.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.fabric.mounting.mountitems; - -import androidx.annotation.NonNull; -import com.facebook.common.logging.FLog; -import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.react.bridge.ReactMarker; -import com.facebook.react.bridge.ReactMarkerConstants; -import com.facebook.react.fabric.mounting.MountingManager; -import com.facebook.systrace.Systrace; - -/** - * This class represents a batch of {@link MountItem}s - * - *

A MountItem batch contains an array of {@link MountItem} and a size. The size determines the - * amount of items that needs to be processed in the array. - * - *

The purpose of encapsulating the array of MountItems this way, is to reduce the amount of - * allocations in C++ - */ -@DoNotStrip -public class BatchMountItem implements MountItem { - static final String TAG = "FabricBatchMountItem"; - - private final int mRootTag; - @NonNull private final MountItem[] mMountItems; - - private final int mSize; - - private final int mCommitNumber; - - public BatchMountItem(int rootTag, MountItem[] items, int size, int commitNumber) { - int itemsLength = (items == null ? 0 : items.length); - if (size < 0 || size > itemsLength) { - throw new IllegalArgumentException( - "Invalid size received by parameter size: " + size + " items.size = " + itemsLength); - } - mRootTag = rootTag; - mMountItems = items; - mSize = size; - mCommitNumber = commitNumber; - } - - private void beginMarkers(String reason) { - Systrace.beginSection( - Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, - "FabricUIManager::" + reason + " - " + mSize + " items"); - - if (mCommitNumber > 0) { - ReactMarker.logFabricMarker( - ReactMarkerConstants.FABRIC_BATCH_EXECUTION_START, null, mCommitNumber); - } - } - - private void endMarkers() { - if (mCommitNumber > 0) { - ReactMarker.logFabricMarker( - ReactMarkerConstants.FABRIC_BATCH_EXECUTION_END, null, mCommitNumber); - } - - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); - } - - @Override - public void execute(@NonNull MountingManager mountingManager) { - beginMarkers("mountViews"); - - int mountItemIndex = 0; - try { - for (; mountItemIndex < mSize; mountItemIndex++) { - mMountItems[mountItemIndex].execute(mountingManager); - } - } catch (RuntimeException e) { - FLog.e( - TAG, - "Caught exception executing mountItem @" - + mountItemIndex - + ": " - + mMountItems[mountItemIndex].toString(), - e); - throw e; - } - - endMarkers(); - } - - public int getRootTag() { - return mRootTag; - } - - public boolean shouldSchedule() { - return mSize != 0; - } - - @Override - public String toString() { - StringBuilder s = new StringBuilder(); - for (int i = 0; i < mSize; i++) { - if (s.length() > 0) { - s.append("\n"); - } - s.append("BatchMountItem [S:" + mRootTag + "] (") - .append(i + 1) - .append("/") - .append(mSize) - .append("): ") - .append(mMountItems[i]); - } - return s.toString(); - } -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/CreateMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/CreateMountItem.java deleted file mode 100644 index d96bab3326e086..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/CreateMountItem.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.fabric.mounting.mountitems; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.fabric.mounting.MountingManager; -import com.facebook.react.uimanager.StateWrapper; -import com.facebook.react.uimanager.ThemedReactContext; - -public class CreateMountItem implements MountItem { - - @NonNull private final String mComponent; - private final int mRootTag; - private final int mReactTag; - @NonNull private final ThemedReactContext mContext; - private final @Nullable ReadableMap mProps; - private final @Nullable StateWrapper mStateWrapper; - private final boolean mIsLayoutable; - - public CreateMountItem( - @Nullable ThemedReactContext context, - int rootTag, - int reactTag, - @NonNull String component, - @Nullable ReadableMap props, - @NonNull StateWrapper stateWrapper, - boolean isLayoutable) { - mContext = context; - mComponent = component; - mRootTag = rootTag; - mReactTag = reactTag; - mProps = props; - mStateWrapper = stateWrapper; - mIsLayoutable = isLayoutable; - } - - @Override - public void execute(@NonNull MountingManager mountingManager) { - if (mContext == null) { - throw new IllegalStateException( - "Cannot execute PreAllocateViewMountItem without Context for ReactTag: " - + mReactTag - + " and rootTag: " - + mRootTag); - } - mountingManager.createView( - mContext, mComponent, mReactTag, mProps, mStateWrapper, mIsLayoutable); - } - - @Override - public String toString() { - return "CreateMountItem [" - + mReactTag - + "] - component: " - + mComponent - + " - rootTag: " - + mRootTag - + " - isLayoutable: " - + mIsLayoutable; - } -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/InsertMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/InsertMountItem.java deleted file mode 100644 index edfc46ac7109cf..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/InsertMountItem.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.fabric.mounting.mountitems; - -import androidx.annotation.NonNull; -import com.facebook.react.fabric.mounting.MountingManager; - -public class InsertMountItem implements MountItem { - - private int mReactTag; - private int mParentReactTag; - private int mIndex; - - public InsertMountItem(int reactTag, int parentReactTag, int index) { - mReactTag = reactTag; - mParentReactTag = parentReactTag; - mIndex = index; - } - - @Override - public void execute(@NonNull MountingManager mountingManager) { - mountingManager.addViewAt(mParentReactTag, mReactTag, mIndex); - } - - public int getParentReactTag() { - return mParentReactTag; - } - - public int getIndex() { - return mIndex; - } - - @Override - public String toString() { - return "InsertMountItem [" - + mReactTag - + "] - parentTag: [" - + mParentReactTag - + "] - index: " - + mIndex; - } -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/RemoveDeleteMultiMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/RemoveDeleteMultiMountItem.java deleted file mode 100644 index daf3ed5ca75d5e..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/RemoveDeleteMultiMountItem.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.fabric.mounting.mountitems; - -import androidx.annotation.NonNull; -import com.facebook.react.fabric.mounting.MountingManager; - -public class RemoveDeleteMultiMountItem implements MountItem { - - // Metadata is an array of ints, grouped into 4 ints per instruction (so the length of metadata - // is always divisible by 4): - // - // `instruction*4 + 0`: react tag of view instruction - // `instruction*4 + 1`: react tag of view's parent - // `instruction*4 + 2`: index of view in parents' children instruction - // `instruction*4 + 3`: flags indicating if the view should be removed, and/or deleted - @NonNull private int[] mMetadata; - - // Bitfields of "flag", indicating if a view should be removed and/or deleted - private static final int REMOVE_FLAG = 1; - private static final int DELETE_FLAG = 2; - - // Indices for each parameter within an "instruction" - private static final int INSTRUCTION_FIELDS_LEN = 4; - private static final int TAG_INDEX = 0; - private static final int PARENT_TAG_INDEX = 1; - private static final int VIEW_INDEX_INDEX = 2; - private static final int FLAGS_INDEX = 3; - - public RemoveDeleteMultiMountItem(@NonNull int[] metadata) { - mMetadata = metadata; - } - - @Override - public void execute(@NonNull MountingManager mountingManager) { - // First, go through instructions and remove all views that are marked - // for removal. - // Not all views that are removed are deleted, and not all deleted views - // are removed first. - // *All* views must be removed here before we can delete any views. - // Removal of a view from a parent is based on indices within the parents' children, - // and deletion causes reordering; so we must perform all removals first. - for (int i = 0; i < mMetadata.length; i += INSTRUCTION_FIELDS_LEN) { - int flags = mMetadata[i + FLAGS_INDEX]; - if ((flags & REMOVE_FLAG) != 0) { - int parentTag = mMetadata[i + PARENT_TAG_INDEX]; - int tag = mMetadata[i + TAG_INDEX]; - int index = mMetadata[i + VIEW_INDEX_INDEX]; - mountingManager.removeViewAt(tag, parentTag, index); - } - } - - // After removing all views, delete all views marked for deletion. - for (int i = 0; i < mMetadata.length; i += 4) { - int flags = mMetadata[i + FLAGS_INDEX]; - if ((flags & DELETE_FLAG) != 0) { - int tag = mMetadata[i + TAG_INDEX]; - mountingManager.deleteView(tag); - } - } - } - - @Override - public String toString() { - StringBuilder s = new StringBuilder(); - for (int i = 0; i < mMetadata.length; i += 4) { - if (s.length() > 0) { - s.append("\n"); - } - s.append("RemoveDeleteMultiMountItem (") - .append(i / INSTRUCTION_FIELDS_LEN + 1) - .append("/") - .append(mMetadata.length / INSTRUCTION_FIELDS_LEN) - .append("): [") - .append(mMetadata[i + TAG_INDEX]) - .append("] parent [") - .append(mMetadata[i + PARENT_TAG_INDEX]) - .append("] idx ") - .append(mMetadata[i + VIEW_INDEX_INDEX]) - .append(" ") - .append(mMetadata[i + FLAGS_INDEX]); - } - return s.toString(); - } -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateEventEmitterMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateEventEmitterMountItem.java deleted file mode 100644 index 72331c6b963484..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateEventEmitterMountItem.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.fabric.mounting.mountitems; - -import androidx.annotation.NonNull; -import com.facebook.react.fabric.events.EventEmitterWrapper; -import com.facebook.react.fabric.mounting.MountingManager; - -public class UpdateEventEmitterMountItem implements MountItem { - - @NonNull private final EventEmitterWrapper mEventHandler; - private final int mReactTag; - - public UpdateEventEmitterMountItem(int reactTag, @NonNull EventEmitterWrapper EventHandler) { - mReactTag = reactTag; - mEventHandler = EventHandler; - } - - @Override - public void execute(@NonNull MountingManager mountingManager) { - mountingManager.updateEventEmitter(mReactTag, mEventHandler); - } - - @Override - public String toString() { - return "UpdateEventEmitterMountItem [" + mReactTag + "]"; - } -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateLayoutMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateLayoutMountItem.java deleted file mode 100644 index cd8edd887e205b..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateLayoutMountItem.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.fabric.mounting.mountitems; - -import android.annotation.TargetApi; -import android.os.Build; -import android.util.LayoutDirection; -import androidx.annotation.NonNull; -import com.facebook.react.fabric.mounting.MountingManager; - -public class UpdateLayoutMountItem implements MountItem { - - private final int mReactTag; - private final int mX; - private final int mY; - private final int mWidth; - private final int mHeight; - private final int mLayoutDirection; - - public UpdateLayoutMountItem( - int reactTag, int x, int y, int width, int height, int layoutDirection) { - mReactTag = reactTag; - mX = x; - mY = y; - mWidth = width; - mHeight = height; - mLayoutDirection = convertLayoutDirection(layoutDirection); - } - - // TODO move this from here - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - private static int convertLayoutDirection(int layoutDirection) { - switch (layoutDirection) { - case 0: - return LayoutDirection.INHERIT; - case 1: - return LayoutDirection.LTR; - case 2: - return LayoutDirection.RTL; - default: - throw new IllegalArgumentException("Unsupported layout direction: " + layoutDirection); - } - } - - @Override - public void execute(@NonNull MountingManager mountingManager) { - mountingManager.updateLayout(mReactTag, mX, mY, mWidth, mHeight); - } - - public int getX() { - return mX; - } - - public int getY() { - return mY; - } - - public int getHeight() { - return mHeight; - } - - public int getWidth() { - return mWidth; - } - - public int getLayoutDirection() { - return mLayoutDirection; - } - - @Override - public String toString() { - return "UpdateLayoutMountItem [" - + mReactTag - + "] - x: " - + mX - + " - y: " - + mY - + " - height: " - + mHeight - + " - width: " - + mWidth - + " - layoutDirection: " - + +mLayoutDirection; - } -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdatePaddingMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdatePaddingMountItem.java deleted file mode 100644 index e0403627bbd99d..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdatePaddingMountItem.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.fabric.mounting.mountitems; - -import androidx.annotation.NonNull; -import com.facebook.react.fabric.mounting.MountingManager; - -/** - * A MountItem that represents setting the padding properties of a view (left, top, right, bottom). - * This is distinct from layout because it happens far less frequently from layout; so it is a perf - * optimization to transfer this data and execute the methods strictly less than the layout-related - * properties. - */ -public class UpdatePaddingMountItem implements MountItem { - - private final int mReactTag; - private final int mLeft; - private final int mTop; - private final int mRight; - private final int mBottom; - - public UpdatePaddingMountItem(int reactTag, int left, int top, int right, int bottom) { - mReactTag = reactTag; - mLeft = left; - mTop = top; - mRight = right; - mBottom = bottom; - } - - @Override - public void execute(@NonNull MountingManager mountingManager) { - mountingManager.updatePadding(mReactTag, mLeft, mTop, mRight, mBottom); - } - - @Override - public String toString() { - return "UpdatePaddingMountItem [" - + mReactTag - + "] - left: " - + mLeft - + " - top: " - + mTop - + " - right: " - + mRight - + " - bottom: " - + mBottom; - } -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdatePropsMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdatePropsMountItem.java deleted file mode 100644 index 8b980705e9dc84..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdatePropsMountItem.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.fabric.mounting.mountitems; - -import static com.facebook.react.fabric.FabricUIManager.IS_DEVELOPMENT_ENVIRONMENT; - -import androidx.annotation.NonNull; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.fabric.mounting.MountingManager; - -public class UpdatePropsMountItem implements MountItem { - - private final int mReactTag; - @NonNull private final ReadableMap mUpdatedProps; - - public UpdatePropsMountItem(int reactTag, @NonNull ReadableMap updatedProps) { - mReactTag = reactTag; - mUpdatedProps = updatedProps; - } - - @Override - public void execute(@NonNull MountingManager mountingManager) { - mountingManager.updateProps(mReactTag, mUpdatedProps); - } - - @Override - public String toString() { - StringBuilder result = - new StringBuilder("UpdatePropsMountItem [").append(mReactTag).append("]"); - - if (IS_DEVELOPMENT_ENVIRONMENT) { - result.append(" props: ").append(mUpdatedProps); - } - - return result.toString(); - } -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateStateMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateStateMountItem.java deleted file mode 100644 index 4544e8f935e23e..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateStateMountItem.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.fabric.mounting.mountitems; - -import static com.facebook.react.fabric.FabricUIManager.IS_DEVELOPMENT_ENVIRONMENT; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import com.facebook.react.fabric.mounting.MountingManager; -import com.facebook.react.uimanager.StateWrapper; - -public class UpdateStateMountItem implements MountItem { - - private final int mReactTag; - @Nullable private final StateWrapper mStateWrapper; - - public UpdateStateMountItem(int reactTag, @Nullable StateWrapper stateWrapper) { - mReactTag = reactTag; - mStateWrapper = stateWrapper; - } - - @Override - public void execute(@NonNull MountingManager mountingManager) { - mountingManager.updateState(mReactTag, mStateWrapper); - } - - @Override - public String toString() { - StringBuilder result = - new StringBuilder("UpdateStateMountItem [").append(mReactTag).append("]"); - - if (IS_DEVELOPMENT_ENVIRONMENT) { - result.append(" state: ").append(mStateWrapper != null ? mStateWrapper.getState() : ""); - } - - return result.toString(); - } -} 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 ff1147ad3fe09b..26dc859215cdb7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/NativeViewHierarchyManager.java @@ -278,7 +278,7 @@ public synchronized void createView( try { ViewManager viewManager = mViewManagers.get(className); - View view = viewManager.createView(themedContext, null, null, mJSResponderHandler); + View view = viewManager.createView(tag, themedContext, null, null, mJSResponderHandler); mTagsToViews.put(tag, view); mTagsToViewManagers.put(tag, viewManager); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java index 22b82bed0ca1d5..f371e341f17d8a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java @@ -246,6 +246,15 @@ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCo } } } + + // Expose the testID prop as the resource-id name of the view. Black-box E2E/UI testing + // frameworks, which interact with the UI through the accessibility framework, do not have + // access to view tags. This allows developers/testers to avoid polluting the + // content-description with test identifiers. + final String testId = (String) host.getTag(R.id.react_test_id); + if (testId != null) { + info.setViewIdResourceName(testId); + } } @Override @@ -425,7 +434,8 @@ public static void setDelegate(final View view) { if (!ViewCompat.hasAccessibilityDelegate(view) && (view.getTag(R.id.accessibility_role) != null || view.getTag(R.id.accessibility_state) != null - || view.getTag(R.id.accessibility_actions) != null)) { + || view.getTag(R.id.accessibility_actions) != null + || view.getTag(R.id.react_test_id) != null)) { ViewCompat.setAccessibilityDelegate(view, new ReactAccessibilityDelegate()); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java index 5401620f715751..cf1be7c7ce0b62 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewManager.java @@ -67,19 +67,14 @@ protected ViewManagerDelegate getDelegate() { return null; } - /** Creates a view and installs event emitters on it. */ - private final @NonNull T createView( - @NonNull ThemedReactContext reactContext, JSResponderHandler jsResponderHandler) { - return createView(reactContext, null, null, jsResponderHandler); - } - /** Creates a view with knowledge of props and state. */ public @NonNull T createView( + int reactTag, @NonNull ThemedReactContext reactContext, @Nullable ReactStylesDiffMap props, @Nullable StateWrapper stateWrapper, JSResponderHandler jsResponderHandler) { - T view = createViewInstance(reactContext, props, stateWrapper); + T view = createViewInstance(reactTag, reactContext, props, stateWrapper); if (view instanceof ReactInterceptingViewGroup) { ((ReactInterceptingViewGroup) view).setOnInterceptTouchEventListener(jsResponderHandler); } @@ -129,13 +124,18 @@ public C createShadowNodeInstance() { * that will call createViewInstance for you. Override it if you need props upon creation of the * view. * - * @param reactContext + * @param reactTag reactTag that should be set as ID of the view instance + * @param reactContext ReactContext used to initialize view instance + * @param initialProps initial props for the view instance + * @param stateWrapper initial state for the view instance */ protected @NonNull T createViewInstance( + int reactTag, @NonNull ThemedReactContext reactContext, @Nullable ReactStylesDiffMap initialProps, @Nullable StateWrapper stateWrapper) { T view = createViewInstance(reactContext); + view.setId(reactTag); addEventEmitters(reactContext, view); if (initialProps != null) { updateProperties(view, initialProps); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditTextInputConnectionWrapper.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditTextInputConnectionWrapper.java index 47b4391c327f11..c5a29b92615b97 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditTextInputConnectionWrapper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditTextInputConnectionWrapper.java @@ -132,10 +132,13 @@ public boolean deleteSurroundingText(int beforeLength, int afterLength) { @Override public boolean sendKeyEvent(KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN) { + boolean isNumberKey = event.getUnicodeChar() < 58 && event.getUnicodeChar() > 47; if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) { dispatchKeyEvent(BACKSPACE_KEY_VALUE); } else if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) { dispatchKeyEvent(ENTER_KEY_VALUE); + } else if (isNumberKey) { + dispatchKeyEvent(String.valueOf(event.getNumber())); } } return super.sendKeyEvent(event); diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/SimpleViewPropertyTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/SimpleViewPropertyTest.java index ed1d23990e437b..91be74945d9c9b 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/SimpleViewPropertyTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/SimpleViewPropertyTest.java @@ -36,6 +36,8 @@ public class SimpleViewPropertyTest { @Rule public PowerMockRule rule = new PowerMockRule(); + private static int sViewTag = 2; + private static class ConcreteViewManager extends SimpleViewManager { @ReactProp(name = "foo") @@ -75,7 +77,9 @@ public ReactStylesDiffMap buildStyles(Object... keysAndValues) { @Test public void testOpacity() { - View view = mManager.createView(mThemedContext, buildStyles(), null, new JSResponderHandler()); + View view = + mManager.createView( + sViewTag, mThemedContext, buildStyles(), null, new JSResponderHandler()); mManager.updateProperties(view, buildStyles()); assertThat(view.getAlpha()).isEqualTo(1.0f); @@ -89,7 +93,9 @@ public void testOpacity() { @Test public void testBackgroundColor() { - View view = mManager.createView(mThemedContext, buildStyles(), null, new JSResponderHandler()); + View view = + mManager.createView( + sViewTag, mThemedContext, buildStyles(), null, new JSResponderHandler()); mManager.updateProperties(view, buildStyles()); assertThat(view.getBackground()).isEqualTo(null); diff --git a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java index b892f527c0e4a9..e8eec3ae80b7a3 100644 --- a/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java +++ b/packages/rn-tester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java @@ -34,6 +34,7 @@ import com.facebook.react.module.model.ReactModuleInfoProvider; import com.facebook.react.shell.MainReactPackage; import com.facebook.react.turbomodule.core.TurboModuleManager; +import com.facebook.react.uimanager.ViewManagerRegistry; import com.facebook.react.views.text.ReactFontManager; import com.facebook.soloader.SoLoader; import java.lang.reflect.InvocationTargetException; @@ -168,6 +169,13 @@ public JSIModuleType getJSIModuleType() { public JSIModuleProvider getJSIModuleProvider() { final ComponentFactory ComponentFactory = new ComponentFactory(); CoreComponentsRegistry.register(ComponentFactory); + final ReactInstanceManager reactInstanceManager = getReactInstanceManager(); + + ViewManagerRegistry viewManagerRegistry = + new ViewManagerRegistry( + reactInstanceManager.getOrCreateViewManagers( + reactApplicationContext)); + return new FabricJSIModuleProvider( reactApplicationContext, ComponentFactory, @@ -192,7 +200,8 @@ public String getString(final String s) { public double getDouble(final String s) { return 0; } - }); + }, + viewManagerRegistry); } }); } diff --git a/scripts/publish-npm.js b/scripts/publish-npm.js index 6107a9efd2a1a6..954eaaf7c77a12 100644 --- a/scripts/publish-npm.js +++ b/scripts/publish-npm.js @@ -137,7 +137,7 @@ exec('git checkout ReactAndroid/gradle.properties'); echo('Generated artifacts for Maven'); -let artifacts = ['-javadoc.jar', '-sources.jar', '.aar', '.pom'].map(suffix => { +let artifacts = ['.aar', '.pom'].map(suffix => { return `react-native-${releaseVersion}${suffix}`; });