Repository navigation
fix(android): handle each back action once - #2029
GitToTheHub wants to merge 1 commit into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #2029 +/- ##
=======================================
Coverage 63.20% 63.20%
=======================================
Files 24 24
Lines 4922 4922
=======================================
Hits 3111 3111
Misses 1811 1811 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
| Intent intent = new Intent(); | ||
| intent.putExtra("startUrl", "https://localhost/backbuttondispatch/index.html"); | ||
| activity = activityRule.launchActivity(intent); | ||
| webView = (WebView) activity.getWebInterface().getView(); |
There was a problem hiding this comment.
This test retrieves the existing Cordova WebView; it does not enable content access or change any WebView security settings. The finding exposes the existing WebView configuration through the new test. Any production change to content:// access should be considered in a separate PR with compatibility coverage, so this back-button fix remains focused.
|
|
||
| private boolean performBackButtonAction() { | ||
| if (mCustomView != null) { | ||
| hideCustomView(); |
There was a problem hiding this comment.
This call already existed in the Back key handler and has been moved into the shared back-action helper. Preserving custom-view dismissal is necessary so closing a full-screen view does not also fire backbutton and navigate the app. Modernizing the deprecated custom-view API should be handled separately; this PR preserves the existing behavior.
| activity.getWebInterface().showCustomView(new View(activity), | ||
| () -> customViewHidden.set(true)); |
There was a problem hiding this comment.
The regression test deliberately exercises the existing showCustomView API to verify that a Back action dismisses the custom view once without also firing a JavaScript backbutton event. The API is deprecated, but the behavior is still supported and needs coverage. Custom-view API modernization can be handled in a separate PR.
| private String evaluate(String script) throws Throwable { | ||
| ArrayBlockingQueue<String> result = new ArrayBlockingQueue<>(1); | ||
| activityRule.runOnUiThread(() -> webView.evaluateJavascript(script, result::add)); | ||
| String value = result.poll(10, TimeUnit.SECONDS); |
There was a problem hiding this comment.
This appears to be a false positive. value is read immediately after this assignment by assertNotNull("JavaScript evaluation timed out", value) and then returned with return value;. Keeping the local variable allows the test to report a clear timeout failure before returning the JavaScript result.
|
Tested this branch (cordova-android 15.1.1-dev.0) with the repro app https://github.com/2zovd/cordova-backbutton-repro on an Android 16 (API 36) emulator, Pixel 9, WebView 153.
With 15.1.0 the same app gets 2 events per Back key press, 0.4 ms apart. I did not see such pairs with this branch. Thanks for the quick fix! |

Platforms affected
Android
Motivation and Context
On Android 16, one Back key press can invoke the AndroidX back callback and then deliver the original key to the WebView. Cordova's synthetic key redispatch therefore fires
backbuttontwice, causing applications to navigate back two screens. Edge swipes fire once.Fixes #2028.
Description
Replace synthetic DOWN/UP keys with a shared back-action handler. Callbacks and legacy key releases use the same action order: dismiss a custom view, notify a JavaScript
backbuttonlistener, or navigate WebView history. Unhandled callback actions delegate to Android with the callback temporarily disabled to avoid recursion.Keep a single callback timestamp in the WebView to consume an original key already handled by the callback. Clear it when the JavaScript override is removed. This avoids a debounce interval and preserves rapid consecutive inputs.
Testing
npm run lint, all 335npm run unit-testsspecs, andgit diff --checkpass.The existing instrumentation project does not build unmodified: Kotlin stdlib versions conflict,
androidx.test:rulesis missing, andBackButtonMultipageTesthas an unhandledInterruptedException. For the targeted run, a temporary Gradle init script aligned Kotlin jdk7/jdk8 to 1.8.22, addedandroidx.test:rules:1.1.1, and limited instrumentation compilation toBackButtonDispatchTest. The APK build excluded the unrelated:CordovaLib:extractDebugAnnotationstask. Those infrastructure workarounds are not part of this PR. The full instrumentation suite and Android 14 or older were not verified.Checklist
(platform)if this change only applies to one platform