diff --git a/gleap/src/main/AndroidManifest.xml b/gleap/src/main/AndroidManifest.xml
index 53dc437..7018e74 100644
--- a/gleap/src/main/AndroidManifest.xml
+++ b/gleap/src/main/AndroidManifest.xml
@@ -7,7 +7,8 @@
diff --git a/gleap/src/main/java/io/gleap/GleapMainActivity.java b/gleap/src/main/java/io/gleap/GleapMainActivity.java
index cc06ae7..eee795c 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,6 +198,11 @@ public void handleOnBackPressed() {
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
try {
+ // 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();
@@ -214,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());
@@ -285,9 +290,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();
}
}
});
@@ -305,7 +320,20 @@ 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
+ 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
@@ -359,7 +387,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 +476,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) {