From 5a9023f7aba9b12bd5b47bb5e2e667cbb03cbf38 Mon Sep 17 00:00:00 2001 From: Jorge Cabiedes Acosta Date: Tue, 22 Apr 2025 13:17:21 -0700 Subject: [PATCH] Fix crash with nested FlatLists and fix edge case with nested views (#50827) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/50827 This diff addresses a crash caused by view duplication in React Native Android. The issue occurred when a view was not already clipped and was laid out again, resulting in duplicated views. This problem was particularly noticeable when using nested FlatLists, which triggered a custom focus search with an incomplete and buggy duplicated FlatList container view. The fix involves preventing the duplication of views by checking if a view is clipped already before laying it out again. Additionally, this diff includes two other improvements: - Preventing clipping issues: When a view is nested within a non-ReactClippingViewGroup ancestor, focus searching would fail due to the needUpdateClippingRecursive logic only running on instances of ReactClippingViewGroup. By excluding these ancestors, we ensure that the next focusable view can be properly excluded from being clipped. - Minor fix: A minor fix was made to prevent potential issues in deeply nested cases. - Add a Kill switch with a feature flag and mobile config combo. For Facebook we can kill through MC and for all other apps we can kill with the feature flag default value Changelog: [Internal] Reviewed By: joevilches Differential Revision: D73213775 fbshipit-source-id: 51a667a0c22eb35f0ec46ac4cbe430e2e62b407b --- .../ReactAndroid/api/ReactAndroid.api | 2 +- .../react/fabric/FabricUIManager.java | 4 +- .../react/fabric/FabricUIManagerBinding.kt | 2 +- .../featureflags/ReactNativeFeatureFlags.kt | 8 +- .../ReactNativeFeatureFlagsCxxAccessor.kt | 12 ++- .../ReactNativeFeatureFlagsCxxInterop.kt | 4 +- .../ReactNativeFeatureFlagsDefaults.kt | 4 +- .../ReactNativeFeatureFlagsLocalAccessor.kt | 13 ++- .../ReactNativeFeatureFlagsProvider.kt | 4 +- .../scroll/ReactHorizontalScrollView.java | 9 +- .../react/views/scroll/ReactScrollView.java | 10 ++- .../views/scroll/ReactScrollViewHelper.kt | 11 ++- .../react/views/view/ReactViewGroup.java | 5 +- .../react/fabric/FabricUIManagerBinding.cpp | 22 +++-- .../jni/react/fabric/FabricUIManagerBinding.h | 2 +- .../JReactNativeFeatureFlagsCxxInterop.cpp | 16 +++- .../JReactNativeFeatureFlagsCxxInterop.h | 5 +- .../featureflags/ReactNativeFeatureFlags.cpp | 6 +- .../featureflags/ReactNativeFeatureFlags.h | 7 +- .../ReactNativeFeatureFlagsAccessor.cpp | 86 +++++++++++-------- .../ReactNativeFeatureFlagsAccessor.h | 6 +- .../ReactNativeFeatureFlagsDefaults.h | 6 +- .../ReactNativeFeatureFlagsDynamicProvider.h | 11 ++- .../ReactNativeFeatureFlagsProvider.h | 3 +- .../NativeReactNativeFeatureFlags.cpp | 7 +- .../NativeReactNativeFeatureFlags.h | 4 +- .../ReactNativeFeatureFlags.config.js | 10 +++ .../featureflags/ReactNativeFeatureFlags.js | 7 +- .../specs/NativeReactNativeFeatureFlags.js | 3 +- 29 files changed, 209 insertions(+), 80 deletions(-) diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 8f8558e84bd..a4f1e4ebb40 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -2344,10 +2344,10 @@ public class com/facebook/react/fabric/FabricUIManager : com/facebook/react/brid public fun dispatchCommand (IILjava/lang/String;Lcom/facebook/react/bridge/ReadableArray;)V public fun dispatchCommand (ILjava/lang/String;Lcom/facebook/react/bridge/ReadableArray;)V public fun findNextFocusableElement (III)Ljava/lang/Integer; - public fun findRelativeTopMostParent (II)Ljava/lang/Integer; public fun getColor (I[Ljava/lang/String;)I public fun getEventDispatcher ()Lcom/facebook/react/uimanager/events/EventDispatcher; public fun getPerformanceCounters ()Ljava/util/Map; + public fun getRelativeAncestorList (II)[I public fun getThemeData (I[F)Z public fun initialize ()V public fun invalidate ()V 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 2dd7615a067..14b4439b6ca 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 @@ -305,8 +305,8 @@ public class FabricUIManager return serializedNextFocusableNodeMetrics; } - public @Nullable Integer findRelativeTopMostParent(int rootTag, int childTag) { - return mBinding != null ? mBinding.findRelativeTopMostParent(rootTag, childTag) : null; + public @Nullable int[] getRelativeAncestorList(int rootTag, int childTag) { + return mBinding != null ? mBinding.getRelativeAncestorList(rootTag, childTag) : null; } @Override 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 f76c676af87..f22661f1d7e 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 @@ -57,7 +57,7 @@ internal class FabricUIManagerBinding : HybridClassBase() { external fun findNextFocusableElement(parentTag: Int, focusedTag: Int, direction: Int): Int - external fun findRelativeTopMostParent(rootTag: Int, childTag: Int): Int + external fun getRelativeAncestorList(rootTag: Int, childTag: Int): IntArray external fun stopSurface(surfaceId: Int) 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 9b747dd0250..e68d497babd 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<> */ /** @@ -84,6 +84,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun enableCppPropsIteratorSetter(): Boolean = accessor.enableCppPropsIteratorSetter() + /** + * This enables the fabric implementation of focus search so that we can focus clipped elements + */ + @JvmStatic + public fun enableCustomFocusSearchOnClippedElementsAndroid(): Boolean = accessor.enableCustomFocusSearchOnClippedElementsAndroid() + /** * Feature flag to configure eager attachment of the root view/initialisation of the JS code. */ 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 234056e7e23..8236a9d552d 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<> + * @generated SignedSource<<7394c9300cb0cf05727c57379320810b>> */ /** @@ -29,6 +29,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces private var enableAccumulatedUpdatesInRawPropsAndroidCache: Boolean? = null private var enableBridgelessArchitectureCache: Boolean? = null private var enableCppPropsIteratorSetterCache: Boolean? = null + private var enableCustomFocusSearchOnClippedElementsAndroidCache: Boolean? = null private var enableEagerRootViewAttachmentCache: Boolean? = null private var enableFabricLogsCache: Boolean? = null private var enableFabricRendererCache: Boolean? = null @@ -144,6 +145,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun enableCustomFocusSearchOnClippedElementsAndroid(): Boolean { + var cached = enableCustomFocusSearchOnClippedElementsAndroidCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.enableCustomFocusSearchOnClippedElementsAndroid() + enableCustomFocusSearchOnClippedElementsAndroidCache = cached + } + return cached + } + override fun enableEagerRootViewAttachment(): Boolean { var cached = enableEagerRootViewAttachmentCache 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 504d71efb7f..9032486ce4b 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<> + * @generated SignedSource<> */ /** @@ -46,6 +46,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun enableCppPropsIteratorSetter(): Boolean + @DoNotStrip @JvmStatic public external fun enableCustomFocusSearchOnClippedElementsAndroid(): Boolean + @DoNotStrip @JvmStatic public external fun enableEagerRootViewAttachment(): Boolean @DoNotStrip @JvmStatic public external fun enableFabricLogs(): 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 e240f056b54..a006beb4d27 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<> */ /** @@ -41,6 +41,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun enableCppPropsIteratorSetter(): Boolean = false + override fun enableCustomFocusSearchOnClippedElementsAndroid(): Boolean = true + override fun enableEagerRootViewAttachment(): Boolean = false override fun enableFabricLogs(): 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 7e3680912dd..3a30fbd3db6 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<> + * @generated SignedSource<<5ea02b7c6aa699b226b7c44e52d8e484>> */ /** @@ -33,6 +33,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc private var enableAccumulatedUpdatesInRawPropsAndroidCache: Boolean? = null private var enableBridgelessArchitectureCache: Boolean? = null private var enableCppPropsIteratorSetterCache: Boolean? = null + private var enableCustomFocusSearchOnClippedElementsAndroidCache: Boolean? = null private var enableEagerRootViewAttachmentCache: Boolean? = null private var enableFabricLogsCache: Boolean? = null private var enableFabricRendererCache: Boolean? = null @@ -157,6 +158,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc return cached } + override fun enableCustomFocusSearchOnClippedElementsAndroid(): Boolean { + var cached = enableCustomFocusSearchOnClippedElementsAndroidCache + if (cached == null) { + cached = currentProvider.enableCustomFocusSearchOnClippedElementsAndroid() + accessedFeatureFlags.add("enableCustomFocusSearchOnClippedElementsAndroid") + enableCustomFocusSearchOnClippedElementsAndroidCache = cached + } + return cached + } + override fun enableEagerRootViewAttachment(): Boolean { var cached = enableEagerRootViewAttachmentCache 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 01d9b41901a..08ced185216 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<<76da11369c2f7b8955a154a63af374a3>> + * @generated SignedSource<> */ /** @@ -41,6 +41,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun enableCppPropsIteratorSetter(): Boolean + @DoNotStrip public fun enableCustomFocusSearchOnClippedElementsAndroid(): Boolean + @DoNotStrip public fun enableEagerRootViewAttachment(): Boolean @DoNotStrip public fun enableFabricLogs(): Boolean 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 0c3ed4e7b25..82c60e7b8fc 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 @@ -41,6 +41,7 @@ import com.facebook.react.animated.NativeAnimatedModule; import com.facebook.react.bridge.ReactContext; import com.facebook.react.common.ReactConstants; import com.facebook.react.common.build.ReactBuildConfig; +import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags; import com.facebook.react.uimanager.BackgroundStyleApplicator; import com.facebook.react.uimanager.LengthPercentage; import com.facebook.react.uimanager.LengthPercentageType; @@ -776,10 +777,12 @@ public class ReactHorizontalScrollView extends HorizontalScrollView @Override public @Nullable View focusSearch(View focused, @FocusRealDirection int direction) { - @Nullable View nextfocusableView = findNextFocusableView(this, focused, direction, true); + if (ReactNativeFeatureFlags.enableCustomFocusSearchOnClippedElementsAndroid()) { + @Nullable View nextfocusableView = findNextFocusableView(this, focused, direction, true); - if (nextfocusableView != null) { - return nextfocusableView; + if (nextfocusableView != null) { + return nextfocusableView; + } } return super.focusSearch(focused, direction); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java index 8cdbcae3d8a..2e0c20dfa0d 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollView.java @@ -41,6 +41,7 @@ import com.facebook.react.animated.NativeAnimatedModule; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.common.ReactConstants; +import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags; import com.facebook.react.uimanager.BackgroundStyleApplicator; import com.facebook.react.uimanager.LengthPercentage; import com.facebook.react.uimanager.LengthPercentageType; @@ -364,11 +365,12 @@ public class ReactScrollView extends ScrollView @Override public @Nullable View focusSearch(View focused, @FocusRealDirection int direction) { + if (ReactNativeFeatureFlags.enableCustomFocusSearchOnClippedElementsAndroid()) { + @Nullable View nextfocusableView = findNextFocusableView(this, focused, direction, false); - @Nullable View nextfocusableView = findNextFocusableView(this, focused, direction, false); - - if (nextfocusableView != null) { - return nextfocusableView; + if (nextfocusableView != null) { + return nextfocusableView; + } } return super.focusSearch(focused, direction); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.kt index a86e571c612..9714d323aa2 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewHelper.kt @@ -499,11 +499,14 @@ public object ReactScrollViewHelper { (uimanager as FabricUIManager).findNextFocusableElement( host.getChildAt(0).id, focused.id, absDir) ?: return null - val nextFocusTopMostParentId = - uimanager.findRelativeTopMostParent(host.getChildAt(0).id, nextFocusableViewId) - ?: return null + val ancestorIdList = + uimanager + .getRelativeAncestorList(host.getChildAt(0).id, nextFocusableViewId) + ?.toMutableSet() ?: return null - host.updateClippingRect(setOf(nextFocusableViewId, nextFocusTopMostParentId)) + ancestorIdList.add(nextFocusableViewId) + + host.updateClippingRect(ancestorIdList) return host.findViewById(nextFocusableViewId) } 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 c2996ed2056..c2801edd45b 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 @@ -507,9 +507,6 @@ public class ReactViewGroup extends ViewGroup Animation animation = child.getAnimation(); boolean isAnimating = animation != null && !animation.hasEnded(); boolean shouldSkipView = excludedViewsSet != null && excludedViewsSet.contains(child.getId()); - if (excludedViewsSet != null) { - needUpdateClippingRecursive = true; - } // We don't want to clip a view that is currently focused at that might break focus navigation if (!intersects && !isViewClipped(child, idx) @@ -521,7 +518,7 @@ public class ReactViewGroup extends ViewGroup // therefore invalidation is not necessary. removeViewInLayout(child); needUpdateClippingRecursive = true; - } else if (shouldSkipView || (intersects && isViewClipped(child, idx))) { + } else if ((shouldSkipView || intersects) && isViewClipped(child, idx)) { int adjustedIdx = idx - clippedSoFar; Assertions.assertCondition(adjustedIdx >= 0); setViewClipped(child, false); 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 50f20e19aa3..2abaa0a06b7 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 @@ -253,9 +253,11 @@ jint FabricUIManagerBinding::findNextFocusableElement( return nextNode->getTag(); } -jint FabricUIManagerBinding::findRelativeTopMostParent( +jintArray FabricUIManagerBinding::getRelativeAncestorList( jint rootTag, jint childTag) { + JNIEnv* env = jni::Environment::current(); + std::shared_ptr uimanager = getScheduler()->getUIManager(); ShadowNode::Shared childShadowNode = @@ -264,27 +266,33 @@ jint FabricUIManagerBinding::findRelativeTopMostParent( uimanager->findShadowNodeByTag_DEPRECATED(rootTag); if (childShadowNode == nullptr || rootShadowNode == nullptr) { - return -1; + return nullptr; } ShadowNode::AncestorList ancestorList = childShadowNode->getFamily().getAncestors(*rootShadowNode); if (ancestorList.empty() || ancestorList.size() < 2) { - return -1; + return nullptr; } // ignore the first ancestor as it is the rootShadowNode itself + std::vector ancestorTags; for (auto it = std::next(ancestorList.begin()); it != ancestorList.end(); ++it) { auto& ancestor = *it; if (ancestor.first.get().getTraits().check( ShadowNodeTraits::Trait::FormsStackingContext)) { - return ancestor.first.get().getTag(); + ancestorTags.push_back(ancestor.first.get().getTag()); } } - return -1; + jintArray result = env->NewIntArray(static_cast(ancestorTags.size())); + + env->SetIntArrayRegion( + result, 0, static_cast(ancestorTags.size()), ancestorTags.data()); + + return result; } // Used by non-bridgeless+Fabric @@ -763,8 +771,8 @@ void FabricUIManagerBinding::registerNatives() { "findNextFocusableElement", FabricUIManagerBinding::findNextFocusableElement), makeNativeMethod( - "findRelativeTopMostParent", - FabricUIManagerBinding::findRelativeTopMostParent), + "getRelativeAncestorList", + FabricUIManagerBinding::getRelativeAncestorList), }); } diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.h index e045425269d..4cd9f26cd05 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.h @@ -135,7 +135,7 @@ class FabricUIManagerBinding : public jni::HybridClass, jint findNextFocusableElement(jint parentTag, jint focusedTag, jint direction); - jint findRelativeTopMostParent(jint rootTag, jint childTag); + jintArray getRelativeAncestorList(jint rootTag, jint childTag); void uninstallFabricUIManager(); 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 786a2c461ba..334038c855d 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<> + * @generated SignedSource<<4c4d84c0af6906301c32d59c129b90f8>> */ /** @@ -93,6 +93,12 @@ class ReactNativeFeatureFlagsJavaProvider return method(javaProvider_); } + bool enableCustomFocusSearchOnClippedElementsAndroid() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("enableCustomFocusSearchOnClippedElementsAndroid"); + return method(javaProvider_); + } + bool enableEagerRootViewAttachment() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("enableEagerRootViewAttachment"); @@ -340,6 +346,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableCppPropsIteratorSetter( return ReactNativeFeatureFlags::enableCppPropsIteratorSetter(); } +bool JReactNativeFeatureFlagsCxxInterop::enableCustomFocusSearchOnClippedElementsAndroid( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::enableCustomFocusSearchOnClippedElementsAndroid(); +} + bool JReactNativeFeatureFlagsCxxInterop::enableEagerRootViewAttachment( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::enableEagerRootViewAttachment(); @@ -563,6 +574,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "enableCppPropsIteratorSetter", JReactNativeFeatureFlagsCxxInterop::enableCppPropsIteratorSetter), + makeNativeMethod( + "enableCustomFocusSearchOnClippedElementsAndroid", + JReactNativeFeatureFlagsCxxInterop::enableCustomFocusSearchOnClippedElementsAndroid), makeNativeMethod( "enableEagerRootViewAttachment", JReactNativeFeatureFlagsCxxInterop::enableEagerRootViewAttachment), 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 a8e7ddce1bb..f010efc3849 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<> + * @generated SignedSource<> */ /** @@ -57,6 +57,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool enableCppPropsIteratorSetter( facebook::jni::alias_ref); + static bool enableCustomFocusSearchOnClippedElementsAndroid( + facebook::jni::alias_ref); + static bool enableEagerRootViewAttachment( 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 86384b2a14b..fa92cafa5aa 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<<5ee10cdf8f5e3695ce4f73373291935e>> + * @generated SignedSource<<59350280417b80ed92aa7eacf3223c4e>> */ /** @@ -62,6 +62,10 @@ bool ReactNativeFeatureFlags::enableCppPropsIteratorSetter() { return getAccessor().enableCppPropsIteratorSetter(); } +bool ReactNativeFeatureFlags::enableCustomFocusSearchOnClippedElementsAndroid() { + return getAccessor().enableCustomFocusSearchOnClippedElementsAndroid(); +} + bool ReactNativeFeatureFlags::enableEagerRootViewAttachment() { return getAccessor().enableEagerRootViewAttachment(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index 89a641961e7..7dc1d7b54aa 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<> + * @generated SignedSource<<7f2965f0a6e4fbed816795866623cfb3>> */ /** @@ -84,6 +84,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool enableCppPropsIteratorSetter(); + /** + * This enables the fabric implementation of focus search so that we can focus clipped elements + */ + RN_EXPORT static bool enableCustomFocusSearchOnClippedElementsAndroid(); + /** * Feature flag to configure eager attachment of the root view/initialisation of the JS code. */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index fb424a14633..18b849b9432 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<<4c18c271811129f1e1411fc2666aeb38>> + * @generated SignedSource<> */ /** @@ -191,6 +191,24 @@ bool ReactNativeFeatureFlagsAccessor::enableCppPropsIteratorSetter() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::enableCustomFocusSearchOnClippedElementsAndroid() { + auto flagValue = enableCustomFocusSearchOnClippedElementsAndroid_.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(9, "enableCustomFocusSearchOnClippedElementsAndroid"); + + flagValue = currentProvider_->enableCustomFocusSearchOnClippedElementsAndroid(); + enableCustomFocusSearchOnClippedElementsAndroid_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::enableEagerRootViewAttachment() { auto flagValue = enableEagerRootViewAttachment_.load(); @@ -200,7 +218,7 @@ bool ReactNativeFeatureFlagsAccessor::enableEagerRootViewAttachment() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(9, "enableEagerRootViewAttachment"); + markFlagAsAccessed(10, "enableEagerRootViewAttachment"); flagValue = currentProvider_->enableEagerRootViewAttachment(); enableEagerRootViewAttachment_ = flagValue; @@ -218,7 +236,7 @@ bool ReactNativeFeatureFlagsAccessor::enableFabricLogs() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(10, "enableFabricLogs"); + markFlagAsAccessed(11, "enableFabricLogs"); flagValue = currentProvider_->enableFabricLogs(); enableFabricLogs_ = flagValue; @@ -236,7 +254,7 @@ bool ReactNativeFeatureFlagsAccessor::enableFabricRenderer() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(11, "enableFabricRenderer"); + markFlagAsAccessed(12, "enableFabricRenderer"); flagValue = currentProvider_->enableFabricRenderer(); enableFabricRenderer_ = flagValue; @@ -254,7 +272,7 @@ bool ReactNativeFeatureFlagsAccessor::enableFixForParentTagDuringReparenting() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(12, "enableFixForParentTagDuringReparenting"); + markFlagAsAccessed(13, "enableFixForParentTagDuringReparenting"); flagValue = currentProvider_->enableFixForParentTagDuringReparenting(); enableFixForParentTagDuringReparenting_ = flagValue; @@ -272,7 +290,7 @@ bool ReactNativeFeatureFlagsAccessor::enableFontScaleChangesUpdatingLayout() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(13, "enableFontScaleChangesUpdatingLayout"); + markFlagAsAccessed(14, "enableFontScaleChangesUpdatingLayout"); flagValue = currentProvider_->enableFontScaleChangesUpdatingLayout(); enableFontScaleChangesUpdatingLayout_ = flagValue; @@ -290,7 +308,7 @@ bool ReactNativeFeatureFlagsAccessor::enableIOSViewClipToPaddingBox() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(14, "enableIOSViewClipToPaddingBox"); + markFlagAsAccessed(15, "enableIOSViewClipToPaddingBox"); flagValue = currentProvider_->enableIOSViewClipToPaddingBox(); enableIOSViewClipToPaddingBox_ = flagValue; @@ -308,7 +326,7 @@ bool ReactNativeFeatureFlagsAccessor::enableJSRuntimeGCOnMemoryPressureOnIOS() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(15, "enableJSRuntimeGCOnMemoryPressureOnIOS"); + markFlagAsAccessed(16, "enableJSRuntimeGCOnMemoryPressureOnIOS"); flagValue = currentProvider_->enableJSRuntimeGCOnMemoryPressureOnIOS(); enableJSRuntimeGCOnMemoryPressureOnIOS_ = flagValue; @@ -326,7 +344,7 @@ bool ReactNativeFeatureFlagsAccessor::enableLayoutAnimationsOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(16, "enableLayoutAnimationsOnAndroid"); + markFlagAsAccessed(17, "enableLayoutAnimationsOnAndroid"); flagValue = currentProvider_->enableLayoutAnimationsOnAndroid(); enableLayoutAnimationsOnAndroid_ = flagValue; @@ -344,7 +362,7 @@ bool ReactNativeFeatureFlagsAccessor::enableLayoutAnimationsOnIOS() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(17, "enableLayoutAnimationsOnIOS"); + markFlagAsAccessed(18, "enableLayoutAnimationsOnIOS"); flagValue = currentProvider_->enableLayoutAnimationsOnIOS(); enableLayoutAnimationsOnIOS_ = flagValue; @@ -362,7 +380,7 @@ bool ReactNativeFeatureFlagsAccessor::enableMainQueueModulesOnIOS() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(18, "enableMainQueueModulesOnIOS"); + markFlagAsAccessed(19, "enableMainQueueModulesOnIOS"); flagValue = currentProvider_->enableMainQueueModulesOnIOS(); enableMainQueueModulesOnIOS_ = flagValue; @@ -380,7 +398,7 @@ bool ReactNativeFeatureFlagsAccessor::enableNativeCSSParsing() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(19, "enableNativeCSSParsing"); + markFlagAsAccessed(20, "enableNativeCSSParsing"); flagValue = currentProvider_->enableNativeCSSParsing(); enableNativeCSSParsing_ = flagValue; @@ -398,7 +416,7 @@ bool ReactNativeFeatureFlagsAccessor::enableNewBackgroundAndBorderDrawables() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(20, "enableNewBackgroundAndBorderDrawables"); + markFlagAsAccessed(21, "enableNewBackgroundAndBorderDrawables"); flagValue = currentProvider_->enableNewBackgroundAndBorderDrawables(); enableNewBackgroundAndBorderDrawables_ = flagValue; @@ -416,7 +434,7 @@ bool ReactNativeFeatureFlagsAccessor::enablePropsUpdateReconciliationAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(21, "enablePropsUpdateReconciliationAndroid"); + markFlagAsAccessed(22, "enablePropsUpdateReconciliationAndroid"); flagValue = currentProvider_->enablePropsUpdateReconciliationAndroid(); enablePropsUpdateReconciliationAndroid_ = flagValue; @@ -434,7 +452,7 @@ bool ReactNativeFeatureFlagsAccessor::enableSynchronousStateUpdates() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(22, "enableSynchronousStateUpdates"); + markFlagAsAccessed(23, "enableSynchronousStateUpdates"); flagValue = currentProvider_->enableSynchronousStateUpdates(); enableSynchronousStateUpdates_ = flagValue; @@ -452,7 +470,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewCulling() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(23, "enableViewCulling"); + markFlagAsAccessed(24, "enableViewCulling"); flagValue = currentProvider_->enableViewCulling(); enableViewCulling_ = flagValue; @@ -470,7 +488,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecycling() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(24, "enableViewRecycling"); + markFlagAsAccessed(25, "enableViewRecycling"); flagValue = currentProvider_->enableViewRecycling(); enableViewRecycling_ = flagValue; @@ -488,7 +506,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForText() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(25, "enableViewRecyclingForText"); + markFlagAsAccessed(26, "enableViewRecyclingForText"); flagValue = currentProvider_->enableViewRecyclingForText(); enableViewRecyclingForText_ = flagValue; @@ -506,7 +524,7 @@ bool ReactNativeFeatureFlagsAccessor::enableViewRecyclingForView() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(26, "enableViewRecyclingForView"); + markFlagAsAccessed(27, "enableViewRecyclingForView"); flagValue = currentProvider_->enableViewRecyclingForView(); enableViewRecyclingForView_ = flagValue; @@ -524,7 +542,7 @@ bool ReactNativeFeatureFlagsAccessor::fixMappingOfEventPrioritiesBetweenFabricAn // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(27, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); + markFlagAsAccessed(28, "fixMappingOfEventPrioritiesBetweenFabricAndReact"); flagValue = currentProvider_->fixMappingOfEventPrioritiesBetweenFabricAndReact(); fixMappingOfEventPrioritiesBetweenFabricAndReact_ = flagValue; @@ -542,7 +560,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxEnabledRelease() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(28, "fuseboxEnabledRelease"); + markFlagAsAccessed(29, "fuseboxEnabledRelease"); flagValue = currentProvider_->fuseboxEnabledRelease(); fuseboxEnabledRelease_ = flagValue; @@ -560,7 +578,7 @@ bool ReactNativeFeatureFlagsAccessor::fuseboxNetworkInspectionEnabled() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(29, "fuseboxNetworkInspectionEnabled"); + markFlagAsAccessed(30, "fuseboxNetworkInspectionEnabled"); flagValue = currentProvider_->fuseboxNetworkInspectionEnabled(); fuseboxNetworkInspectionEnabled_ = flagValue; @@ -578,7 +596,7 @@ bool ReactNativeFeatureFlagsAccessor::removeTurboModuleManagerDelegateMutex() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(30, "removeTurboModuleManagerDelegateMutex"); + markFlagAsAccessed(31, "removeTurboModuleManagerDelegateMutex"); flagValue = currentProvider_->removeTurboModuleManagerDelegateMutex(); removeTurboModuleManagerDelegateMutex_ = flagValue; @@ -596,7 +614,7 @@ bool ReactNativeFeatureFlagsAccessor::traceTurboModulePromiseRejectionsOnAndroid // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(31, "traceTurboModulePromiseRejectionsOnAndroid"); + markFlagAsAccessed(32, "traceTurboModulePromiseRejectionsOnAndroid"); flagValue = currentProvider_->traceTurboModulePromiseRejectionsOnAndroid(); traceTurboModulePromiseRejectionsOnAndroid_ = flagValue; @@ -614,7 +632,7 @@ bool ReactNativeFeatureFlagsAccessor::updateRuntimeShadowNodeReferencesOnCommit( // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(32, "updateRuntimeShadowNodeReferencesOnCommit"); + markFlagAsAccessed(33, "updateRuntimeShadowNodeReferencesOnCommit"); flagValue = currentProvider_->updateRuntimeShadowNodeReferencesOnCommit(); updateRuntimeShadowNodeReferencesOnCommit_ = flagValue; @@ -632,7 +650,7 @@ bool ReactNativeFeatureFlagsAccessor::useAlwaysAvailableJSErrorHandling() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(33, "useAlwaysAvailableJSErrorHandling"); + markFlagAsAccessed(34, "useAlwaysAvailableJSErrorHandling"); flagValue = currentProvider_->useAlwaysAvailableJSErrorHandling(); useAlwaysAvailableJSErrorHandling_ = flagValue; @@ -650,7 +668,7 @@ bool ReactNativeFeatureFlagsAccessor::useEditTextStockAndroidFocusBehavior() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(34, "useEditTextStockAndroidFocusBehavior"); + markFlagAsAccessed(35, "useEditTextStockAndroidFocusBehavior"); flagValue = currentProvider_->useEditTextStockAndroidFocusBehavior(); useEditTextStockAndroidFocusBehavior_ = flagValue; @@ -668,7 +686,7 @@ bool ReactNativeFeatureFlagsAccessor::useFabricInterop() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(35, "useFabricInterop"); + markFlagAsAccessed(36, "useFabricInterop"); flagValue = currentProvider_->useFabricInterop(); useFabricInterop_ = flagValue; @@ -686,7 +704,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(36, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(37, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -704,7 +722,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimizedEventBatchingOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(37, "useOptimizedEventBatchingOnAndroid"); + markFlagAsAccessed(38, "useOptimizedEventBatchingOnAndroid"); flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid(); useOptimizedEventBatchingOnAndroid_ = flagValue; @@ -722,7 +740,7 @@ bool ReactNativeFeatureFlagsAccessor::useRawPropsJsiValue() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(38, "useRawPropsJsiValue"); + markFlagAsAccessed(39, "useRawPropsJsiValue"); flagValue = currentProvider_->useRawPropsJsiValue(); useRawPropsJsiValue_ = flagValue; @@ -740,7 +758,7 @@ bool ReactNativeFeatureFlagsAccessor::useShadowNodeStateOnClone() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(39, "useShadowNodeStateOnClone"); + markFlagAsAccessed(40, "useShadowNodeStateOnClone"); flagValue = currentProvider_->useShadowNodeStateOnClone(); useShadowNodeStateOnClone_ = flagValue; @@ -758,7 +776,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModuleInterop() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(40, "useTurboModuleInterop"); + markFlagAsAccessed(41, "useTurboModuleInterop"); flagValue = currentProvider_->useTurboModuleInterop(); useTurboModuleInterop_ = flagValue; @@ -776,7 +794,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModules() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(41, "useTurboModules"); + markFlagAsAccessed(42, "useTurboModules"); flagValue = currentProvider_->useTurboModules(); useTurboModules_ = flagValue; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h index 8455dc8a56b..e8be4deb576 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<<4338d98b457f8f70a9f8bbe8ab245ce8>> + * @generated SignedSource<<775dea42ec82d31964c9614d86b3e107>> */ /** @@ -41,6 +41,7 @@ class ReactNativeFeatureFlagsAccessor { bool enableAccumulatedUpdatesInRawPropsAndroid(); bool enableBridgelessArchitecture(); bool enableCppPropsIteratorSetter(); + bool enableCustomFocusSearchOnClippedElementsAndroid(); bool enableEagerRootViewAttachment(); bool enableFabricLogs(); bool enableFabricRenderer(); @@ -85,7 +86,7 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 42> accessedFeatureFlags_; + std::array, 43> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> animatedShouldSignalBatch_; @@ -96,6 +97,7 @@ class ReactNativeFeatureFlagsAccessor { std::atomic> enableAccumulatedUpdatesInRawPropsAndroid_; std::atomic> enableBridgelessArchitecture_; std::atomic> enableCppPropsIteratorSetter_; + std::atomic> enableCustomFocusSearchOnClippedElementsAndroid_; std::atomic> enableEagerRootViewAttachment_; std::atomic> enableFabricLogs_; std::atomic> enableFabricRenderer_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index 61cd622c4f9..fca3f21c7b0 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<<2eb8786fbcf716f02200770bba667f48>> + * @generated SignedSource<<213ad9500f8da21c569e104f7c5381c6>> */ /** @@ -63,6 +63,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return false; } + bool enableCustomFocusSearchOnClippedElementsAndroid() override { + return true; + } + bool enableEagerRootViewAttachment() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h index 8ae69f91b90..8d57b08ea5a 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.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<<74978e3a2abd1ec238127003e33b51bd>> + * @generated SignedSource<<20c21d98c3794f426f0146023ba9fa3d>> */ /** @@ -126,6 +126,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef return ReactNativeFeatureFlagsDefaults::enableCppPropsIteratorSetter(); } + bool enableCustomFocusSearchOnClippedElementsAndroid() override { + auto value = values_["enableCustomFocusSearchOnClippedElementsAndroid"]; + if (!value.isNull()) { + return value.getBool(); + } + + return ReactNativeFeatureFlagsDefaults::enableCustomFocusSearchOnClippedElementsAndroid(); + } + bool enableEagerRootViewAttachment() override { auto value = values_["enableEagerRootViewAttachment"]; if (!value.isNull()) { diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index e44ad9f1c95..b7541d79cb0 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<<49c3003d551dc87d22811c92ad16a76c>> + * @generated SignedSource<<7078d82e6af6271cab490fd017dd9ae0>> */ /** @@ -34,6 +34,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool enableAccumulatedUpdatesInRawPropsAndroid() = 0; virtual bool enableBridgelessArchitecture() = 0; virtual bool enableCppPropsIteratorSetter() = 0; + virtual bool enableCustomFocusSearchOnClippedElementsAndroid() = 0; virtual bool enableEagerRootViewAttachment() = 0; virtual bool enableFabricLogs() = 0; virtual bool enableFabricRenderer() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index 20ef94ed163..111af74a4f9 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<<48fbc60de3ca7d6e9c106f451fd0683c>> + * @generated SignedSource<<712f8a51c657c519e19f79ae3d374930>> */ /** @@ -89,6 +89,11 @@ bool NativeReactNativeFeatureFlags::enableCppPropsIteratorSetter( return ReactNativeFeatureFlags::enableCppPropsIteratorSetter(); } +bool NativeReactNativeFeatureFlags::enableCustomFocusSearchOnClippedElementsAndroid( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::enableCustomFocusSearchOnClippedElementsAndroid(); +} + bool NativeReactNativeFeatureFlags::enableEagerRootViewAttachment( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::enableEagerRootViewAttachment(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index 22b13ba1f67..2c98187556b 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<<5bd90040747e90e28f36243cf6c473d0>> + * @generated SignedSource<> */ /** @@ -55,6 +55,8 @@ class NativeReactNativeFeatureFlags bool enableCppPropsIteratorSetter(jsi::Runtime& runtime); + bool enableCustomFocusSearchOnClippedElementsAndroid(jsi::Runtime& runtime); + bool enableEagerRootViewAttachment(jsi::Runtime& runtime); bool enableFabricLogs(jsi::Runtime& runtime); diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index 562016036b3..9f9c55333d2 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -145,6 +145,16 @@ const definitions: FeatureFlagDefinitions = { }, ossReleaseStage: 'none', }, + enableCustomFocusSearchOnClippedElementsAndroid: { + defaultValue: true, + metadata: { + description: + 'This enables the fabric implementation of focus search so that we can focus clipped elements', + expectedReleaseValue: true, + purpose: 'operational', + }, + ossReleaseStage: 'none', + }, enableEagerRootViewAttachment: { defaultValue: false, metadata: { diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index c4cc7849e8c..437a346de60 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<<95280f033ae8492b6fdf610d0d94fff6>> + * @generated SignedSource<> * @flow strict */ @@ -55,6 +55,7 @@ export type ReactNativeFeatureFlags = $ReadOnly<{ enableAccumulatedUpdatesInRawPropsAndroid: Getter, enableBridgelessArchitecture: Getter, enableCppPropsIteratorSetter: Getter, + enableCustomFocusSearchOnClippedElementsAndroid: Getter, enableEagerRootViewAttachment: Getter, enableFabricLogs: Getter, enableFabricRenderer: Getter, @@ -190,6 +191,10 @@ export const enableBridgelessArchitecture: Getter = createNativeFlagGet * Enable prop iterator setter-style construction of Props in C++ (this flag is not used in Java). */ export const enableCppPropsIteratorSetter: Getter = createNativeFlagGetter('enableCppPropsIteratorSetter', false); +/** + * This enables the fabric implementation of focus search so that we can focus clipped elements + */ +export const enableCustomFocusSearchOnClippedElementsAndroid: Getter = createNativeFlagGetter('enableCustomFocusSearchOnClippedElementsAndroid', true); /** * Feature flag to configure eager attachment of the root view/initialisation of the JS code. */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index 115c5b213ca..fcb329eaeeb 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<<7526f36924ba650136380fa0fbd2ee60>> + * @generated SignedSource<<19d3a50e060220a7e0619eceddac025d>> * @flow strict */ @@ -33,6 +33,7 @@ export interface Spec extends TurboModule { +enableAccumulatedUpdatesInRawPropsAndroid?: () => boolean; +enableBridgelessArchitecture?: () => boolean; +enableCppPropsIteratorSetter?: () => boolean; + +enableCustomFocusSearchOnClippedElementsAndroid?: () => boolean; +enableEagerRootViewAttachment?: () => boolean; +enableFabricLogs?: () => boolean; +enableFabricRenderer?: () => boolean;