diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/FabricViewStateManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/FabricViewStateManager.java
deleted file mode 100644
index 2b096b1bbf0..00000000000
--- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/FabricViewStateManager.java
+++ /dev/null
@@ -1,85 +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 androidx.annotation.Nullable;
-import com.facebook.common.logging.FLog;
-import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.bridge.WritableMap;
-
-/**
- * This is a helper base class for ViewGroups that use Fabric State.
- *
- *
Reason to use this: UpdateState calls from the View layer to the Fabric core can fail, and
- * optionally Fabric will call a "failure callback" if that happens. This class abstracts that and
- * makes it easier ensure that State in Fabric is always up-to-date.
- *
- *
1. Whenever ViewManager.updateState is called, call View.setStateWrapper. 2. Instead of
- * calling StateWrapper.updateState directly, call View.setState and it will automatically keep
- * retrying the UpdateState call until it succeeds; or you call setState again; or the View layer is
- * updated with a newer StateWrapper.
- */
-public class FabricViewStateManager {
- private static final String TAG = "FabricViewStateManager";
-
- public interface HasFabricViewStateManager {
- FabricViewStateManager getFabricViewStateManager();
- }
-
- public interface StateUpdateCallback {
- WritableMap getStateUpdate();
- }
-
- @Nullable private StateWrapper mStateWrapper = null;
-
- public void setStateWrapper(StateWrapper stateWrapper) {
- mStateWrapper = stateWrapper;
- }
-
- public boolean hasStateWrapper() {
- return mStateWrapper != null;
- }
-
- private void setState(
- @Nullable final StateWrapper stateWrapper,
- final StateUpdateCallback stateUpdateCallback,
- final int numTries) {
- // The StateWrapper will change, breaking the async loop, whenever the UpdateState MountItem
- // is executed.
- // The caller is responsible for detecting if data is up-to-date, and doing nothing, or
- // detecting if state is stale and calling setState again.
- if (stateWrapper == null) {
- FLog.e(TAG, "setState called without a StateWrapper");
- return;
- }
- if (stateWrapper != mStateWrapper) {
- return;
- }
- // We bail out after an arbitrary number of tries. In practice this should never go higher
- // than 2 or 3, but there's nothing guaranteeing that.
- if (numTries > 60) {
- return;
- }
-
- @Nullable WritableMap stateUpdate = stateUpdateCallback.getStateUpdate();
- if (stateUpdate == null) {
- return;
- }
-
- // TODO: State update cannot fail; remove `failureRunnable` and custom retrying logic.
- stateWrapper.updateState(stateUpdate);
- }
-
- public void setState(final StateUpdateCallback stateUpdateCallback) {
- setState(mStateWrapper, stateUpdateCallback, 0);
- }
-
- public @Nullable ReadableMap getStateData() {
- return mStateWrapper != null ? mStateWrapper.getStateData() : null;
- }
-}
diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java
index 15ce94cb0ad..74c6b8e707c 100644
--- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java
+++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostManager.java
@@ -167,7 +167,7 @@ public class ReactModalHostManager extends ViewGroupManager
@Override
public Object updateState(
ReactModalHostView view, ReactStylesDiffMap props, StateWrapper stateWrapper) {
- view.getFabricViewStateManager().setStateWrapper(stateWrapper);
+ view.setStateWrapper(stateWrapper);
Point modalSize = ModalHostHelper.getModalHostSize(view.getContext());
view.updateState(modalSize.x, modalSize.y);
return null;
diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java
index d6320d42b72..2b3de095d40 100644
--- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java
+++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.java
@@ -36,11 +36,11 @@ import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.common.annotations.VisibleForTesting;
import com.facebook.react.config.ReactFeatureFlags;
-import com.facebook.react.uimanager.FabricViewStateManager;
import com.facebook.react.uimanager.JSPointerDispatcher;
import com.facebook.react.uimanager.JSTouchDispatcher;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.RootView;
+import com.facebook.react.uimanager.StateWrapper;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.events.EventDispatcher;
@@ -63,8 +63,7 @@ import java.util.ArrayList;
* around addition and removal of views to the DialogRootViewGroup.
*
*/
-public class ReactModalHostView extends ViewGroup
- implements LifecycleEventListener, FabricViewStateManager.HasFabricViewStateManager {
+public class ReactModalHostView extends ViewGroup implements LifecycleEventListener {
private static final String TAG = "ReactModalHost";
@@ -395,11 +394,15 @@ public class ReactModalHostView extends ViewGroup
}
}
- @Override
- public FabricViewStateManager getFabricViewStateManager() {
- return mHostView.getFabricViewStateManager();
+ @Nullable
+ public StateWrapper getStateWrapper() {
+ return mHostView.getStateWrapper();
}
+ public void setStateWrapper(StateWrapper stateWrapper) {
+ mHostView.setStateWrapper(stateWrapper);
+ };
+
public void updateState(final int width, final int height) {
mHostView.updateState(width, height);
}
@@ -415,14 +418,13 @@ public class ReactModalHostView extends ViewGroup
* styleHeight on the LayoutShadowNode to be the window size. This is done through the
* UIManagerModule, and will then cause the children to layout as if they can fill the window.
*/
- static class DialogRootViewGroup extends ReactViewGroup
- implements RootView, FabricViewStateManager.HasFabricViewStateManager {
+ static class DialogRootViewGroup extends ReactViewGroup implements RootView {
private boolean hasAdjustedSize = false;
private int viewWidth;
private int viewHeight;
private EventDispatcher mEventDispatcher;
- private final FabricViewStateManager mFabricViewStateManager = new FabricViewStateManager();
+ private StateWrapper mStateWrapper = null;
private final JSTouchDispatcher mJSTouchDispatcher = new JSTouchDispatcher(this);
@Nullable private JSPointerDispatcher mJSPointerDispatcher;
@@ -450,7 +452,7 @@ public class ReactModalHostView extends ViewGroup
if (getChildCount() > 0) {
hasAdjustedSize = false;
final int viewTag = getChildAt(0).getId();
- if (mFabricViewStateManager.hasStateWrapper()) {
+ if (mStateWrapper != null) {
// This will only be called under Fabric
updateState(viewWidth, viewHeight);
} else {
@@ -485,7 +487,7 @@ public class ReactModalHostView extends ViewGroup
// Check incoming state values. If they're already the correct value, return early to prevent
// infinite UpdateState/SetState loop.
- ReadableMap currentState = getFabricViewStateManager().getStateData();
+ ReadableMap currentState = mStateWrapper.getStateData();
if (currentState != null) {
float delta = (float) 0.9;
float stateScreenHeight =
@@ -501,16 +503,12 @@ public class ReactModalHostView extends ViewGroup
}
}
- mFabricViewStateManager.setState(
- new FabricViewStateManager.StateUpdateCallback() {
- @Override
- public WritableMap getStateUpdate() {
- WritableMap map = new WritableNativeMap();
- map.putDouble("screenWidth", realWidth);
- map.putDouble("screenHeight", realHeight);
- return map;
- }
- });
+ if (mStateWrapper != null) {
+ WritableMap newStateData = new WritableNativeMap();
+ newStateData.putDouble("screenWidth", realWidth);
+ newStateData.putDouble("screenHeight", realHeight);
+ mStateWrapper.updateState(newStateData);
+ }
}
@Override
@@ -589,9 +587,13 @@ public class ReactModalHostView extends ViewGroup
// even when some other view disallow that
}
- @Override
- public FabricViewStateManager getFabricViewStateManager() {
- return mFabricViewStateManager;
+ @Nullable
+ public StateWrapper getStateWrapper() {
+ return mStateWrapper;
+ }
+
+ public void setStateWrapper(StateWrapper stateWrapper) {
+ mStateWrapper = stateWrapper;
}
}
}
diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java
index e5a9e12e4bc..483ff24e0d9 100644
--- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java
+++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java
@@ -35,18 +35,19 @@ import com.facebook.infer.annotation.Assertions;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.common.build.ReactBuildConfig;
import com.facebook.react.modules.i18nmanager.I18nUtil;
-import com.facebook.react.uimanager.FabricViewStateManager;
import com.facebook.react.uimanager.MeasureSpecAssertions;
import com.facebook.react.uimanager.PointerEvents;
import com.facebook.react.uimanager.ReactClippingViewGroup;
import com.facebook.react.uimanager.ReactClippingViewGroupHelper;
import com.facebook.react.uimanager.ReactOverflowViewWithInset;
+import com.facebook.react.uimanager.StateWrapper;
import com.facebook.react.uimanager.ViewProps;
import com.facebook.react.uimanager.events.NativeGestureUtil;
import com.facebook.react.views.scroll.ReactScrollViewHelper.HasFlingAnimator;
import com.facebook.react.views.scroll.ReactScrollViewHelper.HasScrollEventThrottle;
import com.facebook.react.views.scroll.ReactScrollViewHelper.HasScrollState;
import com.facebook.react.views.scroll.ReactScrollViewHelper.HasSmoothScroll;
+import com.facebook.react.views.scroll.ReactScrollViewHelper.HasStateWrapper;
import com.facebook.react.views.scroll.ReactScrollViewHelper.ReactScrollViewScrollState;
import com.facebook.react.views.view.ReactViewBackgroundManager;
import java.lang.reflect.Field;
@@ -58,9 +59,9 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
implements ReactClippingViewGroup,
ViewGroup.OnHierarchyChangeListener,
View.OnLayoutChangeListener,
- FabricViewStateManager.HasFabricViewStateManager,
ReactOverflowViewWithInset,
HasScrollState,
+ HasStateWrapper,
HasFlingAnimator,
HasScrollEventThrottle,
HasSmoothScroll {
@@ -106,7 +107,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
private boolean mPagedArrowScrolling = false;
private int pendingContentOffsetX = UNSET_CONTENT_OFFSET;
private int pendingContentOffsetY = UNSET_CONTENT_OFFSET;
- private final FabricViewStateManager mFabricViewStateManager = new FabricViewStateManager();
+ private StateWrapper mStateWrapper = null;
private final ReactScrollViewScrollState mReactScrollViewScrollState;
private final ValueAnimator DEFAULT_FLING_ANIMATOR = ObjectAnimator.ofInt(this, "scrollX", 0, 0);
private PointerEvents mPointerEvents = PointerEvents.AUTO;
@@ -1355,9 +1356,13 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
}
}
- @Override
- public FabricViewStateManager getFabricViewStateManager() {
- return mFabricViewStateManager;
+ @Nullable
+ public StateWrapper getStateWrapper() {
+ return mStateWrapper;
+ }
+
+ public void setStateWrapper(StateWrapper stateWrapper) {
+ mStateWrapper = stateWrapper;
}
@Override
diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java
index f148dcda3be..85f784833b5 100644
--- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java
+++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java
@@ -69,7 +69,7 @@ public class ReactHorizontalScrollViewManager extends ViewGroupManager sScrollListeners =
Collections.newSetFromMap(new WeakHashMap());
@@ -337,10 +342,7 @@ public class ReactScrollViewHelper {
* by calculate the "would be" initial velocity with internal friction to move to the point (x,
* y), then apply that to the animator.
*/
- public static <
- T extends
- ViewGroup & FabricViewStateManager.HasFabricViewStateManager & HasScrollState
- & HasFlingAnimator>
+ public static
void smoothScrollTo(final T scrollView, final int x, final int y) {
if (DEBUG_MODE) {
FLog.i(TAG, "smoothScrollTo[%d] x %d y %d", scrollView.getId(), x, y);
@@ -370,10 +372,7 @@ public class ReactScrollViewHelper {
}
/** Get current position or position after current animation finishes, if any. */
- public static <
- T extends
- ViewGroup & FabricViewStateManager.HasFabricViewStateManager & HasScrollState
- & HasFlingAnimator>
+ public static
int getNextFlingStartValue(
final T scrollView,
final int currentValue,
@@ -394,10 +393,7 @@ public class ReactScrollViewHelper {
: currentValue;
}
- public static <
- T extends
- ViewGroup & FabricViewStateManager.HasFabricViewStateManager & HasScrollState
- & HasFlingAnimator>
+ public static
boolean updateFabricScrollState(final T scrollView) {
return updateFabricScrollState(scrollView, scrollView.getScrollX(), scrollView.getScrollY());
}
@@ -405,10 +401,7 @@ public class ReactScrollViewHelper {
/**
* Called on any stabilized onScroll change to propagate content offset value to a Shadow Node.
*/
- public static <
- T extends
- ViewGroup & FabricViewStateManager.HasFabricViewStateManager & HasScrollState
- & HasFlingAnimator>
+ public static
boolean updateFabricScrollState(final T scrollView, final int scrollX, final int scrollY) {
if (DEBUG_MODE) {
FLog.i(
@@ -434,10 +427,7 @@ public class ReactScrollViewHelper {
return true;
}
- public static <
- T extends
- ViewGroup & FabricViewStateManager.HasFabricViewStateManager & HasScrollState
- & HasFlingAnimator>
+ public static
void forceUpdateState(final T scrollView) {
final ReactScrollViewScrollState scrollState = scrollView.getReactScrollViewScrollState();
final int scrollAwayPaddingTop = scrollState.getScrollAwayPaddingTop();
@@ -467,26 +457,21 @@ public class ReactScrollViewHelper {
fabricScrollX);
}
- scrollView
- .getFabricViewStateManager()
- .setState(
- new FabricViewStateManager.StateUpdateCallback() {
- @Override
- public WritableMap getStateUpdate() {
- WritableMap map = new WritableNativeMap();
- map.putDouble(CONTENT_OFFSET_LEFT, PixelUtil.toDIPFromPixel(scrollX));
- map.putDouble(CONTENT_OFFSET_TOP, PixelUtil.toDIPFromPixel(scrollY));
- map.putDouble(
- SCROLL_AWAY_PADDING_TOP, PixelUtil.toDIPFromPixel(scrollAwayPaddingTop));
- return map;
- }
- });
+ StateWrapper stateWrapper = scrollView.getStateWrapper();
+ if (stateWrapper != null) {
+ WritableMap newStateData = new WritableNativeMap();
+ newStateData.putDouble(CONTENT_OFFSET_LEFT, PixelUtil.toDIPFromPixel(scrollX));
+ newStateData.putDouble(CONTENT_OFFSET_TOP, PixelUtil.toDIPFromPixel(scrollY));
+ newStateData.putDouble(
+ SCROLL_AWAY_PADDING_TOP, PixelUtil.toDIPFromPixel(scrollAwayPaddingTop));
+ stateWrapper.updateState(newStateData);
+ }
}
public static <
T extends
- ViewGroup & FabricViewStateManager.HasFabricViewStateManager & HasScrollState
- & HasFlingAnimator & HasScrollEventThrottle>
+ ViewGroup & HasStateWrapper & HasScrollState & HasFlingAnimator
+ & HasScrollEventThrottle>
void updateStateOnScrollChanged(
final T scrollView, final float xVelocity, final float yVelocity) {
// Race an UpdateState with every onScroll. This makes it more likely that, in Fabric,
@@ -497,10 +482,7 @@ public class ReactScrollViewHelper {
emitScrollEvent(scrollView, xVelocity, yVelocity);
}
- public static <
- T extends
- ViewGroup & FabricViewStateManager.HasFabricViewStateManager & HasScrollState
- & HasFlingAnimator>
+ public static
void registerFlingAnimator(final T scrollView) {
scrollView
.getFlingAnimator()
@@ -530,10 +512,7 @@ public class ReactScrollViewHelper {
});
}
- public static <
- T extends
- ViewGroup & FabricViewStateManager.HasFabricViewStateManager & HasScrollState
- & HasFlingAnimator>
+ public static
Point predictFinalScrollPosition(
final T scrollView,
final int velocityX,
diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
index 33658e78788..af022790a81 100644
--- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
+++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
@@ -337,7 +337,7 @@ public class ReactScrollViewManager extends ViewGroupManager
@Override
public Object updateState(
ReactScrollView view, ReactStylesDiffMap props, StateWrapper stateWrapper) {
- view.getFabricViewStateManager().setStateWrapper(stateWrapper);
+ view.setStateWrapper(stateWrapper);
return null;
}
diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
index c0f793a8d7d..2a77990f9be 100644
--- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
+++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
@@ -8,7 +8,6 @@
package com.facebook.react.views.textinput;
import static com.facebook.react.uimanager.UIManagerHelper.getReactContext;
-import static com.facebook.react.views.text.TextAttributeProps.UNSET;
import android.content.ClipData;
import android.content.ClipboardManager;
@@ -50,8 +49,8 @@ import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactSoftExceptionLogger;
import com.facebook.react.common.build.ReactBuildConfig;
-import com.facebook.react.uimanager.FabricViewStateManager;
import com.facebook.react.uimanager.ReactAccessibilityDelegate;
+import com.facebook.react.uimanager.StateWrapper;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.react.views.text.CustomLetterSpacingSpan;
@@ -84,8 +83,7 @@ import java.util.Objects;
* called this explicitly. This is the default behavior on other platforms as well.
* VisibleForTesting from {@link TextInputEventsTestCase}.
*/
-public class ReactEditText extends AppCompatEditText
- implements FabricViewStateManager.HasFabricViewStateManager {
+public class ReactEditText extends AppCompatEditText {
private final InputMethodManager mInputMethodManager;
private final String TAG = ReactEditText.class.getSimpleName();
public static final boolean DEBUG_MODE = ReactBuildConfig.DEBUG && false;
@@ -126,7 +124,7 @@ public class ReactEditText extends AppCompatEditText
private ReactViewBackgroundManager mReactBackgroundManager;
- private final FabricViewStateManager mFabricViewStateManager = new FabricViewStateManager();
+ private StateWrapper mStateWrapper = null;
protected boolean mDisableTextDiffing = false;
protected boolean mIsSettingTextFromState = false;
@@ -926,9 +924,7 @@ public class ReactEditText extends AppCompatEditText
// view, we don't need to construct one or apply it at all - it provides no use in Fabric.
ReactContext reactContext = getReactContext(this);
- if (mFabricViewStateManager != null
- && !mFabricViewStateManager.hasStateWrapper()
- && !reactContext.isBridgeless()) {
+ if (mStateWrapper != null && !reactContext.isBridgeless()) {
final ReactTextInputLocalData localData = new ReactTextInputLocalData(this);
UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class);
@@ -1157,9 +1153,13 @@ public class ReactEditText extends AppCompatEditText
}
}
- @Override
- public FabricViewStateManager getFabricViewStateManager() {
- return mFabricViewStateManager;
+ @Nullable
+ public StateWrapper getStateWrapper() {
+ return mStateWrapper;
+ }
+
+ public void setStateWrapper(StateWrapper stateWrapper) {
+ mStateWrapper = stateWrapper;
}
/**
@@ -1170,7 +1170,7 @@ public class ReactEditText extends AppCompatEditText
*/
private void updateCachedSpannable() {
// Noops in non-Fabric
- if (mFabricViewStateManager == null || !mFabricViewStateManager.hasStateWrapper()) {
+ if (mStateWrapper == null) {
return;
}
// If this view doesn't have an ID yet, we don't have a cache key, so bail here
diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
index b27ace40cc9..8496a7d059e 100644
--- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
+++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
@@ -49,7 +49,6 @@ import com.facebook.react.common.ReactConstants;
import com.facebook.react.common.mapbuffer.MapBuffer;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.uimanager.BaseViewManager;
-import com.facebook.react.uimanager.FabricViewStateManager;
import com.facebook.react.uimanager.LayoutShadowNode;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.ReactStylesDiffMap;
@@ -1053,23 +1052,13 @@ public class ReactTextInputManager extends BaseViewManager