diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 56b7c520ffd6..6a47338f5db2 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -3052,7 +3052,6 @@ public final class com/facebook/react/runtime/ReactSurfaceView : com/facebook/re public fun (Landroid/content/Context;Lcom/facebook/react/runtime/ReactSurfaceImpl;)V public fun getCurrentReactContext ()Lcom/facebook/react/bridge/ReactContext; public fun getJSModuleName ()Ljava/lang/String; - public fun getUIManagerType ()I public fun handleException (Ljava/lang/Throwable;)V public fun hasActiveReactContext ()Z public fun hasActiveReactInstance ()Z @@ -3061,7 +3060,6 @@ public final class com/facebook/react/runtime/ReactSurfaceView : com/facebook/re public fun onChildStartedNativeGesture (Landroid/view/View;Landroid/view/MotionEvent;)V public fun requestChildFocus (Landroid/view/View;Landroid/view/View;)V public fun requestDisallowInterceptTouchEvent (Z)V - public fun setIsFabric (Z)V } public abstract class com/facebook/react/runtime/cxxreactpackage/CxxReactPackage { @@ -5506,7 +5504,6 @@ public final class com/facebook/react/views/scroll/ReactHorizontalScrollContaine public static final field Companion Lcom/facebook/react/views/scroll/ReactHorizontalScrollContainerViewManager$Companion; public static final field REACT_CLASS Ljava/lang/String; public fun ()V - public synthetic fun createViewInstance (ILcom/facebook/react/uimanager/ThemedReactContext;Lcom/facebook/react/uimanager/ReactStylesDiffMap;Lcom/facebook/react/uimanager/StateWrapper;)Landroid/view/View; public synthetic fun createViewInstance (Lcom/facebook/react/uimanager/ThemedReactContext;)Landroid/view/View; public fun createViewInstance (Lcom/facebook/react/uimanager/ThemedReactContext;)Lcom/facebook/react/views/view/ReactViewGroup; public fun getName ()Ljava/lang/String; diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index d63222a56ddc..39407697687f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -77,7 +77,6 @@ import com.facebook.react.internal.ChoreographerProvider; import com.facebook.react.internal.featureflags.ReactNativeNewArchitectureFeatureFlags; import com.facebook.react.modules.appearance.AppearanceModule; -import com.facebook.react.modules.appregistry.AppRegistry; import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; import com.facebook.react.modules.core.DeviceEventManagerModule; import com.facebook.react.modules.core.ReactChoreographer; @@ -767,10 +766,7 @@ public void destroy() { synchronized (mReactContextLock) { if (mCurrentReactContext != null) { for (ReactRoot reactRoot : mAttachedReactRoots) { - // Fabric surfaces must be cleaned up when React Native is destroyed. - if (reactRoot.getUIManagerType() == UIManagerType.FABRIC) { - detachRootViewFromInstance(reactRoot, mCurrentReactContext); - } + detachRootViewFromInstance(reactRoot, mCurrentReactContext); } mCurrentReactContext.destroy(); @@ -1271,9 +1267,7 @@ private void attachRootViewToInstance(final ReactRoot reactRoot) { Systrace.beginSection(TRACE_TAG_REACT, "attachRootViewToInstance"); - @Nullable - UIManager uiManager = - UIManagerHelper.getUIManager(mCurrentReactContext, reactRoot.getUIManagerType()); + @Nullable UIManager uiManager = UIManagerHelper.getUIManager(mCurrentReactContext, FABRIC); // If we can't get a UIManager something has probably gone horribly wrong if (uiManager == null) { @@ -1284,28 +1278,16 @@ private void attachRootViewToInstance(final ReactRoot reactRoot) { @Nullable Bundle initialProperties = reactRoot.getAppProperties(); - final int rootTag; - if (reactRoot.getUIManagerType() == FABRIC) { - rootTag = - uiManager.startSurface( - reactRoot.getRootViewGroup(), - reactRoot.getJSModuleName(), - initialProperties == null - ? new WritableNativeMap() - : Arguments.fromBundle(initialProperties), - reactRoot.getWidthMeasureSpec(), - reactRoot.getHeightMeasureSpec()); - reactRoot.setShouldLogContentAppeared(true); - } else { - rootTag = - uiManager.addRootView( - reactRoot.getRootViewGroup(), - initialProperties == null - ? new WritableNativeMap() - : Arguments.fromBundle(initialProperties)); - reactRoot.setRootViewTag(rootTag); - reactRoot.runApplication(); - } + final int rootTag = + uiManager.startSurface( + reactRoot.getRootViewGroup(), + reactRoot.getJSModuleName(), + initialProperties == null + ? new WritableNativeMap() + : Arguments.fromBundle(initialProperties), + reactRoot.getWidthMeasureSpec(), + reactRoot.getHeightMeasureSpec()); + reactRoot.setShouldLogContentAppeared(true); Systrace.beginAsyncSection(TRACE_TAG_REACT, "pre_rootView.onAttachedToReactInstance", rootTag); UiThreadUtil.runOnUiThread( @@ -1326,36 +1308,29 @@ private void detachRootViewFromInstance(ReactRoot reactRoot, ReactContext reactC return; } - @UIManagerType int uiManagerType = reactRoot.getUIManagerType(); - if (uiManagerType == UIManagerType.FABRIC) { - // Stop surface in Fabric. - // Calling FabricUIManager.stopSurface causes the C++ Binding.stopSurface - // to be called synchronously over the JNI, which causes an empty tree - // to be committed via the Scheduler, which will cause mounting instructions - // to be queued up and synchronously executed to delete and remove - // all the views in the hierarchy. - final int surfaceId = reactRoot.getRootViewTag(); - if (surfaceId != View.NO_ID) { - UIManager uiManager = UIManagerHelper.getUIManager(reactContext, uiManagerType); - if (uiManager != null) { - uiManager.stopSurface(surfaceId); - } else { - FLog.w(ReactConstants.TAG, "Failed to stop surface, UIManager has already gone away"); - } + @UIManagerType int uiManagerType = FABRIC; + // Stop surface in Fabric. + // Calling FabricUIManager.stopSurface causes the C++ Binding.stopSurface + // to be called synchronously over the JNI, which causes an empty tree + // to be committed via the Scheduler, which will cause mounting instructions + // to be queued up and synchronously executed to delete and remove + // all the views in the hierarchy. + final int surfaceId = reactRoot.getRootViewTag(); + if (surfaceId != View.NO_ID) { + UIManager uiManager = UIManagerHelper.getUIManager(reactContext, uiManagerType); + if (uiManager != null) { + uiManager.stopSurface(surfaceId); } else { - ReactSoftExceptionLogger.logSoftException( - TAG, - new RuntimeException( - "detachRootViewFromInstance called with ReactRootView with invalid id")); + FLog.w(ReactConstants.TAG, "Failed to stop surface, UIManager has already gone away"); } - - clearReactRoot(reactRoot); } else { - reactContext - .getCatalystInstance() - .getJSModule(AppRegistry.class) - .unmountApplicationComponentAtRootTag(reactRoot.getRootViewTag()); + ReactSoftExceptionLogger.logSoftException( + TAG, + new RuntimeException( + "detachRootViewFromInstance called with ReactRootView with invalid id")); } + + clearReactRoot(reactRoot); } @ThreadConfined(UI) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index 907ad9624bd1..f7eb6add6982 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -10,7 +10,6 @@ import static com.facebook.infer.annotation.ThreadConfined.UI; import static com.facebook.react.uimanager.BlendModeHelper.needsIsolatedLayer; import static com.facebook.react.uimanager.common.UIManagerType.FABRIC; -import static com.facebook.react.uimanager.common.UIManagerType.LEGACY; import static com.facebook.systrace.Systrace.TRACE_TAG_REACT; import android.annotation.SuppressLint; @@ -52,6 +51,7 @@ import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableNativeMap; import com.facebook.react.common.annotations.VisibleForTesting; +import com.facebook.react.common.annotations.internal.LegacyArchitecture; import com.facebook.react.config.ReactFeatureFlags; import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags; import com.facebook.react.modules.appregistry.AppRegistry; @@ -70,7 +70,6 @@ import com.facebook.react.uimanager.RootViewUtil; import com.facebook.react.uimanager.UIManagerHelper; import com.facebook.react.uimanager.common.UIManagerType; -import com.facebook.react.uimanager.common.ViewUtil; import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.systrace.Systrace; import java.util.concurrent.atomic.AtomicInteger; @@ -117,7 +116,6 @@ public interface ReactRootViewEventListener { private int mLastHeight = 0; private int mLastOffsetX = Integer.MIN_VALUE; private int mLastOffsetY = Integer.MIN_VALUE; - private @UIManagerType int mUIManagerType = LEGACY; private final AtomicInteger mState = new AtomicInteger(STATE_STOPPED); public ReactRootView(Context context) { @@ -308,9 +306,7 @@ protected void dispatchDraw(Canvas canvas) { protected boolean drawChild(Canvas canvas, View child, long drawingTime) { BlendMode mixBlendMode = null; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q - && ViewUtil.getUIManagerType(this) == UIManagerType.FABRIC - && needsIsolatedLayer(this)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && needsIsolatedLayer(this)) { mixBlendMode = (BlendMode) child.getTag(R.id.mix_blend_mode); if (mixBlendMode != null) { Paint p = new Paint(); @@ -475,7 +471,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto } private boolean isFabric() { - return getUIManagerType() == FABRIC; + return true; } @Override @@ -647,9 +643,7 @@ private void updateRootLayoutSpecs( final ReactContext reactApplicationContext = getCurrentReactContext(); if (reactApplicationContext != null) { - @Nullable - UIManager uiManager = - UIManagerHelper.getUIManager(reactApplicationContext, getUIManagerType()); + @Nullable UIManager uiManager = UIManagerHelper.getUIManager(reactApplicationContext, FABRIC); // Ignore calling updateRootLayoutSpecs if UIManager is not properly initialized. if (uiManager != null) { // In Fabric only, get position of view within screen @@ -892,15 +886,18 @@ public void handleException(final Throwable t) { getCurrentReactContext().handleException(e); } + @LegacyArchitecture + @Deprecated public void setIsFabric(boolean isFabric) { - mUIManagerType = isFabric ? FABRIC : LEGACY; + /* noop */ } @Override public @UIManagerType int getUIManagerType() { - return mUIManagerType; + return FABRIC; } + @LegacyArchitecture @Nullable public ReactInstanceManager getReactInstanceManager() { return mReactInstanceManager; diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.kt index 1029e9519dc6..5f4a4a1898c6 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.kt @@ -23,14 +23,11 @@ import com.facebook.react.bridge.UIManagerListener import com.facebook.react.bridge.buildReadableMap import com.facebook.react.common.annotations.UnstableReactNativeAPI import com.facebook.react.common.annotations.VisibleForTesting -import com.facebook.react.common.build.ReactBuildConfig import com.facebook.react.module.annotations.ReactModule import com.facebook.react.modules.core.ReactChoreographer import com.facebook.react.uimanager.GuardedFrameCallback -import com.facebook.react.uimanager.UIBlock import com.facebook.react.uimanager.UIManagerHelper import com.facebook.react.uimanager.common.UIManagerType -import com.facebook.react.uimanager.common.ViewUtil import java.util.ArrayList import java.util.Queue import java.util.concurrent.ConcurrentLinkedQueue @@ -207,11 +204,6 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) : @Volatile private var currentBatchNumber: Long = 0 private var initializedForFabric = false - private var initializedForNonFabric = false - - @UIManagerType private var uiManagerType = UIManagerType.LEGACY - private var numFabricAnimations = 0 - private var numNonFabricAnimations = 0 /** * This method is used to notify the JS side that the user has stopped scrolling. With natively @@ -285,10 +277,6 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) : // For FabricUIManager only @UiThread override fun didDispatchMountItems(uiManager: UIManager) { - if (uiManagerType != UIManagerType.FABRIC) { - return - } - var batchNumber = currentBatchNumber - 1 // TODO T71377544: delete this when the JS method is confirmed safe @@ -313,33 +301,10 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) : operations.executeBatch(batchNumber, nodesManager) } - // For non-FabricUIManager only - @Suppress("DEPRECATION") + // For non-FabricUIManager only (no-op since Fabric is the only supported UIManager) @UiThread override fun willDispatchViewUpdates(uiManager: UIManager) { - if (operations.isEmpty && preOperations.isEmpty) { - return - } - if ( - uiManagerType == UIManagerType.FABRIC || - ReactBuildConfig.UNSTABLE_ENABLE_MINIFY_LEGACY_ARCHITECTURE - ) { - return - } - - // The following code ONLY executes for non-fabric - // When ReactBuildConfig.UNSTABLE_ENABLE_MINIFY_LEGACY_ARCHITECTURE is true, the folowing code - // might be stripped out. - val frameNo = currentBatchNumber++ - - val preOperationsUIBlock = UIBlock { preOperations.executeBatch(frameNo, nodesManager) } - - val operationsUIBlock = UIBlock { operations.executeBatch(frameNo, nodesManager) } - - assert(uiManager is com.facebook.react.uimanager.UIManagerModule) - val uiManagerModule = uiManager as com.facebook.react.uimanager.UIManagerModule - uiManagerModule.prependUIBlock(preOperationsUIBlock) - uiManagerModule.addUIBlock(operationsUIBlock) + // No-op: Fabric is the only supported UIManager } override fun onHostPause() { @@ -411,23 +376,15 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) : } /** - * Given a viewTag, detect if we're running in Fabric or non-Fabric and attach an event listener - * to the correct UIManager, if necessary. This is expected to only be called from the native - * module thread, and not concurrently. + * Given a viewTag, attach an event listener to the Fabric UIManager if necessary. This is + * expected to only be called from the native module thread, and not concurrently. * * @param viewTag */ private fun initializeLifecycleEventListenersForViewTag(viewTag: Int) { - uiManagerType = ViewUtil.getUIManagerType(viewTag) - if (uiManagerType == UIManagerType.FABRIC) { - numFabricAnimations++ - } else { - numNonFabricAnimations++ - } - val nodesManager = this.nodesManager if (nodesManager != null) { - nodesManager.initializeEventListenerForUIManagerType(uiManagerType) + nodesManager.initializeEventListenerForUIManagerType(UIManagerType.FABRIC) } else { ReactSoftExceptionLogger.logSoftException( NAME, @@ -437,62 +394,21 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) : ) } - // Subscribe to UIManager (Fabric or non-Fabric) lifecycle events if we haven't yet - val initialized = - if (uiManagerType == UIManagerType.FABRIC) initializedForFabric else initializedForNonFabric - if (initialized) { + // Subscribe to Fabric UIManager lifecycle events if we haven't yet + if (initializedForFabric) { return } val reactApplicationContext = reactApplicationContextIfActiveOrWarn if (reactApplicationContext != null) { - val uiManager = UIManagerHelper.getUIManager(reactApplicationContext, uiManagerType) + val uiManager = UIManagerHelper.getUIManager(reactApplicationContext, UIManagerType.FABRIC) if (uiManager != null) { uiManager.addUIManagerEventListener(this) - if (uiManagerType == UIManagerType.FABRIC) { - initializedForFabric = true - } else { - initializedForNonFabric = true - } + initializedForFabric = true } } } - /** - * Given a viewTag and the knowledge that a "disconnect" or "stop"-type imperative command is - * being executed, decrement the number of inflight animations and possibly switch UIManager - * modes. - * - * @param viewTag - */ - private fun decrementInFlightAnimationsForViewTag(viewTag: Int) { - @UIManagerType val animationManagerType = ViewUtil.getUIManagerType(viewTag) - if (animationManagerType == UIManagerType.FABRIC) { - numFabricAnimations-- - } else { - numNonFabricAnimations-- - } - - // Should we switch to a different animation mode? - // This can be useful when navigating between Fabric and non-Fabric screens: - // If there are ongoing Fabric animations from a previous screen, - // and we tear down the current non-Fabric screen, we should expect - // the animation mode to switch back - and vice-versa. - if ( - numNonFabricAnimations == 0 && - numFabricAnimations > 0 && - uiManagerType != UIManagerType.FABRIC - ) { - uiManagerType = UIManagerType.FABRIC - } else if ( - numFabricAnimations == 0 && - numNonFabricAnimations > 0 && - uiManagerType != UIManagerType.LEGACY - ) { - uiManagerType = UIManagerType.LEGACY - } - } - override fun startOperationBatch() { batchingControlledByJS = true currentBatchNumber++ @@ -804,8 +720,6 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) : FLog.d(NAME, "queue disconnectAnimatedNodeFromView: $animatedNodeTag viewTag: $viewTag") } - decrementInFlightAnimationsForViewTag(viewTag) - addOperation( object : UIThreadOperation() { override fun execute(animatedNodesManager: NativeAnimatedNodesManager) { @@ -883,8 +797,6 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) : ) } - decrementInFlightAnimationsForViewTag(viewTag) - addOperation( object : UIThreadOperation() { override fun execute(animatedNodesManager: NativeAnimatedNodesManager) { @@ -1085,7 +997,6 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) : BatchExecutionOpCodes.OP_CODE_DISCONNECT_ANIMATED_NODE_FROM_VIEW -> { val animatedNodeTag = opsAndArgs.getInt(i++) viewTag = opsAndArgs.getInt(i++) - decrementInFlightAnimationsForViewTag(viewTag) animatedNodesManager.disconnectAnimatedNodeFromView(animatedNodeTag, viewTag) } @@ -1104,7 +1015,6 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) : BatchExecutionOpCodes.OP_CODE_REMOVE_ANIMATED_EVENT_FROM_VIEW -> { viewTag = opsAndArgs.getInt(i++) - decrementInFlightAnimationsForViewTag(viewTag) animatedNodesManager.removeAnimatedEventFromView( viewTag, checkNotNull(opsAndArgs.getString(i++)), diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.kt index ec16f18b045e..05ba31d7b132 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedNodesManager.kt @@ -61,25 +61,17 @@ public class NativeAnimatedNodesManager( private val runUpdateNodeList: MutableList = LinkedList() private var eventListenerInitializedForFabric = false - private var eventListenerInitializedForNonFabric = false private var warnedAboutGraphTraversal = false /** - * Initialize event listeners for Fabric UIManager or non-Fabric UIManager, exactly once. Once - * Fabric is the only UIManager, this logic can be simplified. This is expected to only be called - * from the native module thread. + * Initialize event listeners for Fabric UIManager exactly once. This is expected to only be + * called from the native module thread. * * @param uiManagerType */ public fun initializeEventListenerForUIManagerType(@UIManagerType uiManagerType: Int) { - val isEventListenerInitialized = - when (uiManagerType) { - UIManagerType.FABRIC -> eventListenerInitializedForFabric - else -> eventListenerInitializedForNonFabric - } - - if (isEventListenerInitialized) { + if (eventListenerInitializedForFabric) { return } @@ -87,11 +79,7 @@ public class NativeAnimatedNodesManager( UIManagerHelper.getUIManager(checkNotNull(reactApplicationContext), uiManagerType) if (uiManager != null) { uiManager.eventDispatcher.addListener(this) - if (uiManagerType == UIManagerType.FABRIC) { - eventListenerInitializedForFabric = true - } else { - eventListenerInitializedForNonFabric = true - } + eventListenerInitializedForFabric = true } } @@ -763,7 +751,6 @@ public class NativeAnimatedNodesManager( FLog.e(TAG, node.prettyPrintWithChildren()) } - // If we're running only in non-Fabric, we still throw an exception. // In Fabric, it seems that animations enter an inconsistent state fairly often. // We detect if the inconsistency is due to a cycle (a fatal error for which we must crash) // or disconnected regions, indicating a partially-set-up animation graph, which is not @@ -773,17 +760,9 @@ public class NativeAnimatedNodesManager( IllegalStateException( ("Looks like animated nodes graph has ${reason}, there are $activeNodesCount but toposort visited only $updatedNodesCount") ) - if (eventListenerInitializedForFabric && cyclesDetected == 0) { - // TODO T71377544: investigate these SoftExceptions and see if we can remove entirely - // or fix the root cause - ReactSoftExceptionLogger.logSoftException(TAG, ReactNoCrashSoftException(ex)) - } else if (eventListenerInitializedForFabric) { - // TODO T71377544: investigate these SoftExceptions and see if we can remove entirely - // or fix the root cause - ReactSoftExceptionLogger.logSoftException(TAG, ReactNoCrashSoftException(ex)) - } else { - throw ex - } + // TODO T71377544: investigate these SoftExceptions and see if we can remove entirely + // or fix the root cause + ReactSoftExceptionLogger.logSoftException(TAG, ReactNoCrashSoftException(ex)) } else { warnedAboutGraphTraversal = false } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.kt index 6c841bbf2619..753697ac61a9 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/PropsAnimatedNode.kt @@ -12,8 +12,6 @@ import com.facebook.react.bridge.JSApplicationIllegalArgumentException import com.facebook.react.bridge.JavaOnlyMap import com.facebook.react.bridge.ReadableMap import com.facebook.react.bridge.UIManager -import com.facebook.react.uimanager.common.UIManagerType -import com.facebook.react.uimanager.common.ViewUtil.getUIManagerType /** * Animated node that represents view properties. There is a special handling logic implemented for @@ -67,23 +65,8 @@ internal class PropsAnimatedNode( } fun restoreDefaultValues() { - // Cannot restore default values if this view has already been disconnected. - if (connectedViewTag == -1) { - return - } - // Don't restore default values in Fabric. - // In Non-Fabric this had the effect of "restore the value to whatever the value was on the - // ShadowNode instead of in the View hierarchy". However, "synchronouslyUpdateViewOnUIThread" - // will not have that impact on Fabric, because the FabricUIManager doesn't have access to the - // ShadowNode layer. - if (getUIManagerType(connectedViewTag) == UIManagerType.FABRIC) { - return - } - val it = propMap.keySetIterator() - while (it.hasNextKey()) { - propMap.putNull(it.nextKey()) - } - connectedViewUIManager?.synchronouslyUpdateViewOnUIThread(connectedViewTag, propMap) + // In Fabric, we don't restore default values since the FabricUIManager doesn't have access + // to the ShadowNode layer. This method was only relevant for the legacy Paper renderer. } fun updateView() { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceView.kt index 1ab36cda87df..4a59c759464e 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceView.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactSurfaceView.kt @@ -26,7 +26,6 @@ import com.facebook.react.uimanager.IllegalViewOperationException import com.facebook.react.uimanager.JSKeyDispatcher import com.facebook.react.uimanager.JSPointerDispatcher import com.facebook.react.uimanager.JSTouchDispatcher -import com.facebook.react.uimanager.common.UIManagerType import com.facebook.systrace.Systrace import java.util.Objects import kotlin.math.max @@ -150,14 +149,6 @@ public class ReactSurfaceView(context: Context?, internal val surface: ReactSurf (surface.reactHost ?: throw e).handleHostException(e) } - override fun setIsFabric(isFabric: Boolean) { - // This surface view is always on Fabric regardless. - super.setIsFabric(true) - } - - // This surface view is always on Fabric. - @UIManagerType override fun getUIManagerType(): Int = UIManagerType.FABRIC - override fun getJSModuleName(): String = surface.moduleName override fun dispatchJSTouchEvent(event: MotionEvent) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BackgroundStyleApplicator.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BackgroundStyleApplicator.kt index c466a71b9ca8..f7e7fade8c4d 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BackgroundStyleApplicator.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BackgroundStyleApplicator.kt @@ -24,8 +24,6 @@ import com.facebook.react.bridge.ReadableArray import com.facebook.react.common.annotations.UnstableReactNativeAPI import com.facebook.react.uimanager.PixelUtil.dpToPx import com.facebook.react.uimanager.PixelUtil.pxToDp -import com.facebook.react.uimanager.common.UIManagerType -import com.facebook.react.uimanager.common.ViewUtil import com.facebook.react.uimanager.drawable.BackgroundDrawable import com.facebook.react.uimanager.drawable.BackgroundImageDrawable import com.facebook.react.uimanager.drawable.BorderDrawable @@ -279,17 +277,13 @@ public object BackgroundStyleApplicator { } /** - * Sets the outline color for the view (Fabric only). + * Sets the outline color for the view. * * @param view The view to apply the outline color to * @param outlineColor The outline color, or null to remove */ @JvmStatic public fun setOutlineColor(view: View, @ColorInt outlineColor: Int?) { - if (ViewUtil.getUIManagerType(view) != UIManagerType.FABRIC) { - return - } - val outline = ensureOutlineDrawable(view) if (outlineColor != null) { outline.outlineColor = outlineColor @@ -305,17 +299,13 @@ public object BackgroundStyleApplicator { @JvmStatic public fun getOutlineColor(view: View): Int? = getOutlineDrawable(view)?.outlineColor /** - * Sets the outline offset for the view (Fabric only). + * Sets the outline offset for the view. * * @param view The view to apply the outline offset to * @param outlineOffset The outline offset in DIPs */ @JvmStatic public fun setOutlineOffset(view: View, outlineOffset: Float): Unit { - if (ViewUtil.getUIManagerType(view) != UIManagerType.FABRIC) { - return - } - val outline = ensureOutlineDrawable(view) outline.outlineOffset = outlineOffset.dpToPx() } @@ -329,17 +319,13 @@ public object BackgroundStyleApplicator { public fun getOutlineOffset(view: View): Float? = getOutlineDrawable(view)?.outlineOffset /** - * Sets the outline style for the view (Fabric only). + * Sets the outline style for the view. * * @param view The view to apply the outline style to * @param outlineStyle The outline style (solid, dashed, dotted), or null to remove */ @JvmStatic public fun setOutlineStyle(view: View, outlineStyle: OutlineStyle?): Unit { - if (ViewUtil.getUIManagerType(view) != UIManagerType.FABRIC) { - return - } - val outline = ensureOutlineDrawable(view) if (outlineStyle != null) { outline.outlineStyle = outlineStyle @@ -355,17 +341,13 @@ public object BackgroundStyleApplicator { public fun getOutlineStyle(view: View): OutlineStyle? = getOutlineDrawable(view)?.outlineStyle /** - * Sets the outline width for the view (Fabric only). + * Sets the outline width for the view. * * @param view The view to apply the outline width to * @param width The outline width in DIPs */ @JvmStatic public fun setOutlineWidth(view: View, width: Float) { - if (ViewUtil.getUIManagerType(view) != UIManagerType.FABRIC) { - return - } - val outline = ensureOutlineDrawable(view) outline.outlineWidth = width.dpToPx() } @@ -379,17 +361,13 @@ public object BackgroundStyleApplicator { public fun getOutlineWidth(view: View): Float? = getOutlineDrawable(view)?.outlineOffset /** - * Sets box shadows for the view (Fabric only). + * Sets box shadows for the view. * * @param view The view to apply box shadows to * @param shadows The list of box shadow styles to apply */ @JvmStatic public fun setBoxShadow(view: View, shadows: List) { - if (ViewUtil.getUIManagerType(view) != UIManagerType.FABRIC) { - return - } - var innerShadows = mutableListOf() var outerShadows = mutableListOf() @@ -443,7 +421,7 @@ public object BackgroundStyleApplicator { } /** - * Sets box shadows for the view from a ReadableArray (Fabric only). + * Sets box shadows for the view from a ReadableArray. * * @param view The view to apply box shadows to * @param shadows The array of box shadow definitions, or null to remove all shadows diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java index 4dce0dd995c9..c837b84adc6d 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BaseViewManager.java @@ -33,8 +33,6 @@ import com.facebook.react.uimanager.ReactAccessibilityDelegate.AccessibilityRole; import com.facebook.react.uimanager.ReactAccessibilityDelegate.Role; import com.facebook.react.uimanager.annotations.ReactProp; -import com.facebook.react.uimanager.common.UIManagerType; -import com.facebook.react.uimanager.common.ViewUtil; import com.facebook.react.uimanager.events.BlurEvent; import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.react.uimanager.events.FocusEvent; @@ -235,20 +233,16 @@ public void setBackgroundColor(@NonNull T view, @ColorInt int backgroundColor) { @ReactProp(name = ViewProps.FILTER, customType = "Filter") public void setFilter(@NonNull T view, @Nullable ReadableArray filter) { - if (ViewUtil.getUIManagerType(view) == UIManagerType.FABRIC) { - view.setTag(R.id.filter, filter); - } + view.setTag(R.id.filter, filter); } @ReactProp(name = ViewProps.MIX_BLEND_MODE) public void setMixBlendMode(@NonNull T view, @Nullable String mixBlendMode) { - if (ViewUtil.getUIManagerType(view) == UIManagerType.FABRIC) { - view.setTag(R.id.mix_blend_mode, BlendModeHelper.parseMixBlendMode(mixBlendMode)); - // We need to trigger drawChild for the parent ViewGroup which will set the - // mixBlendMode compositing on the child - if (view.getParent() instanceof View) { - ((View) view.getParent()).invalidate(); - } + view.setTag(R.id.mix_blend_mode, BlendModeHelper.parseMixBlendMode(mixBlendMode)); + // We need to trigger drawChild for the parent ViewGroup which will set the + // mixBlendMode compositing on the child + if (view.getParent() instanceof View) { + ((View) view.getParent()).invalidate(); } } @@ -592,16 +586,13 @@ protected void setTransformProperty( return; } - boolean allowPercentageResolution = ViewUtil.getUIManagerType(view) == UIManagerType.FABRIC; - sMatrixDecompositionContext.reset(); TransformHelper.processTransform( transforms, sTransformDecompositionArray, PixelUtil.toDIPFromPixel(view.getWidth()), PixelUtil.toDIPFromPixel(view.getHeight()), - transformOrigin, - allowPercentageResolution); + transformOrigin); MatrixMathHelper.decomposeMatrix(sTransformDecompositionArray, sMatrixDecompositionContext); view.setTranslationX( PixelUtil.toPixelFromDIP( diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.kt index 3be182d08d1c..3c1cbe917d11 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.kt @@ -35,7 +35,7 @@ import com.facebook.react.bridge.ReadableType import com.facebook.react.bridge.WritableMap import com.facebook.react.uimanager.UIManagerHelper.getSurfaceId import com.facebook.react.uimanager.UIManagerHelper.getUIManager -import com.facebook.react.uimanager.common.ViewUtil.getUIManagerType +import com.facebook.react.uimanager.common.UIManagerType import com.facebook.react.uimanager.events.Event import com.facebook.react.uimanager.util.ReactFindViewUtil.findView @@ -231,7 +231,7 @@ public open class ReactAccessibilityDelegate( // The View this delegate is attac if (reactContext.hasActiveReactInstance()) { val reactTag = host.id val surfaceId = getSurfaceId(reactContext) - val uiManager = getUIManager(reactContext, getUIManagerType(reactTag)) + val uiManager = getUIManager(reactContext, UIManagerType.FABRIC) if (uiManager != null) { uiManager.eventDispatcher.dispatchEvent( AccessibilityActionEvent(eventData, surfaceId, reactTag) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.kt index 711167c1dc14..f16f854d6c91 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.kt @@ -16,8 +16,6 @@ import com.facebook.common.logging.FLog import com.facebook.react.bridge.UiThreadUtil import com.facebook.react.common.ReactConstants import com.facebook.react.touch.ReactHitSlopView -import com.facebook.react.uimanager.common.UIManagerType -import com.facebook.react.uimanager.common.ViewUtil import java.util.EnumSet /** @@ -193,10 +191,7 @@ public object TouchTargetHelper { if (view is ReactOverflowViewWithInset) { // If the touch point is outside of the overflow inset for the view, we can safely ignore // it. - if ( - ViewUtil.getUIManagerType(view.id) == UIManagerType.FABRIC && - !isTouchPointInViewWithOverflowInset(eventCoords[0], eventCoords[1], view) - ) { + if (!isTouchPointInViewWithOverflowInset(eventCoords[0], eventCoords[1], view)) { return null } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.kt index 36413e9dcc61..70a9b51f0767 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TransformHelper.kt @@ -40,16 +40,16 @@ public object TransformHelper { } @Deprecated( - "Use processTransform(ReadableArray, DoubleArray, Float, Float, ReadableArray, Boolean) instead", + "Use processTransform(ReadableArray, DoubleArray, Float, Float, ReadableArray) instead", ReplaceWith("processTransform(...)"), ) @JvmStatic public fun processTransform(transforms: ReadableArray, result: DoubleArray) { - processTransform(transforms, result, 0f, 0f, null, false) + processTransform(transforms, result, 0f, 0f, null) } @Deprecated( - "Use processTransform(ReadableArray, DoubleArray, Float, Float, ReadableArray, Boolean) instead", + "Use processTransform(ReadableArray, DoubleArray, Float, Float, ReadableArray) instead", ReplaceWith("processTransform(...)"), ) @JvmStatic @@ -59,8 +59,9 @@ public object TransformHelper { viewWidth: Float, viewHeight: Float, transformOrigin: ReadableArray?, + allowPercentageResolution: Boolean, ) { - processTransform(transforms, result, viewWidth, viewHeight, transformOrigin, false) + processTransform(transforms, result, viewWidth, viewHeight, transformOrigin) } @JvmStatic @@ -70,9 +71,8 @@ public object TransformHelper { viewWidth: Float, viewHeight: Float, transformOrigin: ReadableArray?, - allowPercentageResolution: Boolean, ) { - if (allowPercentageResolution && transforms is NativeArray && transformOrigin is NativeArray?) { + if (transforms is NativeArray && transformOrigin is NativeArray?) { nativeProcessTransform(transforms, result, viewWidth, viewHeight, transformOrigin) return } @@ -84,7 +84,6 @@ public object TransformHelper { viewWidth, viewHeight, transformOrigin, - allowPercentageResolution, ) if (offsets != null) { @@ -144,11 +143,11 @@ public object TransformHelper { "translate" -> { val value = transform.getArray(transformType)!! val x = - if (value.getType(0) == ReadableType.String && allowPercentageResolution) + if (value.getType(0) == ReadableType.String) parseTranslateValue(value.getString(0)!!, viewWidth.toDouble()) else value.getDouble(0) val y = - if (value.getType(1) == ReadableType.String && allowPercentageResolution) + if (value.getType(1) == ReadableType.String) parseTranslateValue(value.getString(1)!!, viewHeight.toDouble()) else value.getDouble(1) val z = if (value.size() > 2) value.getDouble(2) else 0.0 @@ -156,20 +155,14 @@ public object TransformHelper { } "translateX" -> { val translateValue = - if ( - transform.getType(transformType) == ReadableType.String && - allowPercentageResolution - ) + if (transform.getType(transformType) == ReadableType.String) parseTranslateValue(transform.getString(transformType)!!, viewWidth.toDouble()) else transform.getDouble(transformType) MatrixMathHelper.applyTranslate2D(helperMatrix, translateValue, 0.0) } "translateY" -> { val translateValue = - if ( - transform.getType(transformType) == ReadableType.String && - allowPercentageResolution - ) + if (transform.getType(transformType) == ReadableType.String) parseTranslateValue(transform.getString(transformType)!!, viewHeight.toDouble()) else transform.getDouble(transformType) MatrixMathHelper.applyTranslate2D(helperMatrix, 0.0, translateValue) @@ -210,7 +203,6 @@ public object TransformHelper { viewWidth: Float, viewHeight: Float, transformOrigin: ReadableArray?, - allowPercentageResolution: Boolean, ): DoubleArray? { if (transformOrigin == null || (viewHeight == 0f && viewWidth == 0f)) { return null @@ -224,12 +216,10 @@ public object TransformHelper { when (transformOrigin.getType(i)) { ReadableType.Number -> origin[i] = transformOrigin.getDouble(i) ReadableType.String -> { - if (allowPercentageResolution) { - val part = transformOrigin.getString(i)!! - if (part.endsWith("%")) { - val valPercent = part.dropLast(1).toDouble() - origin[i] = (if (i == 0) viewWidth else viewHeight) * valPercent / 100.0 - } + val part = transformOrigin.getString(i)!! + if (part.endsWith("%")) { + val valPercent = part.dropLast(1).toDouble() + origin[i] = (if (i == 0) viewWidth else viewHeight) * valPercent / 100.0 } } else -> {} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerHelper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerHelper.kt index ebbec34138f0..bbd534dd2ba1 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerHelper.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerHelper.kt @@ -14,16 +14,11 @@ import android.content.ContextWrapper import android.view.View import android.widget.EditText import androidx.core.view.ViewCompat -import com.facebook.react.bridge.CatalystInstance import com.facebook.react.bridge.ReactContext import com.facebook.react.bridge.ReactNoCrashSoftException import com.facebook.react.bridge.ReactSoftExceptionLogger import com.facebook.react.bridge.UIManager -import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel -import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger -import com.facebook.react.common.build.ReactBuildConfig import com.facebook.react.uimanager.common.UIManagerType -import com.facebook.react.uimanager.common.ViewUtil.getUIManagerType import com.facebook.react.uimanager.events.EventDispatcher import com.facebook.react.uimanager.events.EventDispatcherProvider @@ -38,78 +33,31 @@ public object UIManagerHelper { /** @return a [UIManager] that can handle the react tag received by parameter. */ @JvmStatic public fun getUIManagerForReactTag(context: ReactContext, reactTag: Int): UIManager? = - getUIManager(context, getUIManagerType(reactTag)) + getUIManager(context, UIManagerType.FABRIC) /** @return a [UIManager] that can handle the react tag received by parameter. */ @JvmStatic - public fun getUIManager(context: ReactContext, @UIManagerType uiManagerType: Int): UIManager? = - getUIManager(context, uiManagerType, true) - - @JvmStatic - private fun getUIManager( - context: ReactContext, - @UIManagerType uiManagerType: Int, - returnNullIfCatalystIsInactive: Boolean, - ): UIManager? { - if (ReactBuildConfig.UNSTABLE_ENABLE_MINIFY_LEGACY_ARCHITECTURE || context.isBridgeless()) { - val uiManager = context.getFabricUIManager() - if (uiManager == null) { - ReactSoftExceptionLogger.logSoftException( - TAG, - ReactNoCrashSoftException( - "Cannot get UIManager because the instance hasn't been initialized yet." - ), - ) - return null - } - return uiManager - } - - // The following code is compiled-out when `context.isBridgeless() == true && - // ReactBuildConfig.UNSTABLE_ENABLE_MINIFY_LEGACY_ARCHITECTURE == true ` because: - // - BridgelessReactContext.isBridgeless() is set to true statically - // - BridgeReactContext is compiled-out when UNSTABLE_ENABLE_MINIFY_LEGACY_ARCHITECTURE == true - // - // To detect a potential regression we add the following assertion ERROR - LegacyArchitectureLogger.assertLegacyArchitecture( - "UIManagerHelper.getUIManager(context, uiManagerType)", - LegacyArchitectureLogLevel.ERROR, - ) - if (!context.hasCatalystInstance()) { + public fun getUIManager(context: ReactContext, @UIManagerType uiManagerType: Int): UIManager? { + if (!context.hasActiveReactInstance()) { ReactSoftExceptionLogger.logSoftException( TAG, ReactNoCrashSoftException( - "Cannot get UIManager because the context doesn't contain a CatalystInstance." + "Cannot get UIManager because the context doesn't contain an active React instance." ), ) return null } - // TODO T60461551: add tests to verify emission of events when the ReactContext is being turn - // down. - if (!context.hasActiveReactInstance()) { + + val uiManager = context.getFabricUIManager() + if (uiManager == null) { ReactSoftExceptionLogger.logSoftException( TAG, ReactNoCrashSoftException( - "Cannot get UIManager because the context doesn't contain an active" + - " CatalystInstance." + "Cannot get UIManager because the instance hasn't been initialized yet." ), ) - if (returnNullIfCatalystIsInactive) { - return null - } - } - val catalystInstance: CatalystInstance = context.getCatalystInstance() - try { - return if (uiManagerType == UIManagerType.Companion.FABRIC) context.getFabricUIManager() - else catalystInstance.getNativeModule(UIManagerModule::class.java) - } catch (_: IllegalArgumentException) { - // TODO T67518514 Clean this up once we migrate everything over to bridgeless mode - ReactSoftExceptionLogger.logSoftException( - TAG, - ReactNoCrashSoftException("Cannot get UIManager for UIManagerType: $uiManagerType"), - ) - return catalystInstance.getNativeModule(UIManagerModule::class.java) } + return uiManager } /** @return the [EventDispatcher] that handles events for the given [ReactContext]. */ @@ -170,15 +118,7 @@ public object UIManagerHelper { public fun getSurfaceId(view: View): Int { if (view is ReactRoot) { val rootView = view as ReactRoot - return if (rootView.getUIManagerType() == UIManagerType.FABRIC) rootView.getRootViewTag() - else -1 - } - - val reactTag = view.id - - // In non-Fabric we don't have (or use) SurfaceId - if (getUIManagerType(reactTag) == UIManagerType.LEGACY) { - return -1 + return rootView.getRootViewTag() } var context = view.context @@ -192,7 +132,7 @@ public object UIManagerHelper { ReactSoftExceptionLogger.logSoftException( TAG, IllegalStateException( - "Fabric View [$reactTag] does not have SurfaceId associated with it" + "Fabric View [${view.id}] does not have SurfaceId associated with it" ), ) } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java index 3cbaabc800f8..e6ab2086e97e 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java @@ -10,7 +10,6 @@ import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_UI_MANAGER_MODULE_CONSTANTS_END; import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_UI_MANAGER_MODULE_CONSTANTS_START; import static com.facebook.react.uimanager.common.UIManagerType.FABRIC; -import static com.facebook.react.uimanager.common.UIManagerType.LEGACY; import android.content.ComponentCallbacks2; import android.content.res.Configuration; @@ -44,7 +43,6 @@ import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.uimanager.common.ViewUtil; import com.facebook.react.uimanager.events.EventDispatcher; -import com.facebook.react.uimanager.events.RCTEventEmitter; import com.facebook.react.uimanager.internal.LegacyArchitectureShadowNodeLogger; import com.facebook.systrace.Systrace; import com.facebook.systrace.SystraceMessage; @@ -511,9 +509,7 @@ public void dispatchViewManagerCommand( int reactTag, Dynamic commandId, @Nullable ReadableArray commandArgs) { // Fabric dispatchCommands should go through the JSI API - this will crash in Fabric. @Nullable - UIManager uiManager = - UIManagerHelper.getUIManager( - getReactApplicationContext(), ViewUtil.getUIManagerType(reactTag)); + UIManager uiManager = UIManagerHelper.getUIManager(getReactApplicationContext(), FABRIC); if (uiManager == null) { return; } @@ -570,14 +566,10 @@ public EventDispatcher getEventDispatcher() { @Override @ReactMethod public void sendAccessibilityEvent(int tag, int eventType) { - int uiManagerType = ViewUtil.getUIManagerType(tag); - if (uiManagerType == FABRIC) { - // TODO: T65793557 Refactor sendAccessibilityEvent to use ViewCommands - UIManager fabricUIManager = - UIManagerHelper.getUIManager(getReactApplicationContext(), uiManagerType); - if (fabricUIManager != null) { - fabricUIManager.sendAccessibilityEvent(tag, eventType); - } + // TODO: T65793557 Refactor sendAccessibilityEvent to use ViewCommands + UIManager fabricUIManager = UIManagerHelper.getUIManager(getReactApplicationContext(), FABRIC); + if (fabricUIManager != null) { + fabricUIManager.sendAccessibilityEvent(tag, eventType); } } @@ -669,9 +661,6 @@ public void receiveEvent(int reactTag, String eventName, @Nullable WritableMap e @Override public void receiveEvent( int surfaceId, int reactTag, String eventName, @Nullable WritableMap event) { - assert ViewUtil.getUIManagerType(reactTag) == LEGACY; - getReactApplicationContext() - .getJSModule(RCTEventEmitter.class) - .receiveEvent(reactTag, eventName, event); + assert false; } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/common/ViewUtil.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/common/ViewUtil.kt index 22d34f6c63fb..d3cba46d56d3 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/common/ViewUtil.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/common/ViewUtil.kt @@ -8,6 +8,7 @@ package com.facebook.react.uimanager.common import android.view.View +import com.facebook.react.common.annotations.internal.LegacyArchitecture /** * Utility object providing helper methods for working with React Native views. @@ -33,53 +34,51 @@ public object ViewUtil { * https://github.com/facebook/react/pull/12587 * * @param viewTag tag of the view this is event is dispatched to + * @deprecated Fabric is now the only supported UIManager. This method always returns + * [UIManagerType.FABRIC]. */ + @Deprecated( + "Fabric is now the only supported UIManager. This method always returns UIManagerType.FABRIC.", + ReplaceWith("UIManagerType.FABRIC"), + ) + @LegacyArchitecture @JvmStatic @UIManagerType - public fun getUIManagerType(viewTag: Int): Int = - if (viewTag % 2 == 0) { - UIManagerType.FABRIC - } else { - UIManagerType.LEGACY - } + public fun getUIManagerType(viewTag: Int): Int = UIManagerType.FABRIC /** * Overload for [getUIManagerType] that uses the view's id to determine if it originated from * Fabric + * + * @deprecated Fabric is now the only supported UIManager. This method always returns + * [UIManagerType.FABRIC]. */ - @JvmStatic @UIManagerType public fun getUIManagerType(view: View): Int = getUIManagerType(view.id) + @Deprecated( + "Fabric is now the only supported UIManager. This method always returns UIManagerType.FABRIC.", + ReplaceWith("UIManagerType.FABRIC"), + ) + @LegacyArchitecture + @JvmStatic + @UIManagerType + public fun getUIManagerType(view: View): Int = UIManagerType.FABRIC /** * Version of getUIManagerType that uses both surfaceId and viewTag heuristics * * @param viewTag tag of the view this is event is dispatched to * @param surfaceId ID of the corresponding surface + * @deprecated Fabric is now the only supported UIManager. This method always returns + * [UIManagerType.FABRIC]. */ - @Suppress("DEPRECATION") + @Deprecated( + "Fabric is now the only supported UIManager. This method always returns UIManagerType.FABRIC.", + ReplaceWith("UIManagerType.FABRIC"), + ) + @LegacyArchitecture + @Suppress("UNUSED_PARAMETER") @JvmStatic @UIManagerType - public fun getUIManagerType(viewTag: Int, surfaceId: Int): Int { - // We have a contract that Fabric events *always* have a SurfaceId passed in, and non-Fabric - // events NEVER have a SurfaceId passed in (the default/placeholder of -1 is passed in instead). - // - // Why does this matter? - // Events can be sent to Views that are part of the View hierarchy *but not directly managed - // by React Native*. For example, embedded custom hierarchies, Litho hierarchies, etc. - // In those cases it's important to know that the Event should be sent to the Fabric or - // non-Fabric UIManager, and we cannot use the ViewTag for inference since it's not controlled - // by RN and is essentially a random number. - // At some point it would be great to pass the SurfaceContext here instead. - @UIManagerType - val uiManagerType = if (surfaceId == -1) UIManagerType.LEGACY else UIManagerType.FABRIC - if (uiManagerType == UIManagerType.LEGACY && !isRootTag(viewTag)) { - // TODO (T123064648): Some events for Fabric still didn't have the surfaceId set, so if it's - // not a React RootView, double check if the tag belongs to Fabric. - if (viewTag % 2 == 0) { - return UIManagerType.FABRIC - } - } - return uiManagerType - } + public fun getUIManagerType(viewTag: Int, surfaceId: Int): Int = UIManagerType.FABRIC /** * @param viewTag react tag diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.kt index 60239c2954c1..f159a5f1343c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/MaintainVisibleScrollPositionHelper.kt @@ -18,7 +18,6 @@ import com.facebook.react.bridge.UiThreadUtil.runOnUiThread import com.facebook.react.common.annotations.UnstableReactNativeAPI import com.facebook.react.uimanager.UIManagerHelper import com.facebook.react.uimanager.common.UIManagerType -import com.facebook.react.uimanager.common.ViewUtil.getUIManagerType import com.facebook.react.views.scroll.ReactScrollViewHelper.HasSmoothScroll import com.facebook.react.views.view.ReactViewGroup import java.lang.ref.WeakReference @@ -47,7 +46,7 @@ internal class MaintainVisibleScrollPositionHelper( checkNotNull( UIManagerHelper.getUIManager( checkNotNull(scrollView?.context as ReactContext?), - getUIManagerType(scrollView.id ?: 0), + UIManagerType.FABRIC, ) ) @@ -88,8 +87,8 @@ internal class MaintainVisibleScrollPositionHelper( * been updated. */ fun updateScrollPosition() { - // On Fabric this will be called internally in `didMountItems`. - if (scrollView == null || getUIManagerType(scrollView.id) == UIManagerType.FABRIC) { + // In Fabric this is called internally in `didMountItems`. + if (scrollView == null) { return } updateScrollPositionInternal() diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerLegacyView.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerLegacyView.kt deleted file mode 100644 index a0c08d4aee1b..000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerLegacyView.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and 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.views.scroll - -import android.content.Context -import com.facebook.react.modules.i18nmanager.I18nUtil -import com.facebook.react.views.view.ReactViewGroup - -/** - * Used by legacy/Paper renderer to perform offsetting of scroll content when the app-wide layout - * direction is RTL. Contextually set layout direction is not respected by legacy renderer. - */ -internal class ReactHorizontalScrollContainerLegacyView(context: Context) : - ReactViewGroup(context) { - private val isRTL: Boolean = I18nUtil.instance.isRTL(context) - - override var removeClippedSubviews: Boolean - get() = super.removeClippedSubviews - set(value) { - // removeClippedSubviews logic may read metrics before the offsetting we do in onLayout() and - // is such unsafe - if (isRTL) { - super.removeClippedSubviews = false - } else { - super.removeClippedSubviews = value - } - } - - override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { - if (isRTL) { - // When the layout direction is RTL, we expect Yoga to give us a layout - // that extends off the screen to the left so we re-center it with left=0 - val newLeft = 0 - val width = right - left - val newRight = newLeft + width - setLeft(newLeft) - setTop(top) - setRight(newRight) - setBottom(bottom) - } - } -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerViewManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerViewManager.kt index bdb980ed8310..6eb7452dd19e 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerViewManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerViewManager.kt @@ -8,11 +8,7 @@ package com.facebook.react.views.scroll import com.facebook.react.module.annotations.ReactModule -import com.facebook.react.uimanager.ReactStylesDiffMap -import com.facebook.react.uimanager.StateWrapper import com.facebook.react.uimanager.ThemedReactContext -import com.facebook.react.uimanager.common.UIManagerType -import com.facebook.react.uimanager.common.ViewUtil import com.facebook.react.views.view.ReactViewGroup import com.facebook.react.views.view.ReactViewManager @@ -21,28 +17,11 @@ import com.facebook.react.views.view.ReactViewManager public class ReactHorizontalScrollContainerViewManager : ReactViewManager() { public override fun getName(): String = REACT_CLASS - protected override fun createViewInstance( - reactTag: Int, - context: ThemedReactContext, - initialProps: ReactStylesDiffMap?, - stateWrapper: StateWrapper?, - ): ReactViewGroup { - check(uiManagerType == null) - uiManagerType = ViewUtil.getUIManagerType(reactTag) - val view = super.createViewInstance(reactTag, context, initialProps, stateWrapper) - uiManagerType = null - return view - } - public override fun createViewInstance(context: ThemedReactContext): ReactViewGroup { - return when (checkNotNull(uiManagerType)) { - UIManagerType.FABRIC -> ReactViewGroup(context) - else -> ReactHorizontalScrollContainerLegacyView(context) - } + return ReactViewGroup(context) } public companion object { public const val REACT_CLASS: String = "AndroidHorizontalScrollContentView" - @UIManagerType private var uiManagerType: Int? = null } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.kt index b5ac1d972947..98b52e028f9f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.kt @@ -30,7 +30,6 @@ import com.facebook.react.uimanager.ReactClippingViewGroup import com.facebook.react.uimanager.StateWrapper import com.facebook.react.uimanager.UIManagerHelper import com.facebook.react.uimanager.common.UIManagerType -import com.facebook.react.uimanager.common.ViewUtil import java.lang.ref.WeakReference import java.util.concurrent.CopyOnWriteArrayList import kotlin.math.abs @@ -347,9 +346,6 @@ public object ReactScrollViewHelper { scrollY, ) } - if (ViewUtil.getUIManagerType(scrollView.id) == UIManagerType.LEGACY) { - return - } // NOTE: if the state wrapper is null, we shouldn't even update // the scroll state because there is a chance of going out of sync! if (scrollView.stateWrapper == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java index 1bf559723a9a..a23e1d3d59db 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java @@ -26,36 +26,28 @@ import android.view.ViewGroup; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatTextView; -import androidx.appcompat.widget.TintContextWrapper; import androidx.core.view.AccessibilityDelegateCompat; import androidx.core.view.ViewCompat; import androidx.customview.widget.ExploreByTouchHelper; import com.facebook.common.logging.FLog; -import com.facebook.infer.annotation.Assertions; import com.facebook.infer.annotation.Nullsafe; import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.WritableMap; import com.facebook.react.common.ReactConstants; import com.facebook.react.common.annotations.UnstableReactNativeAPI; -import com.facebook.react.common.build.ReactBuildConfig; import com.facebook.react.internal.SystraceSection; import com.facebook.react.uimanager.BackgroundStyleApplicator; import com.facebook.react.uimanager.LengthPercentage; import com.facebook.react.uimanager.LengthPercentageType; import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.ReactCompoundView; -import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.ViewDefaults; -import com.facebook.react.uimanager.common.UIManagerType; -import com.facebook.react.uimanager.common.ViewUtil; import com.facebook.react.uimanager.style.BorderRadiusProp; import com.facebook.react.uimanager.style.BorderStyle; import com.facebook.react.uimanager.style.LogicalEdge; import com.facebook.react.uimanager.style.Overflow; import com.facebook.react.views.text.internal.span.ReactFragmentIndexSpan; import com.facebook.react.views.text.internal.span.ReactTagSpan; -import com.facebook.react.views.text.internal.span.TextInlineViewPlaceholderSpan; import com.facebook.yoga.YogaMeasureMode; @Nullsafe(Nullsafe.Mode.LOCAL) @@ -181,164 +173,14 @@ private static WritableMap inlineViewJson( return json; } - private ReactContext getReactContext() { - Context context = getContext(); - return (context instanceof TintContextWrapper) - ? (ReactContext) ((TintContextWrapper) context).getBaseContext() - : (ReactContext) context; - } - @Override protected void onLayout( boolean changed, int textViewLeft, int textViewTop, int textViewRight, int textViewBottom) { // TODO T62882314: Delete this method when Fabric is fully released in OSS - int reactTag = getId(); - if (!(getText() instanceof Spanned) - || ViewUtil.getUIManagerType(reactTag) == UIManagerType.FABRIC - || ReactBuildConfig.UNSTABLE_ENABLE_MINIFY_LEGACY_ARCHITECTURE) { - /** - * In general, {@link #setText} is called via {@link ReactTextViewManager#updateExtraData} - * before we are laid out. This ordering is a requirement because we utilize the data from - * setText in onLayout. - * - *

However, it's possible for us to get an extra layout before we've received our setText - * call. If this happens before the initial setText call, then getText() will have its default - * value which isn't a Spanned and we need to bail out. That's fine because we'll get a - * setText followed by a layout later. - * - *

The cause for the extra early layout is that an ancestor gets transitioned from a - * layout-only node to a non layout-only node. - */ - return; - } - - ReactContext reactContext = getReactContext(); - UIManagerModule uiManager = - Assertions.assertNotNull(reactContext.getNativeModule(UIManagerModule.class)); - - Spanned text = (Spanned) getText(); - Layout layout = getLayout(); - if (layout == null) { - // Text layout is calculated during pre-draw phase, so in some cases it can be empty during - // layout phase, which usually happens before drawing. - // The text layout is created by private {@link assumeLayout} method, which we can try to - // invoke directly through reflection or indirectly through some methods that compute it - // (e.g. {@link getExtendedPaddingTop}). - // It is safer, however, to just early return here, as next measure/layout passes are way more - // likely to have the text layout computed. - return; - } - - TextInlineViewPlaceholderSpan[] placeholders = - text.getSpans(0, text.length(), TextInlineViewPlaceholderSpan.class); - int textViewWidth = textViewRight - textViewLeft; - int textViewHeight = textViewBottom - textViewTop; - - for (TextInlineViewPlaceholderSpan placeholder : placeholders) { - View child = uiManager.resolveView(placeholder.getReactTag()); - - if (child == null) { - continue; - } - - int start = text.getSpanStart(placeholder); - int line = layout.getLineForOffset(start); - boolean isLineTruncated = layout.getEllipsisCount(line) > 0; - - if ( // This truncation check works well on recent versions of Android (tested on 5.1.1 and - // 6.0.1) but not on Android 4.4.4. The reason is that getEllipsisCount is buggy on - // Android 4.4.4. Specifically, it incorrectly returns 0 if an inline view is the first - // thing to be truncated. - (isLineTruncated && start >= layout.getLineStart(line) + layout.getEllipsisStart(line)) - || - - // This truncation check works well on Android 4.4.4 but not on others (e.g. 6.0.1). - // On Android 4.4.4, getLineEnd returns the first truncated character whereas on 6.0.1, - // it appears to return the position after the last character on the line even if that - // character is truncated. - line >= mNumberOfLines - || start >= layout.getLineEnd(line)) { - // On some versions of Android (e.g. 4.4.4, 5.1.1), getPrimaryHorizontal can infinite - // loop when called on a character that appears after the ellipsis. Avoid this bug by - // special casing the character truncation case. - child.setVisibility(View.GONE); - } else { - int width = placeholder.getWidth(); - int height = placeholder.getHeight(); - - // Calculate if the direction of the placeholder character is Right-To-Left. - boolean isRtlChar = layout.isRtlCharAt(start); - - boolean isRtlParagraph = layout.getParagraphDirection(line) == Layout.DIR_RIGHT_TO_LEFT; - - int placeholderHorizontalPosition; - // There's a bug on Samsung devices where calling getPrimaryHorizontal on - // the last offset in the layout will result in an endless loop. Work around - // this bug by avoiding getPrimaryHorizontal in that case. - if (start == text.length() - 1) { - boolean endsWithNewLine = - text.length() > 0 && text.charAt(layout.getLineEnd(line) - 1) == '\n'; - float lineWidth = endsWithNewLine ? layout.getLineMax(line) : layout.getLineWidth(line); - placeholderHorizontalPosition = - isRtlParagraph - // Equivalent to `layout.getLineLeft(line)` but `getLineLeft` returns incorrect - // values when the paragraph is RTL and `setSingleLine(true)`. - ? textViewWidth - (int) lineWidth - : (int) layout.getLineRight(line) - width; - } else { - // The direction of the paragraph may not be exactly the direction the string is heading - // in at the - // position of the placeholder. So, if the direction of the character is the same as the - // paragraph - // use primary, secondary otherwise. - boolean characterAndParagraphDirectionMatch = isRtlParagraph == isRtlChar; - - placeholderHorizontalPosition = - characterAndParagraphDirectionMatch - ? (int) layout.getPrimaryHorizontal(start) - : (int) layout.getSecondaryHorizontal(start); - - if (isRtlParagraph) { - // Adjust `placeholderHorizontalPosition` to work around an Android bug. - // The bug is when the paragraph is RTL and `setSingleLine(true)`, some layout - // methods such as `getPrimaryHorizontal`, `getSecondaryHorizontal`, and - // `getLineRight` return incorrect values. Their return values seem to be off - // by the same number of pixels so subtracting these values cancels out the error. - // - // The result is equivalent to bugless versions of - // `getPrimaryHorizontal`/`getSecondaryHorizontal`. - placeholderHorizontalPosition = - textViewWidth - ((int) layout.getLineRight(line) - placeholderHorizontalPosition); - } - - if (isRtlChar) { - placeholderHorizontalPosition -= width; - } - } - - int leftRelativeToTextView = - isRtlChar - ? placeholderHorizontalPosition + getTotalPaddingRight() - : placeholderHorizontalPosition + getTotalPaddingLeft(); - - int left = textViewLeft + leftRelativeToTextView; - - // Vertically align the inline view to the baseline of the line of text. - int topRelativeToTextView = getTotalPaddingTop() + layout.getLineBaseline(line) - height; - int top = textViewTop + topRelativeToTextView; - - boolean isFullyClipped = - textViewWidth <= leftRelativeToTextView || textViewHeight <= topRelativeToTextView; - int layoutVisibility = isFullyClipped ? View.GONE : View.VISIBLE; - int layoutLeft = left; - int layoutTop = top; - int layoutRight = left + width; - int layoutBottom = top + height; - - child.setVisibility(layoutVisibility); - child.layout(layoutLeft, layoutTop, layoutRight, layoutBottom); - } - } + // In Fabric, setText is called via ReactTextViewManager#updateExtraData + // before we are laid out. This ordering is a requirement because we utilize the data from + // setText in onLayout. The early return here is safe because the text layout is handled + // correctly in Fabric. } @Override diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt index ba9548f37784..a0f2152677e3 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt @@ -62,8 +62,6 @@ import com.facebook.react.uimanager.PixelUtil.toDIPFromPixel import com.facebook.react.uimanager.ReactAccessibilityDelegate import com.facebook.react.uimanager.StateWrapper import com.facebook.react.uimanager.UIManagerHelper -import com.facebook.react.uimanager.common.UIManagerType -import com.facebook.react.uimanager.common.ViewUtil.getUIManagerType import com.facebook.react.uimanager.events.EventDispatcher import com.facebook.react.uimanager.style.BorderRadiusProp import com.facebook.react.uimanager.style.BorderStyle @@ -1098,9 +1096,6 @@ public open class ReactEditText public constructor(context: Context) : AppCompat if (!haveText) { if (hint != null && hint.isNotEmpty()) { sb.append(hint) - } else if (getUIManagerType(this) != UIManagerType.FABRIC) { - // Measure something so we have correct height, even if there's no string. - sb.append("I") } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt index 880c15362a4b..8f4315563500 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.kt @@ -58,8 +58,6 @@ import com.facebook.react.uimanager.ReactClippingViewGroupHelper.calculateClippi import com.facebook.react.uimanager.ReactOverflowViewWithInset import com.facebook.react.uimanager.ReactPointerEventsView import com.facebook.react.uimanager.ReactZIndexedViewGroup -import com.facebook.react.uimanager.common.UIManagerType -import com.facebook.react.uimanager.common.ViewUtil.getUIManagerType import com.facebook.react.uimanager.style.BorderRadiusProp import com.facebook.react.uimanager.style.BorderStyle import com.facebook.react.uimanager.style.LogicalEdge @@ -851,11 +849,7 @@ public open class ReactViewGroup public constructor(context: Context?) : } override fun draw(canvas: Canvas) { - if ( - Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && - getUIManagerType(this) == UIManagerType.FABRIC && - needsIsolatedLayer(this) - ) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && needsIsolatedLayer(this)) { // Check if the view is a stacking context and has children, if it does, do the rendering // offscreen and then composite back. This follows the idea of group isolation on blending // https://www.w3.org/TR/compositing-1/#isolationblending @@ -890,11 +884,7 @@ public open class ReactViewGroup public constructor(context: Context?) : } var mixBlendMode: BlendMode? = null - if ( - Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && - getUIManagerType(this) == UIManagerType.FABRIC && - needsIsolatedLayer(this) - ) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && needsIsolatedLayer(this)) { mixBlendMode = child.getTag(R.id.mix_blend_mode) as? BlendMode if (mixBlendMode != null) { val p = Paint() diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.kt index 0c8568f74f7a..479eee756a7e 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewManager.kt @@ -22,7 +22,6 @@ import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags import com.facebook.react.module.annotations.ReactModule import com.facebook.react.uimanager.BackgroundStyleApplicator import com.facebook.react.uimanager.LengthPercentage -import com.facebook.react.uimanager.LengthPercentageType import com.facebook.react.uimanager.PixelUtil.dpToPx import com.facebook.react.uimanager.PointerEvents import com.facebook.react.uimanager.ReactAxOrderHelper @@ -32,8 +31,6 @@ import com.facebook.react.uimanager.UIManagerHelper import com.facebook.react.uimanager.ViewProps import com.facebook.react.uimanager.annotations.ReactProp import com.facebook.react.uimanager.annotations.ReactPropGroup -import com.facebook.react.uimanager.common.UIManagerType -import com.facebook.react.uimanager.common.ViewUtil import com.facebook.react.uimanager.style.BackgroundImageLayer import com.facebook.react.uimanager.style.BackgroundPosition import com.facebook.react.uimanager.style.BackgroundRepeat @@ -138,37 +135,33 @@ public open class ReactViewManager : ReactClippingViewManager() @ReactProp(name = ViewProps.BACKGROUND_IMAGE, customType = "BackgroundImage") public open fun setBackgroundImage(view: ReactViewGroup, backgroundImage: ReadableArray?) { - if (ViewUtil.getUIManagerType(view) == UIManagerType.FABRIC) { - if (backgroundImage != null && backgroundImage.size() > 0) { - val backgroundImageLayers = ArrayList(backgroundImage.size()) - for (i in 0 until backgroundImage.size()) { - val backgroundImageMap = backgroundImage.getMap(i) - val layer = BackgroundImageLayer.parse(backgroundImageMap, view.context) - if (layer != null) { - backgroundImageLayers.add(layer) - } + if (backgroundImage != null && backgroundImage.size() > 0) { + val backgroundImageLayers = ArrayList(backgroundImage.size()) + for (i in 0 until backgroundImage.size()) { + val backgroundImageMap = backgroundImage.getMap(i) + val layer = BackgroundImageLayer.parse(backgroundImageMap, view.context) + if (layer != null) { + backgroundImageLayers.add(layer) } - BackgroundStyleApplicator.setBackgroundImage(view, backgroundImageLayers) - } else { - BackgroundStyleApplicator.setBackgroundImage(view, null) } + BackgroundStyleApplicator.setBackgroundImage(view, backgroundImageLayers) + } else { + BackgroundStyleApplicator.setBackgroundImage(view, null) } } @ReactProp(name = ViewProps.BACKGROUND_SIZE, customType = "BackgroundSize") public open fun setBackgroundSize(view: ReactViewGroup, backgroundSize: ReadableArray?) { - if (ViewUtil.getUIManagerType(view) == UIManagerType.FABRIC) { - if (backgroundSize != null && backgroundSize.size() > 0) { - val backgroundSizes = ArrayList(backgroundSize.size()) - for (i in 0 until backgroundSize.size()) { - val backgroundSizeValue = backgroundSize.getDynamic(i) - val parsedBackgroundSize = BackgroundSize.parse(backgroundSizeValue) - if (parsedBackgroundSize != null) { - backgroundSizes.add(parsedBackgroundSize) - } + if (backgroundSize != null && backgroundSize.size() > 0) { + val backgroundSizes = ArrayList(backgroundSize.size()) + for (i in 0 until backgroundSize.size()) { + val backgroundSizeValue = backgroundSize.getDynamic(i) + val parsedBackgroundSize = BackgroundSize.parse(backgroundSizeValue) + if (parsedBackgroundSize != null) { + backgroundSizes.add(parsedBackgroundSize) } - BackgroundStyleApplicator.setBackgroundSize(view, backgroundSizes.ifEmpty { null }) } + BackgroundStyleApplicator.setBackgroundSize(view, backgroundSizes.ifEmpty { null }) } else { BackgroundStyleApplicator.setBackgroundSize(view, null) } @@ -176,39 +169,35 @@ public open class ReactViewManager : ReactClippingViewManager() @ReactProp(name = ViewProps.BACKGROUND_POSITION, customType = "BackgroundPosition") public open fun setBackgroundPosition(view: ReactViewGroup, backgroundPosition: ReadableArray?) { - if (ViewUtil.getUIManagerType(view) == UIManagerType.FABRIC) { - if (backgroundPosition != null && backgroundPosition.size() > 0) { - val backgroundPositions = ArrayList(backgroundPosition.size()) - for (i in 0 until backgroundPosition.size()) { - val backgroundPositionMap = backgroundPosition.getMap(i) - val parsedBackgroundPosition = BackgroundPosition.parse(backgroundPositionMap) - if (parsedBackgroundPosition != null) { - backgroundPositions.add(parsedBackgroundPosition) - } + if (backgroundPosition != null && backgroundPosition.size() > 0) { + val backgroundPositions = ArrayList(backgroundPosition.size()) + for (i in 0 until backgroundPosition.size()) { + val backgroundPositionMap = backgroundPosition.getMap(i) + val parsedBackgroundPosition = BackgroundPosition.parse(backgroundPositionMap) + if (parsedBackgroundPosition != null) { + backgroundPositions.add(parsedBackgroundPosition) } - BackgroundStyleApplicator.setBackgroundPosition(view, backgroundPositions.ifEmpty { null }) - } else { - BackgroundStyleApplicator.setBackgroundPosition(view, null) } + BackgroundStyleApplicator.setBackgroundPosition(view, backgroundPositions.ifEmpty { null }) + } else { + BackgroundStyleApplicator.setBackgroundPosition(view, null) } } @ReactProp(name = ViewProps.BACKGROUND_REPEAT, customType = "BackgroundRepeat") public open fun setBackgroundRepeat(view: ReactViewGroup, backgroundRepeat: ReadableArray?) { - if (ViewUtil.getUIManagerType(view) == UIManagerType.FABRIC) { - if (backgroundRepeat != null && backgroundRepeat.size() > 0) { - val backgroundRepeats = ArrayList(backgroundRepeat.size()) - for (i in 0 until backgroundRepeat.size()) { - val backgroundRepeatMap = backgroundRepeat.getMap(i) - val parsedBackgroundRepeat = BackgroundRepeat.parse(backgroundRepeatMap) - if (parsedBackgroundRepeat != null) { - backgroundRepeats.add(parsedBackgroundRepeat) - } + if (backgroundRepeat != null && backgroundRepeat.size() > 0) { + val backgroundRepeats = ArrayList(backgroundRepeat.size()) + for (i in 0 until backgroundRepeat.size()) { + val backgroundRepeatMap = backgroundRepeat.getMap(i) + val parsedBackgroundRepeat = BackgroundRepeat.parse(backgroundRepeatMap) + if (parsedBackgroundRepeat != null) { + backgroundRepeats.add(parsedBackgroundRepeat) } - BackgroundStyleApplicator.setBackgroundRepeat(view, backgroundRepeats.ifEmpty { null }) - } else { - BackgroundStyleApplicator.setBackgroundRepeat(view, null) } + BackgroundStyleApplicator.setBackgroundRepeat(view, backgroundRepeats.ifEmpty { null }) + } else { + BackgroundStyleApplicator.setBackgroundRepeat(view, null) } } @@ -256,17 +245,7 @@ public open class ReactViewManager : ReactClippingViewManager() ] ) public open fun setBorderRadius(view: ReactViewGroup, index: Int, rawBorderRadius: Dynamic) { - var borderRadius = LengthPercentage.setFromDynamic(rawBorderRadius) - - // We do not support percentage border radii on Paper in order to be consistent with iOS (to - // avoid developer surprise if it works on one platform but not another). - if ( - ViewUtil.getUIManagerType(view) != UIManagerType.FABRIC && - borderRadius != null && - borderRadius.type == LengthPercentageType.PERCENT - ) { - borderRadius = null - } + val borderRadius = LengthPercentage.setFromDynamic(rawBorderRadius) BackgroundStyleApplicator.setBorderRadius(view, BorderRadiusProp.values()[index], borderRadius) }