From 03d842391505c1342f8dfa1ae2d4e72923aa5281 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Thu, 16 May 2024 11:28:09 -0700 Subject: [PATCH] Remove CSSBackgroundDrawable.getResolvedLayoutDirection(), [RN][Android] Propagate layout direction to Android views Differential Revision: D57248417 --- .../ReactAndroid/api/ReactAndroid.api | 9 ++-- .../mounting/SurfaceMountingManager.java | 17 ++++++- .../mountitems/IntBufferBatchMountItem.java | 12 +++-- .../featureflags/ReactNativeFeatureFlags.kt | 8 +++- .../ReactNativeFeatureFlagsCxxAccessor.kt | 12 ++++- .../ReactNativeFeatureFlagsCxxInterop.kt | 4 +- .../ReactNativeFeatureFlagsDefaults.kt | 4 +- .../ReactNativeFeatureFlagsLocalAccessor.kt | 13 +++++- .../ReactNativeFeatureFlagsProvider.kt | 4 +- .../drawable/CSSBackgroundDrawable.java | 45 +++++++++---------- .../ReactHorizontalScrollContainerView.java | 13 +++++- .../scroll/ReactHorizontalScrollView.java | 12 ++++- .../react/views/view/ReactViewGroup.java | 20 +++------ .../react/fabric/FabricMountingManager.cpp | 23 +++++++--- .../JReactNativeFeatureFlagsCxxInterop.cpp | 16 ++++++- .../JReactNativeFeatureFlagsCxxInterop.h | 5 ++- .../featureflags/ReactNativeFeatureFlags.cpp | 6 ++- .../featureflags/ReactNativeFeatureFlags.h | 7 ++- .../ReactNativeFeatureFlagsAccessor.cpp | 26 +++++++++-- .../ReactNativeFeatureFlagsAccessor.h | 6 ++- .../ReactNativeFeatureFlagsDefaults.h | 6 ++- .../ReactNativeFeatureFlagsProvider.h | 3 +- .../NativeReactNativeFeatureFlags.cpp | 7 ++- .../NativeReactNativeFeatureFlags.h | 4 +- .../ReactNativeFeatureFlags.config.js | 4 ++ .../featureflags/ReactNativeFeatureFlags.js | 7 ++- .../specs/NativeReactNativeFeatureFlags.js | 3 +- 27 files changed, 217 insertions(+), 79 deletions(-) diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 0e01ff68d478f1..480748f43fcb01 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -2790,7 +2790,7 @@ public class com/facebook/react/fabric/mounting/SurfaceMountingManager { public fun setJSResponder (IIZ)V public fun stopSurface ()V public fun updateEventEmitter (ILcom/facebook/react/fabric/events/EventEmitterWrapper;)V - public fun updateLayout (IIIIIII)V + public fun updateLayout (IIIIIIII)V public fun updateOverflowInset (IIIII)V public fun updatePadding (IIIII)V public fun updateProps (ILcom/facebook/react/bridge/ReadableMap;)V @@ -5527,12 +5527,11 @@ public class com/facebook/react/uimanager/drawable/CSSBackgroundDrawable : andro public fun getComputedBorderRadius ()Lcom/facebook/react/uimanager/style/ComputedBorderRadius; public fun getDirectionAwareBorderInsets ()Landroid/graphics/RectF; public fun getFullBorderWidth ()F + public fun getLayoutDirection ()I public fun getOpacity ()I public fun getOutline (Landroid/graphics/Outline;)V - public fun getResolvedLayoutDirection ()I public fun hasRoundedBorders ()Z protected fun onBoundsChange (Landroid/graphics/Rect;)V - public fun onResolvedLayoutDirectionChanged (I)Z public fun paddingBoxPath ()Landroid/graphics/Path; public fun setAlpha (I)V public fun setBorderColor (IFF)V @@ -5542,9 +5541,9 @@ public class com/facebook/react/uimanager/drawable/CSSBackgroundDrawable : andro public fun setBorderWidth (IF)V public fun setColor (I)V public fun setColorFilter (Landroid/graphics/ColorFilter;)V + public fun setLayoutDirectionOverride (I)V public fun setRadius (F)V public fun setRadius (FI)V - public fun setResolvedLayoutDirection (I)Z } public abstract interface class com/facebook/react/uimanager/events/BatchEventDispatchedListener { @@ -6633,6 +6632,7 @@ public class com/facebook/react/views/scroll/OnScrollDispatchHelper { public class com/facebook/react/views/scroll/ReactHorizontalScrollContainerView : com/facebook/react/views/view/ReactViewGroup { public fun (Landroid/content/Context;)V + public fun getLayoutDirection ()I protected fun onLayout (ZIIII)V public fun setRemoveClippedSubviews (Z)V } @@ -7927,7 +7927,6 @@ public class com/facebook/react/views/view/ReactViewGroup : android/view/ViewGro public fun onInterceptTouchEvent (Landroid/view/MotionEvent;)Z protected fun onLayout (ZIIII)V protected fun onMeasure (II)V - public fun onRtlPropertiesChanged (I)V protected fun onSizeChanged (IIII)V public fun onTouchEvent (Landroid/view/MotionEvent;)Z public fun removeView (Landroid/view/View;)V diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java index dc7179653fe8f4..8494e84e2747e3 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java @@ -35,6 +35,7 @@ import com.facebook.react.fabric.events.EventEmitterWrapper; import com.facebook.react.fabric.mounting.MountingManager.MountItemExecutor; import com.facebook.react.fabric.mounting.mountitems.MountItem; +import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags; import com.facebook.react.modules.core.ReactChoreographer; import com.facebook.react.touch.JSResponderHandler; import com.facebook.react.uimanager.IViewGroupManager; @@ -934,7 +935,14 @@ public void sendAccessibilityEvent(int reactTag, int eventType) { @UiThread public void updateLayout( - int reactTag, int parentTag, int x, int y, int width, int height, int displayType) { + int reactTag, + int parentTag, + int x, + int y, + int width, + int height, + int displayType, + int layoutDirection) { if (isStopped()) { return; } @@ -950,6 +958,13 @@ public void updateLayout( throw new IllegalStateException("Unable to find View for tag: " + reactTag); } + if (ReactNativeFeatureFlags.setAndroidLayoutDirection()) { + viewToUpdate.setLayoutDirection( + layoutDirection == 1 + ? View.LAYOUT_DIRECTION_LTR + : layoutDirection == 2 ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_INHERIT); + } + viewToUpdate.measure( View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java index 45621a90dad79d..c574a2724c5640 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java @@ -20,6 +20,7 @@ import com.facebook.react.fabric.events.EventEmitterWrapper; import com.facebook.react.fabric.mounting.MountingManager; import com.facebook.react.fabric.mounting.SurfaceMountingManager; +import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags; import com.facebook.react.uimanager.StateWrapper; import com.facebook.systrace.Systrace; @@ -150,9 +151,14 @@ public void execute(MountingManager mountingManager) { int height = mIntBuffer[i++]; int displayType = mIntBuffer[i++]; - surfaceMountingManager.updateLayout( - reactTag, parentTag, x, y, width, height, displayType); - + if (ReactNativeFeatureFlags.setAndroidLayoutDirection()) { + int layoutDirection = mIntBuffer[i++]; + surfaceMountingManager.updateLayout( + reactTag, parentTag, x, y, width, height, displayType, layoutDirection); + } else { + surfaceMountingManager.updateLayout( + reactTag, parentTag, x, y, width, height, displayType, 0); + } } else if (type == INSTRUCTION_UPDATE_PADDING) { surfaceMountingManager.updatePadding( mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++]); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt index f9f30e2b8336cf..86994a57752517 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<0d5f4b26573154fb42c312b03c0dc6a7>> */ /** @@ -124,6 +124,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun preventDoubleTextMeasure(): Boolean = accessor.preventDoubleTextMeasure() + /** + * Propagate layout direction to Android views. + */ + @JvmStatic + public fun setAndroidLayoutDirection(): Boolean = accessor.setAndroidLayoutDirection() + /** * When enabled, it uses the modern fork of RuntimeScheduler that allows scheduling tasks with priorities from any thread. */ diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt index f772e19f96058b..db8a9ee7afd0a4 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<1b84e5fa96120a511db6f831afb73eab>> + * @generated SignedSource<<60f7a791ff3eb270c26ebf598f65d8d5>> */ /** @@ -36,6 +36,7 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso private var inspectorEnableModernCDPRegistryCache: Boolean? = null private var lazyAnimationCallbacksCache: Boolean? = null private var preventDoubleTextMeasureCache: Boolean? = null + private var setAndroidLayoutDirectionCache: Boolean? = null private var useModernRuntimeSchedulerCache: Boolean? = null private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null private var useStateAlignmentMechanismCache: Boolean? = null @@ -184,6 +185,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso return cached } + override fun setAndroidLayoutDirection(): Boolean { + var cached = setAndroidLayoutDirectionCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.setAndroidLayoutDirection() + setAndroidLayoutDirectionCache = cached + } + return cached + } + override fun useModernRuntimeScheduler(): Boolean { var cached = useModernRuntimeSchedulerCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt index 17981de89a8ecf..b825c6231c4ede 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<2cd7ab4688ca2179ba3a19e9a062f695>> + * @generated SignedSource<> */ /** @@ -60,6 +60,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun preventDoubleTextMeasure(): Boolean + @DoNotStrip @JvmStatic public external fun setAndroidLayoutDirection(): Boolean + @DoNotStrip @JvmStatic public external fun useModernRuntimeScheduler(): Boolean @DoNotStrip @JvmStatic public external fun useNativeViewConfigsInBridgelessMode(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt index acced5a1f2f691..5310224ea8d2d3 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -55,6 +55,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun preventDoubleTextMeasure(): Boolean = false + override fun setAndroidLayoutDirection(): Boolean = false + override fun useModernRuntimeScheduler(): Boolean = false override fun useNativeViewConfigsInBridgelessMode(): Boolean = false diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt index 3115aba8c89e16..9591d500f0e36d 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<48f657b282ef658ab7e9024f470d37ad>> + * @generated SignedSource<<8f6a50230ef99335baa5929070b94ddc>> */ /** @@ -40,6 +40,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces private var inspectorEnableModernCDPRegistryCache: Boolean? = null private var lazyAnimationCallbacksCache: Boolean? = null private var preventDoubleTextMeasureCache: Boolean? = null + private var setAndroidLayoutDirectionCache: Boolean? = null private var useModernRuntimeSchedulerCache: Boolean? = null private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null private var useStateAlignmentMechanismCache: Boolean? = null @@ -204,6 +205,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun setAndroidLayoutDirection(): Boolean { + var cached = setAndroidLayoutDirectionCache + if (cached == null) { + cached = currentProvider.setAndroidLayoutDirection() + accessedFeatureFlags.add("setAndroidLayoutDirection") + setAndroidLayoutDirectionCache = cached + } + return cached + } + override fun useModernRuntimeScheduler(): Boolean { var cached = useModernRuntimeSchedulerCache if (cached == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt index f7358b775cd1dd..72aea9d12aac86 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<0f3d31f94f4bded41936fe4ecafbdd4a>> + * @generated SignedSource<> */ /** @@ -55,6 +55,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun preventDoubleTextMeasure(): Boolean + @DoNotStrip public fun setAndroidLayoutDirection(): Boolean + @DoNotStrip public fun useModernRuntimeScheduler(): Boolean @DoNotStrip public fun useNativeViewConfigsInBridgelessMode(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CSSBackgroundDrawable.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CSSBackgroundDrawable.java index 4e795bf6f239ca..39a486d26ea3bb 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CSSBackgroundDrawable.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CSSBackgroundDrawable.java @@ -7,6 +7,7 @@ package com.facebook.react.uimanager.drawable; +import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; @@ -119,7 +120,9 @@ private enum BorderStyle { private BorderRadiusStyle mBorderRadius = new BorderRadiusStyle(); private ComputedBorderRadius mComputedBorderRadius = new ComputedBorderRadius(); private final Context mContext; - private int mLayoutDirection; + + // Should be removed after migrating to Android layout direction. + private int mLayoutDirectionOverride = -1; public CSSBackgroundDrawable(Context context) { mContext = context; @@ -163,6 +166,19 @@ public void setColorFilter(ColorFilter cf) { // do nothing } + @Deprecated + public void setLayoutDirectionOverride(int layoutDirection) { + if (mLayoutDirectionOverride != layoutDirection) { + mLayoutDirectionOverride = layoutDirection; + } + } + + @Override + @SuppressLint("WrongConstant") + public int getLayoutDirection() { + return mLayoutDirectionOverride == -1 ? super.getLayoutDirection() : mLayoutDirectionOverride; + } + @Override public int getOpacity() { return (Color.alpha(mColor) * mAlpha) >> 8; @@ -292,25 +308,6 @@ public void setColor(int color) { invalidateSelf(); } - /** Similar to Drawable.getLayoutDirection, but available in APIs < 23. */ - public int getResolvedLayoutDirection() { - return mLayoutDirection; - } - - /** Similar to Drawable.setLayoutDirection, but available in APIs < 23. */ - public boolean setResolvedLayoutDirection(int layoutDirection) { - if (mLayoutDirection != layoutDirection) { - mLayoutDirection = layoutDirection; - return onResolvedLayoutDirectionChanged(layoutDirection); - } - return false; - } - - /** Similar to Drawable.onLayoutDirectionChanged, but available in APIs < 23. */ - public boolean onResolvedLayoutDirectionChanged(int layoutDirection) { - return false; - } - @VisibleForTesting public int getColor() { return mColor; @@ -392,7 +389,7 @@ private void drawRoundedBackgroundWithBorders(Canvas canvas) { // Clip inner border canvas.clipPath(mInnerClipPathForBorderRadius, Region.Op.DIFFERENCE); - final boolean isRTL = getResolvedLayoutDirection() == View.LAYOUT_DIRECTION_RTL; + final boolean isRTL = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; int colorStart = getBorderColor(Spacing.START); int colorEnd = getBorderColor(Spacing.END); @@ -591,7 +588,7 @@ private void updatePath() { mComputedBorderRadius = mBorderRadius.resolve( - mLayoutDirection, + getLayoutDirection(), mContext, mOuterClipTempRectForBorderRadius.width(), mOuterClipTempRectForBorderRadius.height()); @@ -1080,7 +1077,7 @@ private void drawRectangularBackgroundWithBorders(Canvas canvas) { colorTop = colorBlockStart; } - final boolean isRTL = getResolvedLayoutDirection() == View.LAYOUT_DIRECTION_RTL; + final boolean isRTL = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; int colorStart = getBorderColor(Spacing.START); int colorEnd = getBorderColor(Spacing.END); @@ -1305,7 +1302,7 @@ public RectF getDirectionAwareBorderInsets() { float borderRightWidth = getBorderWidthOrDefaultTo(borderWidth, Spacing.RIGHT); if (mBorderWidth != null) { - final boolean isRTL = getResolvedLayoutDirection() == View.LAYOUT_DIRECTION_RTL; + final boolean isRTL = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; float borderStartWidth = mBorderWidth.getRaw(Spacing.START); float borderEndWidth = mBorderWidth.getRaw(Spacing.END); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerView.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerView.java index 3a60050526b6f8..fbb10ecfc40c17 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerView.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollContainerView.java @@ -10,6 +10,7 @@ import android.content.Context; import androidx.core.view.ViewCompat; import com.facebook.infer.annotation.Nullsafe; +import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags; import com.facebook.react.modules.i18nmanager.I18nUtil; import com.facebook.react.views.view.ReactViewGroup; @@ -27,6 +28,14 @@ public ReactHorizontalScrollContainerView(Context context) { : ViewCompat.LAYOUT_DIRECTION_LTR; } + @Override + public int getLayoutDirection() { + if (ReactNativeFeatureFlags.setAndroidLayoutDirection()) { + return super.getLayoutDirection(); + } + return mLayoutDirection; + } + @Override public void setRemoveClippedSubviews(boolean removeClippedSubviews) { // Clipping doesn't work well for horizontal scroll views in RTL mode - in both @@ -34,7 +43,7 @@ public void setRemoveClippedSubviews(boolean removeClippedSubviews) { // is TextInputs being blurred immediately after being focused. So, for now, // it's easier to just disable this for these specific RTL views. // TODO T86027499: support `setRemoveClippedSubviews` in RTL mode - if (mLayoutDirection == LAYOUT_DIRECTION_RTL) { + if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { super.setRemoveClippedSubviews(false); return; } @@ -44,7 +53,7 @@ public void setRemoveClippedSubviews(boolean removeClippedSubviews) { @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - if (mLayoutDirection == LAYOUT_DIRECTION_RTL) { + if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { // 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 int newLeft = 0; 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 0c1ef425494308..4ffe87f9d308cf 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,6 +35,7 @@ import com.facebook.infer.annotation.Nullsafe; import com.facebook.react.common.ReactConstants; import com.facebook.react.common.build.ReactBuildConfig; +import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags; import com.facebook.react.modules.i18nmanager.I18nUtil; import com.facebook.react.uimanager.MeasureSpecAssertions; import com.facebook.react.uimanager.PointerEvents; @@ -1061,7 +1062,10 @@ private void flingAndSnap(int velocityX) { int firstOffset = 0; int lastOffset = maximumOffset; int width = getWidth() - ViewCompat.getPaddingStart(this) - ViewCompat.getPaddingEnd(this); - int layoutDirection = getReactScrollViewScrollState().getLayoutDirection(); + int layoutDirection = + ReactNativeFeatureFlags.setAndroidLayoutDirection() + ? getLayoutDirection() + : mReactScrollViewScrollState.getLayoutDirection(); // offsets are from the right edge in RTL layouts if (layoutDirection == LAYOUT_DIRECTION_RTL) { @@ -1385,7 +1389,11 @@ public void onLayoutChange( // does not shift layout. If `maintainVisibleContentPosition` is enabled, we try to adjust // position so that the viewport keeps the same insets to previously visible views. TODO: MVCP // does not work in RTL. - if (mReactScrollViewScrollState.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { + int layoutDirection = + ReactNativeFeatureFlags.setAndroidLayoutDirection() + ? v.getLayoutDirection() + : mReactScrollViewScrollState.getLayoutDirection(); + if (layoutDirection == LAYOUT_DIRECTION_RTL) { adjustPositionForContentChangeRTL(left, right, oldLeft, oldRight); } else if (mMaintainVisibleContentPositionHelper != null) { mMaintainVisibleContentPositionHelper.updateScrollPosition(); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java index ce066636ca8796..3114e2cfdc14e0 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java @@ -32,6 +32,7 @@ import com.facebook.react.bridge.ReactSoftExceptionLogger; import com.facebook.react.bridge.UiThreadUtil; import com.facebook.react.common.annotations.VisibleForTesting; +import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags; import com.facebook.react.modules.i18nmanager.I18nUtil; import com.facebook.react.touch.OnInterceptTouchEventListener; import com.facebook.react.touch.ReactHitSlopView; @@ -129,7 +130,6 @@ public void onLayoutChange( private boolean mNeedsOffscreenAlphaCompositing; private @Nullable ViewGroupDrawingOrderHelper mDrawingOrderHelper; private @Nullable Path mPath; - private int mLayoutDirection; private float mBackfaceOpacity; private String mBackfaceVisibility; @@ -159,7 +159,6 @@ private void initView() { mNeedsOffscreenAlphaCompositing = false; mDrawingOrderHelper = null; mPath = null; - mLayoutDirection = 0; // set when background is created mBackfaceOpacity = 1.f; mBackfaceVisibility = "visible"; } @@ -199,13 +198,6 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto // No-op since UIManagerModule handles actually laying out children. } - @Override - public void onRtlPropertiesChanged(int layoutDirection) { - if (mCSSBackgroundDrawable != null) { - mCSSBackgroundDrawable.setResolvedLayoutDirection(mLayoutDirection); - } - } - @Override @SuppressLint("MissingSuperCall") public void requestLayout() { @@ -806,10 +798,12 @@ public int getBackgroundColor() { new LayerDrawable(new Drawable[] {mCSSBackgroundDrawable, backgroundDrawable}); updateBackgroundDrawable(layerDrawable); } - - mLayoutDirection = - I18nUtil.getInstance().isRTL(getContext()) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; - mCSSBackgroundDrawable.setResolvedLayoutDirection(mLayoutDirection); + if (!ReactNativeFeatureFlags.setAndroidLayoutDirection()) { + mCSSBackgroundDrawable.setLayoutDirectionOverride( + I18nUtil.getInstance().isRTL(getContext()) + ? LAYOUT_DIRECTION_RTL + : LAYOUT_DIRECTION_LTR); + } } return mCSSBackgroundDrawable; } diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp index 61ec7ceaca48e1..ca1937640658a8 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp @@ -63,7 +63,9 @@ static inline int getIntBufferSizeForType(CppMountItem::Type mountItemType) { case CppMountItem::Type::UpdatePadding: return 5; // tag, top, left, bottom, right case CppMountItem::Type::UpdateLayout: - return 7; // tag, parentTag, x, y, w, h, DisplayType + return ReactNativeFeatureFlags::setAndroidLayoutDirection() + ? 8 // tag, parentTag, x, y, w, h, DisplayType, LayoutDirection + : 7; // tag, parentTag, x, y, w, h, DisplayType case CppMountItem::Type::UpdateOverflowInset: return 5; // tag, left, top, right, bottom case CppMountItem::Undefined: @@ -496,7 +498,7 @@ void FabricMountingManager::executeMount( int intBufferPosition = 0; int objBufferPosition = 0; int prevMountItemType = -1; - jint temp[7]; + jint temp[8]; for (int i = 0; i < cppCommonMountItems.size(); i++) { const auto& mountItem = cppCommonMountItems[i]; const auto& mountItemType = mountItem.type; @@ -656,7 +658,7 @@ void FabricMountingManager::executeMount( intBufferPosition); for (const auto& mountItem : cppUpdateLayoutMountItems) { - auto layoutMetrics = mountItem.newChildShadowView.layoutMetrics; + const auto& layoutMetrics = mountItem.newChildShadowView.layoutMetrics; auto pointScaleFactor = layoutMetrics.pointScaleFactor; auto frame = layoutMetrics.frame; @@ -664,8 +666,8 @@ void FabricMountingManager::executeMount( int y = round(scale(frame.origin.y, pointScaleFactor)); int w = round(scale(frame.size.width, pointScaleFactor)); int h = round(scale(frame.size.height, pointScaleFactor)); - int displayType = - toInt(mountItem.newChildShadowView.layoutMetrics.displayType); + int displayType = toInt(layoutMetrics.displayType); + int layoutDirection = toInt(layoutMetrics.layoutDirection); temp[0] = mountItem.newChildShadowView.tag; temp[1] = mountItem.parentShadowView.tag; @@ -674,8 +676,15 @@ void FabricMountingManager::executeMount( temp[4] = w; temp[5] = h; temp[6] = displayType; - env->SetIntArrayRegion(intBufferArray, intBufferPosition, 7, temp); - intBufferPosition += 7; + + if (ReactNativeFeatureFlags::setAndroidLayoutDirection()) { + temp[7] = layoutDirection; + env->SetIntArrayRegion(intBufferArray, intBufferPosition, 8, temp); + intBufferPosition += 8; + } else { + env->SetIntArrayRegion(intBufferArray, intBufferPosition, 7, temp); + intBufferPosition += 7; + } } } if (!cppUpdateOverflowInsetMountItems.empty()) { diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp index 5ef972f3da5bd4..6edce23ca78dd1 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<630ef8f9e65223c8d4c2b07bcc0ebadd>> + * @generated SignedSource<<3974227d88e1ee8e676a38f5ac4faed1>> */ /** @@ -135,6 +135,12 @@ class ReactNativeFeatureFlagsProviderHolder return method(javaProvider_); } + bool setAndroidLayoutDirection() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("setAndroidLayoutDirection"); + return method(javaProvider_); + } + bool useModernRuntimeScheduler() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("useModernRuntimeScheduler"); @@ -237,6 +243,11 @@ bool JReactNativeFeatureFlagsCxxInterop::preventDoubleTextMeasure( return ReactNativeFeatureFlags::preventDoubleTextMeasure(); } +bool JReactNativeFeatureFlagsCxxInterop::setAndroidLayoutDirection( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::setAndroidLayoutDirection(); +} + bool JReactNativeFeatureFlagsCxxInterop::useModernRuntimeScheduler( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::useModernRuntimeScheduler(); @@ -317,6 +328,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "preventDoubleTextMeasure", JReactNativeFeatureFlagsCxxInterop::preventDoubleTextMeasure), + makeNativeMethod( + "setAndroidLayoutDirection", + JReactNativeFeatureFlagsCxxInterop::setAndroidLayoutDirection), makeNativeMethod( "useModernRuntimeScheduler", JReactNativeFeatureFlagsCxxInterop::useModernRuntimeScheduler), diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h index f907c08f287c2a..9f5dbc82a59a03 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<39dde965f082a0dffbe00763e184d1db>> + * @generated SignedSource<> */ /** @@ -78,6 +78,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool preventDoubleTextMeasure( facebook::jni::alias_ref); + static bool setAndroidLayoutDirection( + facebook::jni::alias_ref); + static bool useModernRuntimeScheduler( facebook::jni::alias_ref); diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp index 567b83d3f7806c..f315a0ceec4a15 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<> */ /** @@ -85,6 +85,10 @@ bool ReactNativeFeatureFlags::preventDoubleTextMeasure() { return getAccessor().preventDoubleTextMeasure(); } +bool ReactNativeFeatureFlags::setAndroidLayoutDirection() { + return getAccessor().setAndroidLayoutDirection(); +} + bool ReactNativeFeatureFlags::useModernRuntimeScheduler() { return getAccessor().useModernRuntimeScheduler(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index ff2c79c9a7bdc6..1581266f1cd2f4 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<0f7b95b5d42c879dabea8f7d53f9cc17>> + * @generated SignedSource<<24c7fe3b2504e27f578262582719f581>> */ /** @@ -117,6 +117,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool preventDoubleTextMeasure(); + /** + * Propagate layout direction to Android views. + */ + RN_EXPORT static bool setAndroidLayoutDirection(); + /** * When enabled, it uses the modern fork of RuntimeScheduler that allows scheduling tasks with priorities from any thread. */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index e57083eba60b2f..b0849352218c39 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<165de70ff21543c949e57971f1a8ff07>> + * @generated SignedSource<<1039989da579b07d4ff5926938f047c6>> */ /** @@ -317,6 +317,24 @@ bool ReactNativeFeatureFlagsAccessor::preventDoubleTextMeasure() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::setAndroidLayoutDirection() { + auto flagValue = setAndroidLayoutDirection_.load(); + + if (!flagValue.has_value()) { + // This block is not exclusive but it is not necessary. + // If multiple threads try to initialize the feature flag, we would only + // be accessing the provider multiple times but the end state of this + // instance and the returned flag value would be the same. + + markFlagAsAccessed(16, "setAndroidLayoutDirection"); + + flagValue = currentProvider_->setAndroidLayoutDirection(); + setAndroidLayoutDirection_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::useModernRuntimeScheduler() { auto flagValue = useModernRuntimeScheduler_.load(); @@ -326,7 +344,7 @@ bool ReactNativeFeatureFlagsAccessor::useModernRuntimeScheduler() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(16, "useModernRuntimeScheduler"); + markFlagAsAccessed(17, "useModernRuntimeScheduler"); flagValue = currentProvider_->useModernRuntimeScheduler(); useModernRuntimeScheduler_ = flagValue; @@ -344,7 +362,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(17, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(18, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -362,7 +380,7 @@ bool ReactNativeFeatureFlagsAccessor::useStateAlignmentMechanism() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(18, "useStateAlignmentMechanism"); + markFlagAsAccessed(19, "useStateAlignmentMechanism"); flagValue = currentProvider_->useStateAlignmentMechanism(); useStateAlignmentMechanism_ = flagValue; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index 25b9b3342302fa..3feafffa871634 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<1818a852d68148dbabfe5bebd4142ae2>> */ /** @@ -47,6 +47,7 @@ class ReactNativeFeatureFlagsAccessor { bool inspectorEnableModernCDPRegistry(); bool lazyAnimationCallbacks(); bool preventDoubleTextMeasure(); + bool setAndroidLayoutDirection(); bool useModernRuntimeScheduler(); bool useNativeViewConfigsInBridgelessMode(); bool useStateAlignmentMechanism(); @@ -60,7 +61,7 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 19> accessedFeatureFlags_; + std::array, 20> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> allowCollapsableChildren_; @@ -78,6 +79,7 @@ class ReactNativeFeatureFlagsAccessor { std::atomic> inspectorEnableModernCDPRegistry_; std::atomic> lazyAnimationCallbacks_; std::atomic> preventDoubleTextMeasure_; + std::atomic> setAndroidLayoutDirection_; std::atomic> useModernRuntimeScheduler_; std::atomic> useNativeViewConfigsInBridgelessMode_; std::atomic> useStateAlignmentMechanism_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index 5b3bf0785371af..80066cc133257d 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<3563000e4692990818012aa6ee7480e5>> */ /** @@ -91,6 +91,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return false; } + bool setAndroidLayoutDirection() override { + return false; + } + bool useModernRuntimeScheduler() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index 9def019e3182cc..061332262c7a29 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<488476c6915add36fe67d53697a64801>> + * @generated SignedSource<<6206a6ce32afc6d7f83e1a11dfcb0f46>> */ /** @@ -41,6 +41,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool inspectorEnableModernCDPRegistry() = 0; virtual bool lazyAnimationCallbacks() = 0; virtual bool preventDoubleTextMeasure() = 0; + virtual bool setAndroidLayoutDirection() = 0; virtual bool useModernRuntimeScheduler() = 0; virtual bool useNativeViewConfigsInBridgelessMode() = 0; virtual bool useStateAlignmentMechanism() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index 11c8acd990fe10..d481457735550b 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<4ccd72ad67edf83d62da6be13c1ec850>> */ /** @@ -117,6 +117,11 @@ bool NativeReactNativeFeatureFlags::preventDoubleTextMeasure( return ReactNativeFeatureFlags::preventDoubleTextMeasure(); } +bool NativeReactNativeFeatureFlags::setAndroidLayoutDirection( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::setAndroidLayoutDirection(); +} + bool NativeReactNativeFeatureFlags::useModernRuntimeScheduler( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::useModernRuntimeScheduler(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index 1fe8906f128319..89d40d9395a38b 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +++ b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<8e6f4fc87e96710fcd2011e5893f071b>> */ /** @@ -67,6 +67,8 @@ class NativeReactNativeFeatureFlags bool preventDoubleTextMeasure(jsi::Runtime& runtime); + bool setAndroidLayoutDirection(jsi::Runtime& runtime); + bool useModernRuntimeScheduler(jsi::Runtime& runtime); bool useNativeViewConfigsInBridgelessMode(jsi::Runtime& runtime); diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index f1a25474ef1fa4..ae65968c048920 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -113,6 +113,10 @@ const definitions: FeatureFlagDefinitions = { description: 'When enabled, ParagraphShadowNode will no longer call measure twice.', }, + setAndroidLayoutDirection: { + defaultValue: false, + description: 'Propagate layout direction to Android views.', + }, useModernRuntimeScheduler: { defaultValue: false, description: diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index 2ea84944030b5d..50f3e20c5bed26 100644 --- a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<953d2d7e7adb016bf30c2be62ee0d89a>> + * @generated SignedSource<<723a8825d7a3281d90439e6600c839cb>> * @flow strict-local */ @@ -56,6 +56,7 @@ export type ReactNativeFeatureFlags = { inspectorEnableModernCDPRegistry: Getter, lazyAnimationCallbacks: Getter, preventDoubleTextMeasure: Getter, + setAndroidLayoutDirection: Getter, useModernRuntimeScheduler: Getter, useNativeViewConfigsInBridgelessMode: Getter, useStateAlignmentMechanism: Getter, @@ -165,6 +166,10 @@ export const lazyAnimationCallbacks: Getter = createNativeFlagGetter('l * When enabled, ParagraphShadowNode will no longer call measure twice. */ export const preventDoubleTextMeasure: Getter = createNativeFlagGetter('preventDoubleTextMeasure', false); +/** + * Propagate layout direction to Android views. + */ +export const setAndroidLayoutDirection: Getter = createNativeFlagGetter('setAndroidLayoutDirection', false); /** * When enabled, it uses the modern fork of RuntimeScheduler that allows scheduling tasks with priorities from any thread. */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index 9a14b68c580606..2bc881fff3762f 100644 --- a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<446991ce24c5765399940bfda55c0e5c>> + * @generated SignedSource<<0563625894ea466e12b8b6edd2f0022a>> * @flow strict-local */ @@ -39,6 +39,7 @@ export interface Spec extends TurboModule { +inspectorEnableModernCDPRegistry?: () => boolean; +lazyAnimationCallbacks?: () => boolean; +preventDoubleTextMeasure?: () => boolean; + +setAndroidLayoutDirection?: () => boolean; +useModernRuntimeScheduler?: () => boolean; +useNativeViewConfigsInBridgelessMode?: () => boolean; +useStateAlignmentMechanism?: () => boolean;