diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerHelper.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerHelper.java deleted file mode 100644 index c852369a9afa86..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerHelper.java +++ /dev/null @@ -1,235 +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.uimanager; - -import static com.facebook.react.uimanager.common.UIManagerType.FABRIC; -import static com.facebook.react.uimanager.common.ViewUtil.getUIManagerType; - -import android.content.Context; -import android.content.ContextWrapper; -import android.view.View; -import android.widget.EditText; -import androidx.annotation.Nullable; -import androidx.core.view.ViewCompat; -import com.facebook.infer.annotation.Nullsafe; -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.events.EventDispatcher; -import com.facebook.react.uimanager.events.EventDispatcherProvider; - -/** Helper class for {@link UIManager}. */ -@Nullsafe(Nullsafe.Mode.LOCAL) -public class UIManagerHelper { - - private static final String TAG = "UIManagerHelper"; - public static final int PADDING_START_INDEX = 0; - public static final int PADDING_END_INDEX = 1; - public static final int PADDING_TOP_INDEX = 2; - public static final int PADDING_BOTTOM_INDEX = 3; - - /** - * @return a {@link UIManager} that can handle the react tag received by parameter. - */ - @Nullable - public static UIManager getUIManagerForReactTag(ReactContext context, int reactTag) { - return getUIManager(context, getUIManagerType(reactTag)); - } - - /** - * @return a {@link UIManager} that can handle the react tag received by parameter. - */ - @Nullable - public static UIManager getUIManager(ReactContext context, @UIManagerType int uiManagerType) { - return getUIManager(context, uiManagerType, true); - } - - @Nullable - private static UIManager getUIManager( - ReactContext context, - @UIManagerType int uiManagerType, - boolean returnNullIfCatalystIsInactive) { - if (ReactBuildConfig.UNSTABLE_ENABLE_MINIFY_LEGACY_ARCHITECTURE || context.isBridgeless()) { - @Nullable UIManager uiManager = context.getFabricUIManager(); - if (uiManager == null) { - ReactSoftExceptionLogger.logSoftException( - TAG, - new 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()) { - ReactSoftExceptionLogger.logSoftException( - TAG, - new ReactNoCrashSoftException( - "Cannot get UIManager because the context doesn't contain a CatalystInstance.")); - return null; - } - // TODO T60461551: add tests to verify emission of events when the ReactContext is being turn - // down. - if (!context.hasActiveReactInstance()) { - ReactSoftExceptionLogger.logSoftException( - TAG, - new ReactNoCrashSoftException( - "Cannot get UIManager because the context doesn't contain an active" - + " CatalystInstance.")); - if (returnNullIfCatalystIsInactive) { - return null; - } - } - CatalystInstance catalystInstance = context.getCatalystInstance(); - try { - return uiManagerType == FABRIC - ? context.getFabricUIManager() - : catalystInstance.getNativeModule(UIManagerModule.class); - } catch (IllegalArgumentException ex) { - // TODO T67518514 Clean this up once we migrate everything over to bridgeless mode - ReactSoftExceptionLogger.logSoftException( - TAG, - new ReactNoCrashSoftException( - "Cannot get UIManager for UIManagerType: " + uiManagerType)); - return catalystInstance.getNativeModule(UIManagerModule.class); - } - } - - /** - * @return the {@link EventDispatcher} that handles events for the reactTag received as a - * parameter. - */ - @Nullable - public static EventDispatcher getEventDispatcherForReactTag(ReactContext context, int reactTag) { - EventDispatcher eventDispatcher = getEventDispatcher(context, getUIManagerType(reactTag)); - if (eventDispatcher == null) { - ReactSoftExceptionLogger.logSoftException( - TAG, new IllegalStateException("Cannot get EventDispatcher for reactTag " + reactTag)); - } - return eventDispatcher; - } - - /** - * @return the {@link EventDispatcher} that handles events for the {@link UIManagerType} received - * as a parameter. - */ - @Nullable - public static EventDispatcher getEventDispatcher( - ReactContext context, @UIManagerType int uiManagerType) { - // TODO T67518514 Clean this up once we migrate everything over to bridgeless mode - if (context.isBridgeless()) { - if (context instanceof ThemedReactContext) { - context = ((ThemedReactContext) context).getReactApplicationContext(); - } - return ((EventDispatcherProvider) context).getEventDispatcher(); - } - UIManager uiManager = getUIManager(context, uiManagerType, false); - if (uiManager == null) { - ReactSoftExceptionLogger.logSoftException( - TAG, - new ReactNoCrashSoftException( - "Unable to find UIManager for UIManagerType " + uiManagerType)); - return null; - } - EventDispatcher eventDispatcher = (EventDispatcher) uiManager.getEventDispatcher(); - if (eventDispatcher == null) { - ReactSoftExceptionLogger.logSoftException( - TAG, - new IllegalStateException( - "Cannot get EventDispatcher for UIManagerType " + uiManagerType)); - } - return eventDispatcher; - } - - /** - * @return The {@link ReactContext} associated to the {@link View} received as a parameter. - *
We can't rely that the method View.getContext() will return the same context that was - * passed as a parameter during the construction of the View. - *
For example the AppCompatEditText class wraps the context received as a parameter in the - * constructor of the View into a TintContextWrapper object. See: - * https://android.googlesource.com/platform/frameworks/support/+/dd55716/v7/appcompat/src/android/support/v7/widget/AppCompatEditText.java#55 - */ - public static ReactContext getReactContext(View view) { - Context context = view.getContext(); - if (!(context instanceof ReactContext) && context instanceof ContextWrapper) { - context = ((ContextWrapper) context).getBaseContext(); - } - return (ReactContext) context; - } - - /** - * @return Gets the surfaceId for the {@link ThemedReactContext} associated with a View, if - * possible, and then call getSurfaceId on it. See above (getReactContext) for additional - * context. - *
For RootViews, the root's rootViewTag is returned - *
Returns -1 for non-Fabric views
- */
- public static int getSurfaceId(View view) {
- if (view instanceof ReactRoot) {
- ReactRoot rootView = (ReactRoot) view;
- return rootView.getUIManagerType() == UIManagerType.FABRIC ? rootView.getRootViewTag() : -1;
- }
-
- int reactTag = view.getId();
-
- // In non-Fabric we don't have (or use) SurfaceId
- if (getUIManagerType(reactTag) == UIManagerType.LEGACY) {
- return -1;
- }
-
- Context context = view.getContext();
- if (!(context instanceof ThemedReactContext) && context instanceof ContextWrapper) {
- context = ((ContextWrapper) context).getBaseContext();
- }
-
- int surfaceId = getSurfaceId(context);
- if (surfaceId == -1) {
- // All Fabric-managed Views (should) have a ThemedReactContext attached.
- ReactSoftExceptionLogger.logSoftException(
- TAG,
- new IllegalStateException(
- "Fabric View [" + reactTag + "] does not have SurfaceId associated with it"));
- }
- return surfaceId;
- }
-
- public static int getSurfaceId(Context context) {
- if (context instanceof ThemedReactContext) {
- return ((ThemedReactContext) context).getSurfaceId();
- }
- return -1;
- }
-
- /**
- * @return the default padding used by Android EditText's. This method returns the padding in an
- * array to avoid extra classloading during hot-path of RN Android.
- */
- public static float[] getDefaultTextInputPadding(Context context) {
- EditText editText = new EditText(context);
- float[] padding = new float[4];
- padding[PADDING_START_INDEX] = PixelUtil.toDIPFromPixel(ViewCompat.getPaddingStart(editText));
- padding[PADDING_END_INDEX] = PixelUtil.toDIPFromPixel(ViewCompat.getPaddingEnd(editText));
- padding[PADDING_TOP_INDEX] = PixelUtil.toDIPFromPixel(editText.getPaddingTop());
- padding[PADDING_BOTTOM_INDEX] = PixelUtil.toDIPFromPixel(editText.getPaddingBottom());
- return padding;
- }
-}
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
new file mode 100644
index 00000000000000..5fe9fa691189b7
--- /dev/null
+++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerHelper.kt
@@ -0,0 +1,232 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("DEPRECATION") // CatalystInstance is deprecated
+
+package com.facebook.react.uimanager
+
+import android.content.Context
+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
+
+/** Helper class for [UIManager]. */
+public object UIManagerHelper {
+ private const val TAG = "UIManagerHelper"
+ public const val PADDING_START_INDEX: Int = 0
+ public const val PADDING_END_INDEX: Int = 1
+ public const val PADDING_TOP_INDEX: Int = 2
+ public const val PADDING_BOTTOM_INDEX: Int = 3
+
+ /** @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))
+
+ /** @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()) {
+ ReactSoftExceptionLogger.logSoftException(
+ TAG,
+ ReactNoCrashSoftException(
+ "Cannot get UIManager because the context doesn't contain a CatalystInstance."))
+ return null
+ }
+ // TODO T60461551: add tests to verify emission of events when the ReactContext is being turn
+ // down.
+ if (!context.hasActiveReactInstance()) {
+ ReactSoftExceptionLogger.logSoftException(
+ TAG,
+ ReactNoCrashSoftException(
+ "Cannot get UIManager because the context doesn't contain an active" +
+ " CatalystInstance."))
+ if (returnNullIfCatalystIsInactive) {
+ return null
+ }
+ }
+ val catalystInstance: CatalystInstance = context.getCatalystInstance()
+ try {
+ return if (uiManagerType == UIManagerType.Companion.FABRIC) context.getFabricUIManager()
+ else catalystInstance.getNativeModule