From a442367706d1bde3b29232a351e62f749559560d Mon Sep 17 00:00:00 2001 From: klirktag Date: Sun, 21 Jun 2026 13:36:55 +0200 Subject: [PATCH] Android: hide system bars via WindowInsetsController on API 30+ The immersive-fullscreen code hid the status and navigation bars with the deprecated View.setSystemUiVisibility() flags plus FLAG_FULLSCREEN. On Android 15+ (API 35), edge-to-edge is enforced for apps targeting SDK 35+ and those flags are ignored, so the bars never hide (e.g. on a Samsung S25). Android 14 and below still honour them, which is why older devices were unaffected. Hide/show the system bars with WindowInsetsController on API 30+ (using BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE for sticky-immersive), keeping the legacy setSystemUiVisibility() path for API < 30. The minimum supported version is unchanged. --- .../main/java/org/libsdl/app/SDLActivity.java | 60 ++++++++++++++----- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java index ef77381b50..e213f495b9 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java @@ -38,6 +38,8 @@ import android.view.Surface; import android.view.View; import android.view.ViewGroup; import android.view.Window; +import android.view.WindowInsets; +import android.view.WindowInsetsController; import android.view.WindowManager; import android.view.inputmethod.BaseInputConnection; import android.view.inputmethod.EditorInfo; @@ -773,21 +775,45 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh Window window = ((Activity) context).getWindow(); if (window != null) { if ((msg.obj instanceof Integer) && ((Integer) msg.obj != 0)) { - int flags = View.SYSTEM_UI_FLAG_FULLSCREEN | - View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | - View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | - View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.INVISIBLE; - window.getDecorView().setSystemUiVisibility(flags); - window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); - window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); + if (Build.VERSION.SDK_INT >= 30 /* Android 11 (R) */) { + // The legacy setSystemUiVisibility() flags are ignored on + // Android 15+ (API 35+), where edge-to-edge is enforced for + // apps targeting that SDK, so the status/navigation bars + // would never hide. Use WindowInsetsController instead. + window.setDecorFitsSystemWindows(false); + final WindowInsetsController controller = window.getInsetsController(); + if (controller != null) { + controller.hide(WindowInsets.Type.systemBars()); + // Sticky-immersive (replaces SYSTEM_UI_FLAG_IMMERSIVE_STICKY): + // a swipe shows the bars transiently, then they auto-hide. + controller.setSystemBarsBehavior( + WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE); + } + } else { + int flags = View.SYSTEM_UI_FLAG_FULLSCREEN | + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.INVISIBLE; + window.getDecorView().setSystemUiVisibility(flags); + window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); + } SDLActivity.mFullscreenModeActive = true; } else { - int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_VISIBLE; - window.getDecorView().setSystemUiVisibility(flags); - window.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); - window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + if (Build.VERSION.SDK_INT >= 30 /* Android 11 (R) */) { + window.setDecorFitsSystemWindows(true); + final WindowInsetsController controller = window.getInsetsController(); + if (controller != null) { + controller.show(WindowInsets.Type.systemBars()); + } + } else { + int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_VISIBLE; + window.getDecorView().setSystemUiVisibility(flags); + window.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); + window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + } SDLActivity.mFullscreenModeActive = false; } if (Build.VERSION.SDK_INT >= 28 /* Android 9 (Pie) */) { @@ -1623,7 +1649,13 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh private final Runnable rehideSystemUi = new Runnable() { @Override public void run() { - if (Build.VERSION.SDK_INT >= 19 /* Android 4.4 (KITKAT) */) { + if (Build.VERSION.SDK_INT >= 30 /* Android 11 (R) */) { + final WindowInsetsController controller = + SDLActivity.this.getWindow().getInsetsController(); + if (controller != null) { + controller.hide(WindowInsets.Type.systemBars()); + } + } else if (Build.VERSION.SDK_INT >= 19 /* Android 4.4 (KITKAT) */) { int flags = View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |