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 53c4bd6c186d09..ee749afde3cbeb 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<<3e10f8d2f623da3b7b502d8fa78f82a4>> + * @generated SignedSource<<2c321a7a8e811dc238a75f76180843b9>> */ /** @@ -244,6 +244,12 @@ public object ReactNativeFeatureFlags { @JvmStatic public fun useAlwaysAvailableJSErrorHandling(): Boolean = accessor.useAlwaysAvailableJSErrorHandling() + /** + * If true, focusing in ReactEditText will mainly use stock Android requestFocus() behavior. If false it will use legacy custom focus behavior. + */ + @JvmStatic + public fun useEditTextStockAndroidFocusBehavior(): Boolean = accessor.useEditTextStockAndroidFocusBehavior() + /** * Should this application enable the Fabric Interop Layer for Android? If yes, the application will behave so that it can accept non-Fabric components and render them on Fabric. This toggle is controlling extra logic such as custom event dispatching that are needed for the Fabric Interop Layer to work correctly. */ 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 c25a7ad0a77d46..3a7fbd9185358c 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<<497bbb23778fe0f9763e9bfa715ea3aa>> + * @generated SignedSource<> */ /** @@ -56,6 +56,7 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso private var loadVectorDrawablesOnImagesCache: Boolean? = null private var traceTurboModulePromiseRejectionsOnAndroidCache: Boolean? = null private var useAlwaysAvailableJSErrorHandlingCache: Boolean? = null + private var useEditTextStockAndroidFocusBehaviorCache: Boolean? = null private var useFabricInteropCache: Boolean? = null private var useImmediateExecutorInAndroidBridgelessCache: Boolean? = null private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null @@ -390,6 +391,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso return cached } + override fun useEditTextStockAndroidFocusBehavior(): Boolean { + var cached = useEditTextStockAndroidFocusBehaviorCache + if (cached == null) { + cached = ReactNativeFeatureFlagsCxxInterop.useEditTextStockAndroidFocusBehavior() + useEditTextStockAndroidFocusBehaviorCache = cached + } + return cached + } + override fun useFabricInterop(): Boolean { var cached = useFabricInteropCache 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 181c06d9c7cb03..d29a6979cabd9b 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<> */ /** @@ -100,6 +100,8 @@ public object ReactNativeFeatureFlagsCxxInterop { @DoNotStrip @JvmStatic public external fun useAlwaysAvailableJSErrorHandling(): Boolean + @DoNotStrip @JvmStatic public external fun useEditTextStockAndroidFocusBehavior(): Boolean + @DoNotStrip @JvmStatic public external fun useFabricInterop(): Boolean @DoNotStrip @JvmStatic public external fun useImmediateExecutorInAndroidBridgeless(): 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 ca2265e22368bb..882730b504259b 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<<5de2cfc00f486b7d07266939ce18a397>> + * @generated SignedSource<<85d40be44d053b58a74ad76467c8e5e9>> */ /** @@ -95,6 +95,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun useAlwaysAvailableJSErrorHandling(): Boolean = false + override fun useEditTextStockAndroidFocusBehavior(): Boolean = true + override fun useFabricInterop(): Boolean = false override fun useImmediateExecutorInAndroidBridgeless(): Boolean = true 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 0200670573d136..f08720d444f56d 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<<18d5c2ffa66a36e364bc358a144534ec>> */ /** @@ -60,6 +60,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces private var loadVectorDrawablesOnImagesCache: Boolean? = null private var traceTurboModulePromiseRejectionsOnAndroidCache: Boolean? = null private var useAlwaysAvailableJSErrorHandlingCache: Boolean? = null + private var useEditTextStockAndroidFocusBehaviorCache: Boolean? = null private var useFabricInteropCache: Boolean? = null private var useImmediateExecutorInAndroidBridgelessCache: Boolean? = null private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null @@ -430,6 +431,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces return cached } + override fun useEditTextStockAndroidFocusBehavior(): Boolean { + var cached = useEditTextStockAndroidFocusBehaviorCache + if (cached == null) { + cached = currentProvider.useEditTextStockAndroidFocusBehavior() + accessedFeatureFlags.add("useEditTextStockAndroidFocusBehavior") + useEditTextStockAndroidFocusBehaviorCache = cached + } + return cached + } + override fun useFabricInterop(): Boolean { var cached = useFabricInteropCache 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 e3fb3270f52fce..cbff3e1f929001 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<<3cd802bdd1d383ea0668e43319d53b3f>> + * @generated SignedSource<<4f90c47ea6f23c2ebfae1f35790c4af5>> */ /** @@ -95,6 +95,8 @@ public interface ReactNativeFeatureFlagsProvider { @DoNotStrip public fun useAlwaysAvailableJSErrorHandling(): Boolean + @DoNotStrip public fun useEditTextStockAndroidFocusBehavior(): Boolean + @DoNotStrip public fun useFabricInterop(): Boolean @DoNotStrip public fun useImmediateExecutorInAndroidBridgeless(): Boolean diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java index a0370775f5c288..2282e43bd21d01 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java @@ -50,6 +50,7 @@ import com.facebook.react.bridge.ReactSoftExceptionLogger; 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; @@ -145,7 +146,9 @@ public class ReactEditText extends AppCompatEditText { public ReactEditText(Context context) { super(context); - setFocusableInTouchMode(false); + if (!ReactNativeFeatureFlags.useEditTextStockAndroidFocusBehavior()) { + setFocusableInTouchMode(false); + } mInputMethodManager = (InputMethodManager) @@ -188,7 +191,9 @@ public boolean performAccessibilityAction(View host, int action, Bundle args) { // selection on accessibility click to undo that. setSelection(length); } - return requestFocusInternal(); + return ReactNativeFeatureFlags.useEditTextStockAndroidFocusBehavior() + ? requestFocusProgramatically() + : requestFocusInternal(); } return super.performAccessibilityAction(host, action, args); } @@ -338,7 +343,10 @@ public boolean onTextContextMenuItem(int id) { @Override public void clearFocus() { - setFocusableInTouchMode(false); + boolean useStockFocusBehavior = ReactNativeFeatureFlags.useEditTextStockAndroidFocusBehavior(); + if (!useStockFocusBehavior) { + setFocusableInTouchMode(false); + } super.clearFocus(); hideSoftKeyboard(); } @@ -349,7 +357,9 @@ public boolean requestFocus(int direction, Rect previouslyFocusedRect) { // is a controlled component, which means its focus is controlled by JS, with two exceptions: // autofocus when it's attached to the window, and responding to accessibility events. In both // of these cases, we call requestFocusInternal() directly. - return isFocused(); + return ReactNativeFeatureFlags.useEditTextStockAndroidFocusBehavior() + ? super.requestFocus(direction, previouslyFocusedRect) + : isFocused(); } private boolean requestFocusInternal() { @@ -360,6 +370,20 @@ private boolean requestFocusInternal() { if (getShowSoftInputOnFocus()) { showSoftKeyboard(); } + + return focused; + } + + // For cases like autoFocus, or ref.focus() where we request focus programatically and not through + // interacting with the EditText directly (like clicking on it). We cannot use stock + // requestFocus() because it will not pop up the soft keyboard, only clicking the input will do + // that. This method will eventually replace requestFocusInternal() + private boolean requestFocusProgramatically() { + boolean focused = super.requestFocus(View.FOCUS_DOWN, null); + if (isInTouchMode() && getShowSoftInputOnFocus()) { + showSoftKeyboard(); + } + return focused; } @@ -632,7 +656,11 @@ public void maybeUpdateTypeface() { // VisibleForTesting from {@link TextInputEventsTestCase}. public void requestFocusFromJS() { - requestFocusInternal(); + if (ReactNativeFeatureFlags.useEditTextStockAndroidFocusBehavior()) { + requestFocusProgramatically(); + } else { + requestFocusInternal(); + } } /* package */ void clearFocusFromJS() { @@ -1079,7 +1107,11 @@ public void onAttachedToWindow() { } if (mAutoFocus && !mDidAttachToWindow) { - requestFocusInternal(); + if (ReactNativeFeatureFlags.useEditTextStockAndroidFocusBehavior()) { + requestFocusProgramatically(); + } else { + requestFocusInternal(); + } } mDidAttachToWindow = true; 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 d3d0dc3ea1e040..97e7af5ae37ade 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<<7c3853858da56eb5f471abccf9dcbf55>> + * @generated SignedSource<<63ebe186ccd5ee30fc654aa8d90f27f9>> */ /** @@ -255,6 +255,12 @@ class ReactNativeFeatureFlagsProviderHolder return method(javaProvider_); } + bool useEditTextStockAndroidFocusBehavior() override { + static const auto method = + getReactNativeFeatureFlagsProviderJavaClass()->getMethod("useEditTextStockAndroidFocusBehavior"); + return method(javaProvider_); + } + bool useFabricInterop() override { static const auto method = getReactNativeFeatureFlagsProviderJavaClass()->getMethod("useFabricInterop"); @@ -493,6 +499,11 @@ bool JReactNativeFeatureFlagsCxxInterop::useAlwaysAvailableJSErrorHandling( return ReactNativeFeatureFlags::useAlwaysAvailableJSErrorHandling(); } +bool JReactNativeFeatureFlagsCxxInterop::useEditTextStockAndroidFocusBehavior( + facebook::jni::alias_ref /*unused*/) { + return ReactNativeFeatureFlags::useEditTextStockAndroidFocusBehavior(); +} + bool JReactNativeFeatureFlagsCxxInterop::useFabricInterop( facebook::jni::alias_ref /*unused*/) { return ReactNativeFeatureFlags::useFabricInterop(); @@ -677,6 +688,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() { makeNativeMethod( "useAlwaysAvailableJSErrorHandling", JReactNativeFeatureFlagsCxxInterop::useAlwaysAvailableJSErrorHandling), + makeNativeMethod( + "useEditTextStockAndroidFocusBehavior", + JReactNativeFeatureFlagsCxxInterop::useEditTextStockAndroidFocusBehavior), makeNativeMethod( "useFabricInterop", JReactNativeFeatureFlagsCxxInterop::useFabricInterop), 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 80ef331dff8352..f8631b2e947bc4 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<<77b4ed5aa33290ba9da1719544e974cb>> + * @generated SignedSource<> */ /** @@ -138,6 +138,9 @@ class JReactNativeFeatureFlagsCxxInterop static bool useAlwaysAvailableJSErrorHandling( facebook::jni::alias_ref); + static bool useEditTextStockAndroidFocusBehavior( + facebook::jni::alias_ref); + static bool useFabricInterop( facebook::jni::alias_ref); diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.kt index 91aabb17f3b80a..43de322a28c6f5 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.kt @@ -25,6 +25,7 @@ import com.facebook.react.bridge.BridgeReactContext import com.facebook.react.bridge.CatalystInstance import com.facebook.react.bridge.JavaOnlyMap import com.facebook.react.bridge.ReactTestHelper.createMockCatalystInstance +import com.facebook.react.internal.featureflags.ReactNativeFeatureFlagsForTests import com.facebook.react.uimanager.DisplayMetricsHolder import com.facebook.react.uimanager.ReactStylesDiffMap import com.facebook.react.uimanager.ThemedReactContext @@ -65,6 +66,7 @@ class ReactTextInputPropertyTest { manager = ReactTextInputManager() DisplayMetricsHolder.setWindowDisplayMetrics(DisplayMetrics()) view = manager.createViewInstance(themedContext) + ReactNativeFeatureFlagsForTests.setUp() } @Test diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp index f71795970ae0c7..3a27b0604c156c 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<<7d301656072183649246db8fa738fc4d>> + * @generated SignedSource<<58c69846193598ce0c3666c37b8a185f>> */ /** @@ -170,6 +170,10 @@ bool ReactNativeFeatureFlags::useAlwaysAvailableJSErrorHandling() { return getAccessor().useAlwaysAvailableJSErrorHandling(); } +bool ReactNativeFeatureFlags::useEditTextStockAndroidFocusBehavior() { + return getAccessor().useEditTextStockAndroidFocusBehavior(); +} + bool ReactNativeFeatureFlags::useFabricInterop() { return getAccessor().useFabricInterop(); } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h index 4d075604aa7da4..68b5c50f09744b 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<<1d578508c3cd69bbf9616a811508a03e>> */ /** @@ -219,6 +219,11 @@ class ReactNativeFeatureFlags { */ RN_EXPORT static bool useAlwaysAvailableJSErrorHandling(); + /** + * If true, focusing in ReactEditText will mainly use stock Android requestFocus() behavior. If false it will use legacy custom focus behavior. + */ + RN_EXPORT static bool useEditTextStockAndroidFocusBehavior(); + /** * Should this application enable the Fabric Interop Layer for Android? If yes, the application will behave so that it can accept non-Fabric components and render them on Fabric. This toggle is controlling extra logic such as custom event dispatching that are needed for the Fabric Interop Layer to work correctly. */ diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp index 4e528eff110880..8d1253b74d1bee 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<> + * @generated SignedSource<<42e2ae5cbfb15c17a7d60a771128858a>> */ /** @@ -677,6 +677,24 @@ bool ReactNativeFeatureFlagsAccessor::useAlwaysAvailableJSErrorHandling() { return flagValue.value(); } +bool ReactNativeFeatureFlagsAccessor::useEditTextStockAndroidFocusBehavior() { + auto flagValue = useEditTextStockAndroidFocusBehavior_.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(36, "useEditTextStockAndroidFocusBehavior"); + + flagValue = currentProvider_->useEditTextStockAndroidFocusBehavior(); + useEditTextStockAndroidFocusBehavior_ = flagValue; + } + + return flagValue.value(); +} + bool ReactNativeFeatureFlagsAccessor::useFabricInterop() { auto flagValue = useFabricInterop_.load(); @@ -686,7 +704,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(36, "useFabricInterop"); + markFlagAsAccessed(37, "useFabricInterop"); flagValue = currentProvider_->useFabricInterop(); useFabricInterop_ = flagValue; @@ -704,7 +722,7 @@ bool ReactNativeFeatureFlagsAccessor::useImmediateExecutorInAndroidBridgeless() // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(37, "useImmediateExecutorInAndroidBridgeless"); + markFlagAsAccessed(38, "useImmediateExecutorInAndroidBridgeless"); flagValue = currentProvider_->useImmediateExecutorInAndroidBridgeless(); useImmediateExecutorInAndroidBridgeless_ = flagValue; @@ -722,7 +740,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(38, "useNativeViewConfigsInBridgelessMode"); + markFlagAsAccessed(39, "useNativeViewConfigsInBridgelessMode"); flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode(); useNativeViewConfigsInBridgelessMode_ = flagValue; @@ -740,7 +758,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimisedViewPreallocationOnAndroid() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(39, "useOptimisedViewPreallocationOnAndroid"); + markFlagAsAccessed(40, "useOptimisedViewPreallocationOnAndroid"); flagValue = currentProvider_->useOptimisedViewPreallocationOnAndroid(); useOptimisedViewPreallocationOnAndroid_ = flagValue; @@ -758,7 +776,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(40, "useOptimizedEventBatchingOnAndroid"); + markFlagAsAccessed(41, "useOptimizedEventBatchingOnAndroid"); flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid(); useOptimizedEventBatchingOnAndroid_ = flagValue; @@ -776,7 +794,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(41, "useRawPropsJsiValue"); + markFlagAsAccessed(42, "useRawPropsJsiValue"); flagValue = currentProvider_->useRawPropsJsiValue(); useRawPropsJsiValue_ = flagValue; @@ -794,7 +812,7 @@ bool ReactNativeFeatureFlagsAccessor::useRuntimeShadowNodeReferenceUpdate() { // be accessing the provider multiple times but the end state of this // instance and the returned flag value would be the same. - markFlagAsAccessed(42, "useRuntimeShadowNodeReferenceUpdate"); + markFlagAsAccessed(43, "useRuntimeShadowNodeReferenceUpdate"); flagValue = currentProvider_->useRuntimeShadowNodeReferenceUpdate(); useRuntimeShadowNodeReferenceUpdate_ = flagValue; @@ -812,7 +830,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(43, "useTurboModuleInterop"); + markFlagAsAccessed(44, "useTurboModuleInterop"); flagValue = currentProvider_->useTurboModuleInterop(); useTurboModuleInterop_ = flagValue; @@ -830,7 +848,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(44, "useTurboModules"); + markFlagAsAccessed(45, "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 ac0c3e53a1dbd7..3c0468e8e04fa0 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<<8eb2b5d6dd367826ff7bc899afbdea60>> + * @generated SignedSource<<8423497c73f5315fdc3e8b4fa0bdc8c2>> */ /** @@ -68,6 +68,7 @@ class ReactNativeFeatureFlagsAccessor { bool loadVectorDrawablesOnImages(); bool traceTurboModulePromiseRejectionsOnAndroid(); bool useAlwaysAvailableJSErrorHandling(); + bool useEditTextStockAndroidFocusBehavior(); bool useFabricInterop(); bool useImmediateExecutorInAndroidBridgeless(); bool useNativeViewConfigsInBridgelessMode(); @@ -88,7 +89,7 @@ class ReactNativeFeatureFlagsAccessor { std::unique_ptr currentProvider_; bool wasOverridden_; - std::array, 45> accessedFeatureFlags_; + std::array, 46> accessedFeatureFlags_; std::atomic> commonTestFlag_; std::atomic> completeReactInstanceCreationOnBgThreadOnAndroid_; @@ -126,6 +127,7 @@ class ReactNativeFeatureFlagsAccessor { std::atomic> loadVectorDrawablesOnImages_; std::atomic> traceTurboModulePromiseRejectionsOnAndroid_; std::atomic> useAlwaysAvailableJSErrorHandling_; + std::atomic> useEditTextStockAndroidFocusBehavior_; std::atomic> useFabricInterop_; std::atomic> useImmediateExecutorInAndroidBridgeless_; std::atomic> useNativeViewConfigsInBridgelessMode_; diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index aec774f80d20dc..8f0a2fabb42aac 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<> */ /** @@ -171,6 +171,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { return false; } + bool useEditTextStockAndroidFocusBehavior() override { + return true; + } + bool useFabricInterop() override { return false; } diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h index 5a6b8a82ae33f2..7fd97a9b561519 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<> + * @generated SignedSource<<179524938d2e6148ef87835844c4135e>> */ /** @@ -369,6 +369,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef return ReactNativeFeatureFlagsDefaults::useAlwaysAvailableJSErrorHandling(); } + bool useEditTextStockAndroidFocusBehavior() override { + auto value = values_["useEditTextStockAndroidFocusBehavior"]; + if (!value.isNull()) { + return value.getBool(); + } + + return ReactNativeFeatureFlagsDefaults::useEditTextStockAndroidFocusBehavior(); + } + bool useFabricInterop() override { auto value = values_["useFabricInterop"]; if (!value.isNull()) { diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h index c89d65c0d88b54..9975fc02014384 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<<36bfe0037e4dba3b6eb6e95075914fce>> + * @generated SignedSource<> */ /** @@ -61,6 +61,7 @@ class ReactNativeFeatureFlagsProvider { virtual bool loadVectorDrawablesOnImages() = 0; virtual bool traceTurboModulePromiseRejectionsOnAndroid() = 0; virtual bool useAlwaysAvailableJSErrorHandling() = 0; + virtual bool useEditTextStockAndroidFocusBehavior() = 0; virtual bool useFabricInterop() = 0; virtual bool useImmediateExecutorInAndroidBridgeless() = 0; virtual bool useNativeViewConfigsInBridgelessMode() = 0; diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp index f326fcd073b5f8..f8108b98f97470 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<<81f3e20643ddb2612eaa9276bb75e70e>> */ /** @@ -224,6 +224,11 @@ bool NativeReactNativeFeatureFlags::useAlwaysAvailableJSErrorHandling( return ReactNativeFeatureFlags::useAlwaysAvailableJSErrorHandling(); } +bool NativeReactNativeFeatureFlags::useEditTextStockAndroidFocusBehavior( + jsi::Runtime& /*runtime*/) { + return ReactNativeFeatureFlags::useEditTextStockAndroidFocusBehavior(); +} + bool NativeReactNativeFeatureFlags::useFabricInterop( jsi::Runtime& /*runtime*/) { return ReactNativeFeatureFlags::useFabricInterop(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h b/packages/react-native/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h index 7f4364d355d522..b96b81b87853ef 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<<0852372c6b328f128319949a01aa8787>> */ /** @@ -109,6 +109,8 @@ class NativeReactNativeFeatureFlags bool useAlwaysAvailableJSErrorHandling(jsi::Runtime& runtime); + bool useEditTextStockAndroidFocusBehavior(jsi::Runtime& runtime); + bool useFabricInterop(jsi::Runtime& runtime); bool useImmediateExecutorInAndroidBridgeless(jsi::Runtime& runtime); diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index 9be0b03e20a2ab..2248bae913f5cb 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -390,6 +390,15 @@ const definitions: FeatureFlagDefinitions = { purpose: 'release', }, }, + useEditTextStockAndroidFocusBehavior: { + defaultValue: true, + metadata: { + description: + 'If true, focusing in ReactEditText will mainly use stock Android requestFocus() behavior. If false it will use legacy custom focus behavior.', + expectedReleaseValue: true, + purpose: 'release', + }, + }, useFabricInterop: { defaultValue: false, metadata: { diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index 9e3e918b870ee3..b97da614d309b6 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<<3bdec862f75745ce81e9cf23fef82468>> + * @generated SignedSource<> * @flow strict */ @@ -87,6 +87,7 @@ export type ReactNativeFeatureFlags = $ReadOnly<{ loadVectorDrawablesOnImages: Getter, traceTurboModulePromiseRejectionsOnAndroid: Getter, useAlwaysAvailableJSErrorHandling: Getter, + useEditTextStockAndroidFocusBehavior: Getter, useFabricInterop: Getter, useImmediateExecutorInAndroidBridgeless: Getter, useNativeViewConfigsInBridgelessMode: Getter, @@ -331,6 +332,10 @@ export const traceTurboModulePromiseRejectionsOnAndroid: Getter = creat * In Bridgeless mode, use the always available javascript error reporting pipeline. */ export const useAlwaysAvailableJSErrorHandling: Getter = createNativeFlagGetter('useAlwaysAvailableJSErrorHandling', false); +/** + * If true, focusing in ReactEditText will mainly use stock Android requestFocus() behavior. If false it will use legacy custom focus behavior. + */ +export const useEditTextStockAndroidFocusBehavior: Getter = createNativeFlagGetter('useEditTextStockAndroidFocusBehavior', true); /** * Should this application enable the Fabric Interop Layer for Android? If yes, the application will behave so that it can accept non-Fabric components and render them on Fabric. This toggle is controlling extra logic such as custom event dispatching that are needed for the Fabric Interop Layer to work correctly. */ diff --git a/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js index f9f4a5bc187baf..5a0c476acbb924 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<<37e95652ef5d824bb05e78ebdb051e43>> + * @generated SignedSource<<9fd249e6c81d4aaa9793c003d986524c>> * @flow strict */ @@ -60,6 +60,7 @@ export interface Spec extends TurboModule { +loadVectorDrawablesOnImages?: () => boolean; +traceTurboModulePromiseRejectionsOnAndroid?: () => boolean; +useAlwaysAvailableJSErrorHandling?: () => boolean; + +useEditTextStockAndroidFocusBehavior?: () => boolean; +useFabricInterop?: () => boolean; +useImmediateExecutorInAndroidBridgeless?: () => boolean; +useNativeViewConfigsInBridgelessMode?: () => boolean;