diff --git a/framework/src/org/apache/cordova/CoreAndroid.java b/framework/src/org/apache/cordova/CoreAndroid.java index a41b85db..969cc296 100755 --- a/framework/src/org/apache/cordova/CoreAndroid.java +++ b/framework/src/org/apache/cordova/CoreAndroid.java @@ -29,6 +29,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Build; +import android.os.SystemClock; import android.content.IntentFilter; import android.telephony.TelephonyManager; import android.view.KeyEvent; @@ -253,7 +254,6 @@ public class CoreAndroid extends CordovaPlugin { * @param override T=override, F=cancel override */ public void overrideBackbutton(boolean override) { - LOG.i("App", "WARNING: Back Button Default Behavior will be overridden. The backbutton event will be fired!"); if (cordova.getActivity() == null) { return; } @@ -263,15 +263,24 @@ public class CoreAndroid extends CordovaPlugin { @Override public void run() { if (shouldOverride) { + LOG.i("App", "WARNING: Back Button Default Behavior will be overridden. The backbutton event will be fired!"); synchronized (backButtonHandlerLock) { if (backCallback == null) { - registerBackPressedCallback(); + backCallback = new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + dispatchBackKeyEvent(); + } + }; + OnBackPressedDispatcherOwner backPressedDispatcherOwner = cordova.getActivity(); + backPressedDispatcherOwner.getOnBackPressedDispatcher().addCallback(backPressedDispatcherOwner, backCallback); } } } else { synchronized (backButtonHandlerLock) { if (backCallback != null) { - unregisterBackPressedCallback(); + backCallback.remove(); + backCallback = null; } } } @@ -281,29 +290,29 @@ public class CoreAndroid extends CordovaPlugin { }); } - /** - * Registers an AndroidX back callback so Cordova can keep routing back presses through its - * existing key dispatch path across Android versions without directly referencing newer - * platform-only back APIs. - */ - private void registerBackPressedCallback() { - final OnBackPressedDispatcherOwner backPressedDispatcherOwner = this.cordova.getActivity(); + private void dispatchBackKeyEvent() { + // Build a synthetic BACK key press (DOWN + UP) and route it through the WebView. + // This lets Cordova's existing key handling fire the JS "backbutton" event. + final long eventTime = SystemClock.uptimeMillis(); + final KeyEvent downEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK, 0); + final KeyEvent upEvent = new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK, 0); - backCallback = new OnBackPressedCallback(true) { - @Override - public void handleOnBackPressed() { - // Intentionally empty. - // On modern Android versions, registering a callback keeps back handling - // routed through Cordova's existing key dispatch path. - } - }; + final boolean handledDown = webView.getView().dispatchKeyEvent(downEvent); + final boolean handledUp = webView.getView().dispatchKeyEvent(upEvent); - backPressedDispatcherOwner.getOnBackPressedDispatcher().addCallback(backPressedDispatcherOwner, backCallback); - } + // If either event was consumed, Cordova/WebView already handled back behavior. + if (handledDown || handledUp) { + return; + } - private void unregisterBackPressedCallback() { - backCallback.remove(); - backCallback = null; + // Otherwise, delegate to Android's default back dispatcher. + // Temporarily disable this callback to avoid recursive re-entry. + backCallback.setEnabled(false); + try { + cordova.getActivity().getOnBackPressedDispatcher().onBackPressed(); + } finally { + backCallback.setEnabled(true); + } } /**