diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.kt index f7d2d4d6557..21cf94272ec 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.kt @@ -20,7 +20,7 @@ public interface UIManager : PerformanceCounter { @UiThread @ThreadConfined(ThreadConfined.UI) @Deprecated("") - public fun addRootView(rootView: T, initialProps: WritableMap?): Int + public fun addRootView(rootView: T, initialProps: WritableMap?): Int /** Registers a new root view with width and height. */ @AnyThread @@ -92,7 +92,7 @@ public interface UIManager : PerformanceCounter { */ @UiThread @ThreadConfined(ThreadConfined.UI) - public fun synchronouslyUpdateViewOnUIThread(reactTag: Int, props: ReadableMap?) + public fun synchronouslyUpdateViewOnUIThread(reactTag: Int, props: ReadableMap) /** * Dispatch an accessibility event to a view asynchronously. @@ -109,14 +109,14 @@ public interface UIManager : PerformanceCounter { * * @param listener */ - public fun addUIManagerEventListener(listener: UIManagerListener?) + public fun addUIManagerEventListener(listener: UIManagerListener) /** * Unregister a [UIManagerListener] from this UIManager to stop receiving lifecycle callbacks. * * @param listener */ - public fun removeUIManagerEventListener(listener: UIManagerListener?) + public fun removeUIManagerEventListener(listener: UIManagerListener) /** * Resolves a view based on its reactTag. Do not mutate properties on this view that are already diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index e41d5e928e2..64b5851459a 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -25,10 +25,11 @@ import android.os.SystemClock; import android.view.View; import android.view.accessibility.AccessibilityEvent; import androidx.annotation.AnyThread; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.UiThread; import com.facebook.common.logging.FLog; +import com.facebook.infer.annotation.Assertions; +import com.facebook.infer.annotation.Nullsafe; import com.facebook.infer.annotation.ThreadConfined; import com.facebook.proguard.annotations.DoNotStripAny; import com.facebook.react.bridge.ColorPropConverter; @@ -97,6 +98,7 @@ import java.util.concurrent.CopyOnWriteArrayList; * We instruct ProGuard not to strip out any fields or methods, because many of these methods are * only called through the JNI from Cxx so it appears that most of this class is "unused". */ +@Nullsafe(Nullsafe.Mode.LOCAL) @SuppressLint("MissingNativeLoadLibrary") @DoNotStripAny public class FabricUIManager @@ -106,8 +108,7 @@ public class FabricUIManager // The IS_DEVELOPMENT_ENVIRONMENT variable is used to log extra data when running fabric in a // development environment. DO NOT ENABLE THIS ON PRODUCTION OR YOU WILL BE FIRED! public static final boolean IS_DEVELOPMENT_ENVIRONMENT = false && ReactBuildConfig.DEBUG; - // NULLSAFE_FIXME[Field Not Initialized] - public DevToolsReactPerfLogger mDevToolsReactPerfLogger; + public @Nullable DevToolsReactPerfLogger mDevToolsReactPerfLogger; private static final DevToolsReactPerfLogger.DevToolsReactPerfLoggerListener FABRIC_PERF_LOGGER = commitPoint -> { @@ -160,27 +161,24 @@ public class FabricUIManager } @Nullable private FabricUIManagerBinding mBinding; - @NonNull private final ReactApplicationContext mReactApplicationContext; - @NonNull private final MountingManager mMountingManager; - @NonNull private final FabricEventDispatcher mEventDispatcher; - @NonNull private final MountItemDispatcher mMountItemDispatcher; - @NonNull private final ViewManagerRegistry mViewManagerRegistry; + private final ReactApplicationContext mReactApplicationContext; + private final MountingManager mMountingManager; + private final FabricEventDispatcher mEventDispatcher; + private final MountItemDispatcher mMountItemDispatcher; + private final ViewManagerRegistry mViewManagerRegistry; - @NonNull private final BatchEventDispatchedListener mBatchEventDispatchedListener; + private final BatchEventDispatchedListener mBatchEventDispatchedListener; - @NonNull private final CopyOnWriteArrayList mListeners = new CopyOnWriteArrayList<>(); private boolean mMountNotificationScheduled = false; private List mSurfaceIdsWithPendingMountNotification = new ArrayList<>(); @ThreadConfined(UI) - @NonNull private final DispatchUIFrameCallback mDispatchUIFrameCallback; /** Set of events sent synchronously during the current frame render. Cleared after each frame. */ @ThreadConfined(UI) - @NonNull private final Set mSynchronousEvents = new HashSet<>(); /** @@ -218,9 +216,9 @@ public class FabricUIManager @Nullable private InteropUIBlockListener mInteropUIBlockListener; public FabricUIManager( - @NonNull ReactApplicationContext reactContext, - @NonNull ViewManagerRegistry viewManagerRegistry, - @NonNull BatchEventDispatchedListener batchEventDispatchedListener) { + ReactApplicationContext reactContext, + ViewManagerRegistry viewManagerRegistry, + BatchEventDispatchedListener batchEventDispatchedListener) { mDispatchUIFrameCallback = new DispatchUIFrameCallback(reactContext); mReactApplicationContext = reactContext; mMountingManager = new MountingManager(viewManagerRegistry, mMountItemExecutor); @@ -238,8 +236,8 @@ public class FabricUIManager @UiThread @ThreadConfined(UI) @Deprecated - // NULLSAFE_FIXME[Inconsistent Subclass Parameter Annotation] - public int addRootView(final T rootView, final WritableMap initialProps) { + public int addRootView( + final T rootView, final @Nullable WritableMap initialProps) { ReactSoftExceptionLogger.logSoftException( TAG, new IllegalViewOperationException( @@ -256,7 +254,7 @@ public class FabricUIManager if (ReactNativeFeatureFlags.enableFabricLogs()) { FLog.d(TAG, "Starting surface for module: %s and reactTag: %d", moduleName, rootTag); } - // NULLSAFE_FIXME[Nullable Dereference] + Assertions.assertNotNull(mBinding, "Binding in FabricUIManager is null"); mBinding.startSurface(rootTag, moduleName, (NativeMap) initialProps); return rootTag; } @@ -264,11 +262,10 @@ public class FabricUIManager @Override @AnyThread @ThreadConfined(ANY) - // NULLSAFE_FIXME[Inconsistent Subclass Parameter Annotation] public int startSurface( final T rootView, final String moduleName, - final WritableMap initialProps, + final @Nullable WritableMap initialProps, int widthMeasureSpec, int heightMeasureSpec) { final int rootTag = ((ReactRoot) rootView).getRootViewTag(); @@ -287,7 +284,7 @@ public class FabricUIManager Point viewportOffset = UiThreadUtil.isOnUiThread() ? RootViewUtil.getViewportOffset(rootView) : new Point(0, 0); - // NULLSAFE_FIXME[Nullable Dereference] + Assertions.assertNotNull(mBinding, "Binding in FabricUIManager is null"); mBinding.startSurfaceWithConstraints( rootTag, moduleName, @@ -313,7 +310,7 @@ public class FabricUIManager new ThemedReactContext( mReactApplicationContext, context, surfaceHandler.getModuleName(), rootTag); mMountingManager.startSurface(rootTag, reactContext, rootView); - // NULLSAFE_FIXME[Nullable Dereference] + Assertions.assertNotNull(mBinding, "Binding in FabricUIManager is null"); mBinding.startSurfaceWithSurfaceHandler(rootTag, surfaceHandler, rootView != null); } @@ -338,7 +335,7 @@ public class FabricUIManager } mMountingManager.stopSurface(surfaceHandler.getSurfaceId()); - // NULLSAFE_FIXME[Nullable Dereference] + Assertions.assertNotNull(mBinding, "Binding in FabricUIManager is null"); mBinding.stopSurfaceWithSurfaceHandler(surfaceHandler); } @@ -358,7 +355,7 @@ public class FabricUIManager // Communicate stopSurface to Cxx - causes an empty ShadowTree to be committed, // but all mounting instructions will be ignored because stopSurface was called // on the MountingManager - // NULLSAFE_FIXME[Nullable Dereference] + Assertions.assertNotNull(mBinding, "Binding in FabricUIManager is null"); mBinding.stopSurface(surfaceID); } @@ -409,8 +406,9 @@ public class FabricUIManager mReactApplicationContext.removeLifecycleEventListener(this); onHostPause(); - // NULLSAFE_FIXME[Nullable Dereference] - mBinding.unregister(); + if (mBinding != null) { + mBinding.unregister(); + } mBinding = null; ViewManagerPropertyUpdater.clear(); @@ -454,7 +452,6 @@ public class FabricUIManager } } - @NonNull private InteropUIBlockListener getInteropUIBlockListener() { if (mInteropUIBlockListener == null) { mInteropUIBlockListener = new InteropUIBlockListener(); @@ -541,12 +538,13 @@ public class FabricUIManager return 0; } context = surfaceMountingManager.getContext(); + Assertions.assertNotNull( + context, "Context in SurfaceMountingManager is null. surfaceId: " + surfaceId); } else { context = mReactApplicationContext; } return mMountingManager.measure( - // NULLSAFE_FIXME[Parameter Not Nullable] context, componentName, localData, @@ -580,13 +578,14 @@ public class FabricUIManager return 0; } context = surfaceMountingManager.getContext(); + Assertions.assertNotNull( + context, "Context in SurfaceMountingManager is null. surfaceId: " + surfaceId); } else { context = mReactApplicationContext; } // TODO: replace ReadableNativeMap -> ReadableMapBuffer return mMountingManager.measureMapBuffer( - // NULLSAFE_FIXME[Parameter Not Nullable] context, componentName, localData, @@ -623,13 +622,11 @@ public class FabricUIManager } @Override - // NULLSAFE_FIXME[Inconsistent Subclass Parameter Annotation] public void addUIManagerEventListener(UIManagerListener listener) { mListeners.add(listener); } @Override - // NULLSAFE_FIXME[Inconsistent Subclass Parameter Annotation] public void removeUIManagerEventListener(UIManagerListener listener) { mListeners.remove(listener); } @@ -637,9 +634,7 @@ public class FabricUIManager @Override @UiThread @ThreadConfined(UI) - // NULLSAFE_FIXME[Inconsistent Subclass Parameter Annotation] - public void synchronouslyUpdateViewOnUIThread( - final int reactTag, @NonNull final ReadableMap props) { + public void synchronouslyUpdateViewOnUIThread(final int reactTag, final ReadableMap props) { UiThreadUtil.assertOnUiThread(); int commitNumber = mCurrentSynchronousCommitNumber++; @@ -670,7 +665,7 @@ public class FabricUIManager MountItem synchronousMountItem = new MountItem() { @Override - public void execute(@NonNull MountingManager mountingManager) { + public void execute(MountingManager mountingManager) { try { mountingManager.updateProps(reactTag, props); } catch (Exception ex) { @@ -688,7 +683,6 @@ public class FabricUIManager return View.NO_ID; } - @NonNull @Override public String toString() { String propsString = @@ -793,11 +787,14 @@ public class FabricUIManager // calls scheduleMountItems with a BatchMountItem. long scheduleMountItemStartTime = SystemClock.uptimeMillis(); boolean isBatchMountItem = mountItem instanceof BatchMountItem; - boolean shouldSchedule = - // NULLSAFE_FIXME[Nullable Dereference] - (isBatchMountItem && !((BatchMountItem) mountItem).isBatchEmpty()) - || (!isBatchMountItem && mountItem != null); - + boolean shouldSchedule = false; + if (isBatchMountItem) { + BatchMountItem batchMountItem = (BatchMountItem) mountItem; + Assertions.assertNotNull(batchMountItem, "BatchMountItem is null"); + shouldSchedule = !batchMountItem.isBatchEmpty(); + } else { + shouldSchedule = mountItem != null; + } // In case of sync rendering, this could be called on the UI thread. Otherwise, // it should ~always be called on the JS thread. for (UIManagerListener listener : mListeners) { @@ -813,7 +810,7 @@ public class FabricUIManager } if (shouldSchedule) { - // NULLSAFE_FIXME[Parameter Not Nullable] + Assertions.assertNotNull(mountItem, "MountItem is null"); mMountItemDispatcher.addMountItem(mountItem); Runnable runnable = new GuardedRunnable(mReactApplicationContext) { @@ -910,7 +907,7 @@ public class FabricUIManager doLeftAndRightSwapInRTL = I18nUtil.getInstance().doLeftAndRightSwapInRTL(context); } - // NULLSAFE_FIXME[Nullable Dereference] + Assertions.assertNotNull(mBinding, "Binding in FabricUIManager is null"); mBinding.setConstraints( surfaceId, getMinSize(widthMeasureSpec), @@ -924,11 +921,10 @@ public class FabricUIManager } @Override - public View resolveView(int reactTag) { + public @Nullable View resolveView(int reactTag) { UiThreadUtil.assertOnUiThread(); SurfaceMountingManager surfaceManager = mMountingManager.getSurfaceManagerForView(reactTag); - // NULLSAFE_FIXME[Return Not Nullable] return surfaceManager == null ? null : surfaceManager.getView(reactTag); } @@ -971,7 +967,7 @@ public class FabricUIManager public void receiveEvent( int surfaceId, int reactTag, - @NonNull String eventName, + String eventName, boolean canCoalesceEvent, @Nullable WritableMap params, @EventCategoryDef int eventCategory, @@ -1024,7 +1020,6 @@ public class FabricUIManager } @Override - @NonNull public EventDispatcher getEventDispatcher() { return mEventDispatcher; } @@ -1137,7 +1132,7 @@ public class FabricUIManager mMountItemDispatcher.addMountItem( new MountItem() { @Override - public void execute(@NonNull MountingManager mountingManager) { + public void execute(MountingManager mountingManager) { SurfaceMountingManager surfaceMountingManager = mountingManager.getSurfaceManager(surfaceId); if (surfaceMountingManager != null) { @@ -1154,7 +1149,6 @@ public class FabricUIManager return surfaceId; } - @NonNull @SuppressLint("DefaultLocale") @Override public String toString() { @@ -1171,7 +1165,7 @@ public class FabricUIManager mMountItemDispatcher.addMountItem( new MountItem() { @Override - public void execute(@NonNull MountingManager mountingManager) { + public void execute(MountingManager mountingManager) { mountingManager.clearJSResponder(); } @@ -1180,7 +1174,6 @@ public class FabricUIManager return View.NO_ID; } - @NonNull @Override public String toString() { return "CLEAR_JS_RESPONDER"; @@ -1329,7 +1322,7 @@ public class FabricUIManager @ThreadConfined(UI) private boolean mIsScheduled = false; - private DispatchUIFrameCallback(@NonNull ReactContext reactContext) { + private DispatchUIFrameCallback(ReactContext reactContext) { super(reactContext); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManagerBinding.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManagerBinding.kt index 13c448525a2..7b9f9ee4500 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManagerBinding.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManagerBinding.kt @@ -33,12 +33,12 @@ internal class FabricUIManagerBinding : HybridClassBase() { componentsRegistry: ComponentFactory, ) - external fun startSurface(surfaceId: Int, moduleName: String, initialProps: NativeMap) + external fun startSurface(surfaceId: Int, moduleName: String, initialProps: NativeMap?) external fun startSurfaceWithConstraints( surfaceId: Int, moduleName: String, - initialProps: NativeMap, + initialProps: NativeMap?, minWidth: Float, maxWidth: Float, minHeight: Float, diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp index e16008a27bc..b3813b0a0ed 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp @@ -172,7 +172,9 @@ void FabricUIManagerBinding::startSurface( auto surfaceHandler = SurfaceHandler{moduleName->toStdString(), surfaceId}; surfaceHandler.setContextContainer(scheduler->getContextContainer()); - surfaceHandler.setProps(initialProps->consume()); + if (initialProps != nullptr) { + surfaceHandler.setProps(initialProps->consume()); + } surfaceHandler.constraintLayout({}, layoutContext); scheduler->registerSurface(surfaceHandler); @@ -241,7 +243,9 @@ void FabricUIManagerBinding::startSurfaceWithConstraints( auto surfaceHandler = SurfaceHandler{moduleName->toStdString(), surfaceId}; surfaceHandler.setContextContainer(scheduler->getContextContainer()); - surfaceHandler.setProps(initialProps->consume()); + if (initialProps != nullptr) { + surfaceHandler.setProps(initialProps->consume()); + } surfaceHandler.constraintLayout(constraints, context); scheduler->registerSurface(surfaceHandler); diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeUIManager.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeUIManager.kt index 49ba0848635..f0841bf89d0 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeUIManager.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/fakes/FakeUIManager.kt @@ -30,7 +30,7 @@ class FakeUIManager : UIManager, UIBlockViewResolver { } @Deprecated("") - override fun addRootView(rootView: T, initialProps: WritableMap?): Int { + override fun addRootView(rootView: T, initialProps: WritableMap?): Int { error("Not yet implemented") } @@ -69,7 +69,7 @@ class FakeUIManager : UIManager, UIBlockViewResolver { override val eventDispatcher: EventDispatcher get() = TODO("Not yet implemented") - override fun synchronouslyUpdateViewOnUIThread(reactTag: Int, props: ReadableMap?) { + override fun synchronouslyUpdateViewOnUIThread(reactTag: Int, props: ReadableMap) { error("Not yet implemented") } @@ -77,11 +77,11 @@ class FakeUIManager : UIManager, UIBlockViewResolver { error("Not yet implemented") } - override fun addUIManagerEventListener(listener: UIManagerListener?) { + override fun addUIManagerEventListener(listener: UIManagerListener) { error("Not yet implemented") } - override fun removeUIManagerEventListener(listener: UIManagerListener?) { + override fun removeUIManagerEventListener(listener: UIManagerListener) { error("Not yet implemented") }