From 19c16f8b4e3bbb77c8dce8b4cc5e77df6d1110d6 Mon Sep 17 00:00:00 2001 From: Gleap Coder Agent Date: Tue, 3 Mar 2026 15:46:49 +0100 Subject: [PATCH 1/2] Coder Agent: Fix an Android SDK bug where tapping the chat text input field causes the chat UI to crash into a loading state with a blank pink/magenta screen. After a recent SDK update, users on Android (specific --- gleap/src/main/AndroidManifest.xml | 2 +- .../main/java/io/gleap/GleapMainActivity.java | 50 ++++++++++++++++--- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/gleap/src/main/AndroidManifest.xml b/gleap/src/main/AndroidManifest.xml index 53dc437..97294d0 100644 --- a/gleap/src/main/AndroidManifest.xml +++ b/gleap/src/main/AndroidManifest.xml @@ -7,7 +7,7 @@ diff --git a/gleap/src/main/java/io/gleap/GleapMainActivity.java b/gleap/src/main/java/io/gleap/GleapMainActivity.java index cc06ae7..ed39246 100644 --- a/gleap/src/main/java/io/gleap/GleapMainActivity.java +++ b/gleap/src/main/java/io/gleap/GleapMainActivity.java @@ -7,6 +7,7 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; +import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; @@ -197,7 +198,12 @@ public void handleOnBackPressed() { this.requestWindowFeature(Window.FEATURE_NO_TITLE); try { - getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + // SOFT_INPUT_ADJUST_RESIZE is deprecated on API 30+ and ignored on API 35+. + // On API 30+ we rely solely on the WindowInsetsCompat listener for keyboard + // handling; on older versions we keep the legacy flag for compatibility. + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + } if (getSupportActionBar() != null) { getSupportActionBar().hide(); } @@ -285,9 +291,19 @@ public void invoke() { @Override public void run() { url += GleapURLGenerator.generateURL(); - initBrowser(); if (savedInstanceState != null) { - webView.restoreState(savedInstanceState); + // Activity was recreated (e.g. process killed in background). + // Set up WebView clients/settings but skip loading a new URL; + // restoreState will navigate back to the previous page. + initBrowserSettings(); + android.webkit.WebBackForwardList restored = webView.restoreState(savedInstanceState); + if (restored == null) { + // restoreState failed — fall back to a full reload. + webView.loadUrl(url); + } + } else { + // Fresh start — initialise everything and load the URL. + initBrowser(); } } }); @@ -308,6 +324,15 @@ protected void onRestoreInstanceState(Bundle savedInstanceState) { webView.restoreState(savedInstanceState); } + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + super.onConfigurationChanged(newConfig); + // Intentionally empty — we declared the relevant configChanges in the + // manifest so the system delivers them here instead of recreating the + // activity. This keeps the WebView (and its chat state) alive when the + // soft keyboard appears/disappears or the screen layout changes. + } + @Override protected void onDestroy() { try { @@ -359,7 +384,12 @@ protected void onDestroy() { super.onDestroy(); } - private void initBrowser() { + /** + * Configure WebView settings, clients and JS bridge without loading a URL. + * Call this when restoring from saved state so the WebView is properly + * wired up before {@code restoreState()} navigates to the previous page. + */ + private void initBrowserSettings() { WebSettings settings = webView.getSettings(); settings.setJavaScriptEnabled(true); settings.setDomStorageEnabled(true); @@ -443,10 +473,16 @@ public boolean onShowFileChooser(WebView webView, ValueCallback filePathC } } }); - webView.loadUrl(url); webView.setVisibility(View.INVISIBLE); - settings.setUseWideViewPort(true); - settings.setLoadWithOverviewMode(true); + } + + /** + * Full browser initialisation: configure settings, clients and load the URL. + * Used on a fresh start (no saved instance state). + */ + private void initBrowser() { + initBrowserSettings(); + webView.loadUrl(url); } public void askForPermission(String origin, String androidPermission, String webkitPermission, int requestCode) { From 668fb811b6de18cb49217842db7bab178b1f74bd Mon Sep 17 00:00:00 2001 From: Gleap Coder Agent Date: Tue, 3 Mar 2026 16:47:31 +0100 Subject: [PATCH 2/2] Coder Agent: Fix a bug where the Android chat view goes blank with an infinite loading spinner when the keyboard opens after tapping the text input field. After a recent SDK update, on a Samsung Galaxy S22 Ultra --- gleap/src/main/AndroidManifest.xml | 1 + .../main/java/io/gleap/GleapMainActivity.java | 39 ++++++++++--------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/gleap/src/main/AndroidManifest.xml b/gleap/src/main/AndroidManifest.xml index 97294d0..7018e74 100644 --- a/gleap/src/main/AndroidManifest.xml +++ b/gleap/src/main/AndroidManifest.xml @@ -8,6 +8,7 @@ diff --git a/gleap/src/main/java/io/gleap/GleapMainActivity.java b/gleap/src/main/java/io/gleap/GleapMainActivity.java index ed39246..eee795c 100644 --- a/gleap/src/main/java/io/gleap/GleapMainActivity.java +++ b/gleap/src/main/java/io/gleap/GleapMainActivity.java @@ -198,12 +198,12 @@ public void handleOnBackPressed() { this.requestWindowFeature(Window.FEATURE_NO_TITLE); try { - // SOFT_INPUT_ADJUST_RESIZE is deprecated on API 30+ and ignored on API 35+. - // On API 30+ we rely solely on the WindowInsetsCompat listener for keyboard - // handling; on older versions we keep the legacy flag for compatibility. - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { - getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); - } + // SOFT_INPUT_ADJUST_RESIZE is deprecated on API 30+ but still honoured + // for apps that target SDK < 35 (this SDK targets 33). Setting it + // unconditionally ensures the window shrinks for the keyboard on every + // device – including Android 16 / Samsung One UI 8.0 – so the WebView + // content remains visible without needing a separate IME-insets handler. + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); if (getSupportActionBar() != null) { getSupportActionBar().hide(); } @@ -220,25 +220,24 @@ public void handleOnBackPressed() { final FrameLayout webViewContainer = findViewById(R.id.webview_container); + // Handle system-bar insets (status bar, navigation bar) so the + // WebView content is not drawn behind them. We intentionally + // do NOT include IME insets here: the keyboard resize is fully + // handled by SOFT_INPUT_ADJUST_RESIZE which shrinks the window + // itself. Adding IME padding on top of that would double-shift + // the content -- the root cause of the blank-screen-on-keyboard + // bug on Android 16 / Samsung One UI 8.0. ViewCompat.setOnApplyWindowInsetsListener(webViewContainer, (view, insets) -> { - // status + navigation bars (stable system bars) Insets bars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); - // on Android 11+ this is the real keyboard height; - // on older versions it’s 0 – but then the IME is reported as a system‑bar inset - Insets ime = insets.getInsets(WindowInsetsCompat.Type.ime()); - - int topInset = bars.top; // keep the status‑bar height - int bottomInset = Math.max(bars.bottom, ime.bottom); // choose the larger of nav‑bar or IME - view.setPadding(view.getPaddingLeft(), - topInset, + bars.top, view.getPaddingRight(), - bottomInset); + bars.bottom); - return insets; // DON’T consume – let child views see the same insets + return insets; }); int backgroundColor = Color.parseColor(GleapConfig.getInstance().getBackgroundColor()); @@ -321,7 +320,11 @@ protected void onSaveInstanceState(Bundle outState) { @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); - webView.restoreState(savedInstanceState); + // Do NOT call webView.restoreState() here. The posted runnable in + // onCreate already handles restoration after the WebView clients are + // wired up via initBrowserSettings(). Calling restoreState() here + // would consume the Bundle's WebView state before that runnable + // executes, forcing an unnecessary full URL reload every time. } @Override