From 40aa5c05ad8ad9ce2dc215c7b7dfe948c692c401 Mon Sep 17 00:00:00 2001 From: Dimitris Dafnis <68849116+jim-daf@users.noreply.github.com> Date: Tue, 21 Apr 2026 21:54:15 +0200 Subject: [PATCH] fix(DefaultUIController): guard SSL-error dialog against finishing activity (#1065) Resolves #1065 The crash reported in #1065 is a WindowManager$BadTokenException raised from DefaultUIController.onShowSslCertificateErrorDialog when AlertDialog is shown after the hosting Activity has already started its finishing/destroyed teardown. The WebView delivers SSL error callbacks on the main thread and there is no guarantee the cached mActivity is still in a state where it can host a dialog. This change short-circuits the path when the activity is null, finishing, or destroyed, calling handler.cancel() in that case so we fail safe rather than crash. The same check is repeated immediately before AlertDialog.show(), and the show() call itself is wrapped in a try/catch for the residual race where the activity transitions between our last check and the platform call. --- .../just/agentweb/DefaultUIController.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/agentweb-core/src/main/java/com/just/agentweb/DefaultUIController.java b/agentweb-core/src/main/java/com/just/agentweb/DefaultUIController.java index bbd2224d..85129c4a 100644 --- a/agentweb-core/src/main/java/com/just/agentweb/DefaultUIController.java +++ b/agentweb-core/src/main/java/com/just/agentweb/DefaultUIController.java @@ -367,6 +367,15 @@ public void onPermissionsDeny(String[] permissions, String permissionType, Strin @Override public void onShowSslCertificateErrorDialog(final WebView view, final SslErrorHandler handler, final SslError error) { + // Issue #1065: Activity may already be finishing/destroyed by the time the + // WebView delivers the SSL error callback on the main thread. Showing a + // dialog against a stale window token throws WindowManager$BadTokenException. + // Fail safe by cancelling the request when we cannot present UI. + if (mActivity == null || mActivity.isFinishing() + || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && mActivity.isDestroyed())) { + handler.cancel(); + return; + } AlertDialog.Builder alertDialog = new AlertDialog.Builder(mActivity); String sslErrorMessage; switch (error.getPrimaryError()) { @@ -402,7 +411,18 @@ public void onClick(DialogInterface dialog, int which) { handler.cancel(); } }); - alertDialog.show(); + // Re-check just before show in case the activity transitioned during string lookup. + if (mActivity.isFinishing() + || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && mActivity.isDestroyed())) { + handler.cancel(); + return; + } + try { + alertDialog.show(); + } catch (android.view.WindowManager.BadTokenException | IllegalStateException e) { + // Activity window went away between our check and show(); fail safe. + handler.cancel(); + } }