diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java index 757ba90d5be..031f534afec 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactActivity.java @@ -11,11 +11,13 @@ import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; import android.view.KeyEvent; +import androidx.activity.OnBackPressedCallback; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; import com.facebook.react.modules.core.PermissionAwareActivity; import com.facebook.react.modules.core.PermissionListener; +import com.facebook.react.util.AndroidVersion; import org.jetbrains.annotations.NotNull; /** Base Activity for React Native applications. */ @@ -24,6 +26,18 @@ public abstract class ReactActivity extends AppCompatActivity private final ReactActivityDelegate mDelegate; + // Due to enforced predictive back on targetSdk 36, 'onBackPressed()' is disabled by default. + // Using a workaround to trigger it manually. + private final OnBackPressedCallback mBackPressedCallback = + new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + setEnabled(false); + onBackPressed(); + setEnabled(true); + } + }; + protected ReactActivity() { mDelegate = createReactActivityDelegate(); } @@ -45,6 +59,9 @@ public abstract class ReactActivity extends AppCompatActivity protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mDelegate.onCreate(savedInstanceState); + if (AndroidVersion.isAtLeastTargetSdk36(this)) { + getOnBackPressedDispatcher().addCallback(this, mBackPressedCallback); + } } @Override @@ -103,6 +120,9 @@ public abstract class ReactActivity extends AppCompatActivity @Override public void invokeDefaultOnBackPressed() { + // Disabling callback so the fallback logic (finish activity) can run + // as super.onBackPressed() will call all enabled callbacks in the dispatcher. + mBackPressedCallback.setEnabled(false); super.onBackPressed(); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/util/AndroidVersion.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/util/AndroidVersion.kt new file mode 100644 index 00000000000..325ab60f901 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/util/AndroidVersion.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.util + +import android.content.Context +import android.os.Build + +/** Helper class for checking Android version-related information. */ +internal object AndroidVersion { + + /** + * This is the version code for Android 16 (SDK Level 36). Delete it once we bump up the default + * compile SDK version to 36. + */ + private const val VERSION_CODE_BAKLAVA: Int = 36 + + /** + * This method is used to check if the current device is running Android 16 (SDK Level 36) or + * higher and the app is targeting Android 16 (SDK Level 36) or higher. + */ + @JvmStatic + fun isAtLeastTargetSdk36(context: Context): Boolean = + Build.VERSION.SDK_INT >= VERSION_CODE_BAKLAVA && + context.applicationInfo.targetSdkVersion >= VERSION_CODE_BAKLAVA +}