summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/android/jar/CMakeLists.txt1
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java6
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java15
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java18
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java354
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtWindowInsetsController.java358
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtWindowInterface.java1
-rw-r--r--src/plugins/platforms/android/qandroidplatformtheme.cpp6
-rw-r--r--src/plugins/platforms/android/qandroidplatformwindow.cpp16
9 files changed, 386 insertions, 389 deletions
diff --git a/src/android/jar/CMakeLists.txt b/src/android/jar/CMakeLists.txt
index b073dbea0ea..e0a675ab463 100644
--- a/src/android/jar/CMakeLists.txt
+++ b/src/android/jar/CMakeLists.txt
@@ -53,6 +53,7 @@ set(java_sources
src/org/qtproject/qt/android/BackgroundActionsTracker.java
src/org/qtproject/qt/android/QtApkFileEngine.java
src/org/qtproject/qt/android/QtContentFileEngine.java
+ src/org/qtproject/qt/android/QtWindowInsetsController.java
)
qt_internal_add_jar(Qt${QtBase_VERSION_MAJOR}Android
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java
index f3083969a89..78763e65905 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java
@@ -170,7 +170,7 @@ public class QtActivityBase extends Activity
m_delegate.displayManager().registerDisplayListener();
QtWindow.updateWindows();
// Suspending the app clears the immersive mode, so we need to set it again.
- m_delegate.displayManager().restoreFullScreenVisibility(this);
+ QtWindowInsetsController.restoreFullScreenVisibility(this);
}
}
@@ -313,7 +313,7 @@ public class QtActivityBase extends Activity
return;
QtNative.setStarted(savedInstanceState.getBoolean("Started"));
- m_delegate.displayManager().restoreFullScreenVisibility(this);
+ QtWindowInsetsController.restoreFullScreenVisibility(this);
// FIXME restore all surfaces
}
@@ -337,7 +337,7 @@ public class QtActivityBase extends Activity
{
super.onWindowFocusChanged(hasFocus);
if (hasFocus)
- m_delegate.displayManager().restoreFullScreenVisibility(this);
+ QtWindowInsetsController.restoreFullScreenVisibility(this);
}
@Override
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java
index 066fe14f5db..aa2964c3ae9 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java
@@ -86,21 +86,6 @@ class QtActivityDelegate extends QtActivityDelegateBase
}
@Override
- public void setSystemUiVisibility(boolean isFullScreen, boolean expandedToCutout)
- {
- if (m_layout == null)
- return;
-
- QtNative.runAction(() -> {
- if (m_layout != null) {
- m_displayManager.setSystemUiVisibility(isFullScreen, expandedToCutout);
- QtWindow.updateWindows();
- }
- });
- }
-
-
- @Override
final public void onAppStateDetailsChanged(QtNative.ApplicationStateDetails details) {
if (details.isStarted)
registerBackends();
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java
index 7916025ddc8..7f6163f164d 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java
@@ -47,7 +47,7 @@ abstract class QtActivityDelegateBase
QtNative.setActivity(m_activity);
m_displayManager = new QtDisplayManager(m_activity);
m_inputDelegate = new QtInputDelegate(() -> {
- m_displayManager.restoreFullScreenVisibility(m_activity);
+ QtWindowInsetsController.restoreFullScreenVisibility(m_activity);
});
m_accessibilityDelegate = new QtAccessibilityDelegate();
}
@@ -107,20 +107,20 @@ abstract class QtActivityDelegateBase
Configuration config = resources.getConfiguration();
int uiMode = config.uiMode & Configuration.UI_MODE_NIGHT_MASK;
- if (QtDisplayManager.decorFitsSystemWindows(m_activity)) {
+ if (QtWindowInsetsController.decorFitsSystemWindows(m_activity)) {
Window window = m_activity.getWindow();
- QtDisplayManager.enableSystemBarsBackgroundDrawing(window);
- int status = QtDisplayManager.getThemeDefaultStatusBarColor(m_activity);
- QtDisplayManager.setStatusBarColor(window, status);
- int nav = QtDisplayManager.getThemeDefaultNavigationBarColor(m_activity);
- QtDisplayManager.setNavigationBarColor(window, nav);
+ QtWindowInsetsController.enableSystemBarsBackgroundDrawing(window);
+ int status = QtWindowInsetsController.getThemeDefaultStatusBarColor(m_activity);
+ QtWindowInsetsController.setStatusBarColor(window, status);
+ int nav = QtWindowInsetsController.getThemeDefaultNavigationBarColor(m_activity);
+ QtWindowInsetsController.setNavigationBarColor(window, nav);
}
// Don't override color scheme if the app has it set explicitly.
if (canOverrideColorSchemeHint()) {
boolean isLight = uiMode == Configuration.UI_MODE_NIGHT_NO;
- QtDisplayManager.setStatusBarColorHint(m_activity, isLight);
- QtDisplayManager.setNavigationBarColorHint(m_activity, isLight);
+ QtWindowInsetsController.setStatusBarColorHint(m_activity, isLight);
+ QtWindowInsetsController.setNavigationBarColorHint(m_activity, isLight);
}
switch (uiMode) {
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java b/src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java
index 7d03941ff01..2cabb951813 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java
@@ -7,7 +7,6 @@ import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.Build;
@@ -15,22 +14,13 @@ import android.util.DisplayMetrics;
import android.util.Size;
import android.view.Display;
import android.view.Surface;
-import android.view.View;
-import android.view.WindowInsets;
import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
import android.view.WindowMetrics;
-import android.view.WindowInsetsController;
-import android.view.Window;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import android.graphics.Color;
-import android.util.TypedValue;
-import android.content.res.Resources.Theme;
-
import android.util.Log;
class QtDisplayManager
@@ -132,350 +122,6 @@ class QtDisplayManager
displayManager.unregisterDisplayListener(m_displayListener);
}
- /*
- * Convenience method to call deprecated API prior to Android R (30).
- */
- @SuppressWarnings ("deprecation")
- private static void setDecorFitsSystemWindows(Window window, boolean enable)
- {
- final int sdk = Build.VERSION.SDK_INT;
- if (sdk < Build.VERSION_CODES.R || sdk > Build.VERSION_CODES.VANILLA_ICE_CREAM)
- return;
- window.setDecorFitsSystemWindows(enable);
- }
-
- static void useCutoutShortEdges(Window window, boolean enabled)
- {
- if (window == null)
- return;
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- WindowManager.LayoutParams layoutParams = window.getAttributes();
- layoutParams.layoutInDisplayCutoutMode = enabled
- ? WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
- : WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
- window.setAttributes(layoutParams);
- }
- }
-
- static void showNormal(Activity activity)
- {
- Window window = activity.getWindow();
- if (window == null)
- return;
-
- final View decor = window.getDecorView();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- setDecorFitsSystemWindows(window, true);
- WindowInsetsController ctrl = window.getInsetsController();
- if (ctrl != null) {
- ctrl.show(WindowInsets.Type.systemBars());
- ctrl.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_DEFAULT);
- }
- } else {
- @SuppressWarnings("deprecation")
- int flags = View.SYSTEM_UI_FLAG_VISIBLE; // clear all flags
- setSystemUiVisibility(decor, flags);
- }
-
- setTransparentSystemBars(activity, false);
- useCutoutShortEdges(window, false);
-
- decor.post(() -> decor.requestApplyInsets());
- }
-
- /*
- * Make system bars transparent for Andorid versions prior to Android 15.
- */
- @SuppressWarnings("deprecation")
- static void setTransparentSystemBars(Activity activity, boolean transparent)
- {
- Window window = activity.getWindow();
- if (window == null)
- return;
-
- if (edgeToEdgeEnabled(activity))
- return;
-
- // These are needed to operate on system bar colors
- window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
- | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
- window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
-
- if (transparent) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- window.setStatusBarColor(Color.TRANSPARENT);
- window.setNavigationBarColor(Color.TRANSPARENT);
- } else {
- // Android 9 and prior doesn't add the semi-transparent bars
- // to avoid low contrast system icons, so try to mimick it
- // by taking the current color and only increase the opacity.
- int statusBarColor = window.getStatusBarColor();
- int transparentStatusBar = statusBarColor & 0x00FFFFFF;
- window.setStatusBarColor(transparentStatusBar);
-
- int navigationBarColor = window.getNavigationBarColor();
- int semiTransparentNavigationBar = navigationBarColor & 0x7FFFFFFF;
- window.setNavigationBarColor(semiTransparentNavigationBar);
- }
- } else {
- // Restore theme's system bars colors
- int defaultStatusBarColor = getThemeDefaultStatusBarColor(activity);
- window.setStatusBarColor(defaultStatusBarColor);
-
- int defaultNavigationBarColor = getThemeDefaultNavigationBarColor(activity);
- window.setNavigationBarColor(defaultNavigationBarColor);
- }
- }
-
- static void showExpanded(Activity activity)
- {
- Window window = activity.getWindow();
- if (window == null)
- return;
-
- final View decor = window.getDecorView();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- setDecorFitsSystemWindows(window, false);
- WindowInsetsController ctrl = window.getInsetsController();
- if (ctrl != null) {
- ctrl.show(WindowInsets.Type.systemBars());
- ctrl.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_DEFAULT);
- }
- } else {
- @SuppressWarnings("deprecation")
- int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
- setSystemUiVisibility(decor, flags);
- }
-
- setTransparentSystemBars(activity, true);
- useCutoutShortEdges(window, true);
-
- decor.post(() -> decor.requestApplyInsets());
- }
-
- public static void showFullScreen(Activity activity)
- {
- Window window = activity.getWindow();
- if (window == null)
- return;
-
- final View decor = window.getDecorView();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- setDecorFitsSystemWindows(window, false);
- WindowInsetsController ctrl = window.getInsetsController();
- if (ctrl != null) {
- ctrl.hide(WindowInsets.Type.systemBars());
- ctrl.setSystemBarsBehavior(
- WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
- }
- } else {
- @SuppressWarnings("deprecation")
- int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
- setSystemUiVisibility(decor, flags);
- }
-
- useCutoutShortEdges(window, true);
-
- decor.post(() -> decor.requestApplyInsets());
- }
-
- void setSystemUiVisibility(boolean fullScreen, boolean expandedClientArea)
- {
- if (fullScreen)
- showFullScreen(m_activity);
- else if (expandedClientArea)
- showExpanded(m_activity);
- else
- showNormal(m_activity);
- }
-
- private static boolean edgeToEdgeEnabled(Activity activity) {
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.VANILLA_ICE_CREAM)
- return true;
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM)
- return false;
- int[] attrs = new int[] { android.R.attr.windowOptOutEdgeToEdgeEnforcement };
- TypedArray ta = activity.getTheme().obtainStyledAttributes(attrs);
- try {
- return !ta.getBoolean(0, false);
- } finally {
- ta.recycle();
- }
- }
-
- static boolean isFullScreen(Activity activity)
- {
- Window window = activity.getWindow();
- if (window == null)
- return false;
-
- final View decor = window.getDecorView();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- WindowInsets insets = activity.getWindow().getDecorView().getRootWindowInsets();
- if (insets != null)
- return !insets.isVisible(WindowInsets.Type.statusBars());
- } else {
- @SuppressWarnings("deprecation")
- int flags = decor.getSystemUiVisibility();
- @SuppressWarnings("deprecation")
- int immersiveMask = View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
- return (flags & immersiveMask) == immersiveMask;
- }
-
- return false;
- }
-
- static boolean isExpandedClientArea(Activity activity)
- {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM)
- return edgeToEdgeEnabled(activity);
-
- @SuppressWarnings("deprecation")
- int statusBarColor = activity.getWindow().getStatusBarColor();
- // If the status bar is not fully opaque assume we have expanded client
- // area and we're drawing under it.
- int statusBarAlpha = statusBarColor >>> 24;
- return statusBarAlpha != 0xFF;
- }
-
- static boolean decorFitsSystemWindows(Activity activity)
- {
- return !isFullScreen(activity) && !isExpandedClientArea(activity);
- }
-
- void restoreFullScreenVisibility(Activity activity)
- {
- if (isFullScreen(activity))
- setSystemUiVisibility(true, false);
- }
-
- /*
- * Convenience method to call deprecated API prior to Android R (30).
- */
- @SuppressWarnings ("deprecation")
- private static void setSystemUiVisibility(View decorView, int flags)
- {
- decorView.setSystemUiVisibility(flags);
- }
-
- /*
- * Set the status bar color scheme hint so that the system decides how to color the icons.
- */
- @UsedFromNativeCode
- static void setStatusBarColorHint(Activity activity, boolean isLight)
- {
- Window window = activity.getWindow();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- WindowInsetsController controller = window.getInsetsController();
- if (controller != null) {
- int lightStatusBarMask = WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
- int appearance = isLight ? lightStatusBarMask : 0;
- controller.setSystemBarsAppearance(appearance, lightStatusBarMask);
- }
- } else {
- @SuppressWarnings("deprecation")
- int currentFlags = window.getDecorView().getSystemUiVisibility();
- @SuppressWarnings("deprecation")
- int lightStatusBarMask = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
- int appearance = isLight
- ? currentFlags | lightStatusBarMask
- : currentFlags & ~lightStatusBarMask;
- setSystemUiVisibility(window.getDecorView(), appearance);
- }
- }
-
- /*
- * Set the navigation bar color scheme hint so that the system decides how to color the icons.
- */
- @UsedFromNativeCode
- static void setNavigationBarColorHint(Activity activity, boolean isLight)
- {
- Window window = activity.getWindow();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- WindowInsetsController controller = window.getInsetsController();
- if (controller != null) {
- int lightNavigationBarMask = WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
- int appearance = isLight ? lightNavigationBarMask : 0;
- controller.setSystemBarsAppearance(appearance, lightNavigationBarMask);
- }
- } else {
- @SuppressWarnings("deprecation")
- int currentFlags = window.getDecorView().getSystemUiVisibility();
- @SuppressWarnings("deprecation")
- int lightNavigationBarMask = View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
- int appearance = isLight
- ? currentFlags | lightNavigationBarMask
- : currentFlags & ~lightNavigationBarMask;
- setSystemUiVisibility(window.getDecorView(), appearance);
- }
- }
-
- static int resolveColorAttribute(Activity activity, int attribute)
- {
- Theme theme = activity.getTheme();
- Resources resources = activity.getResources();
- TypedValue tv = new TypedValue();
-
- if (theme.resolveAttribute(attribute, tv, true)) {
- if (tv.resourceId != 0)
- return resources.getColor(tv.resourceId, theme);
- if (tv.type >= TypedValue.TYPE_FIRST_COLOR_INT && tv.type <= TypedValue.TYPE_LAST_COLOR_INT)
- return tv.data;
- }
-
- return -1;
- }
-
- @SuppressWarnings("deprecation")
- static int getThemeDefaultStatusBarColor(Activity activity)
- {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM)
- return -1;
- return resolveColorAttribute(activity, android.R.attr.statusBarColor);
- }
-
- @SuppressWarnings("deprecation")
- static int getThemeDefaultNavigationBarColor(Activity activity)
- {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM)
- return -1;
- return resolveColorAttribute(activity, android.R.attr.navigationBarColor);
- }
-
- static void enableSystemBarsBackgroundDrawing(Window window)
- {
- // These are needed to operate on system bar colors
- window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- @SuppressWarnings("deprecation")
- final int translucentFlags = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
- | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
- window.clearFlags(translucentFlags);
- }
-
- @SuppressWarnings("deprecation")
- static void setStatusBarColor(Window window, int color)
- {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM)
- return;
- window.setStatusBarColor(color);
- }
-
- @SuppressWarnings("deprecation")
- static void setNavigationBarColor(Window window, int color)
- {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM)
- return;
- window.setNavigationBarColor(color);
- }
-
@SuppressWarnings("deprecation")
static Display getDisplay(Context context)
{
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtWindowInsetsController.java b/src/android/jar/src/org/qtproject/qt/android/QtWindowInsetsController.java
new file mode 100644
index 00000000000..a3d0a0df8e5
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtWindowInsetsController.java
@@ -0,0 +1,358 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.WindowInsetsController;
+import android.view.Window;
+
+import android.graphics.Color;
+import android.util.TypedValue;
+import android.content.res.Resources.Theme;
+
+class QtWindowInsetsController
+{
+ /*
+ * Convenience method to call deprecated API prior to Android R (30).
+ */
+ @SuppressWarnings ("deprecation")
+ private static void setDecorFitsSystemWindows(Window window, boolean enable)
+ {
+ final int sdk = Build.VERSION.SDK_INT;
+ if (sdk < Build.VERSION_CODES.R || sdk > Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ return;
+ window.setDecorFitsSystemWindows(enable);
+ }
+
+ private static void useCutoutShortEdges(Window window, boolean enabled)
+ {
+ if (window == null)
+ return;
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ WindowManager.LayoutParams layoutParams = window.getAttributes();
+ layoutParams.layoutInDisplayCutoutMode = enabled
+ ? WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
+ : WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
+ window.setAttributes(layoutParams);
+ }
+ }
+
+ @UsedFromNativeCode
+ static void showNormal(Activity activity)
+ {
+ Window window = activity.getWindow();
+ if (window == null)
+ return;
+
+ final View decor = window.getDecorView();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ setDecorFitsSystemWindows(window, true);
+ WindowInsetsController ctrl = window.getInsetsController();
+ if (ctrl != null) {
+ ctrl.show(WindowInsets.Type.systemBars());
+ ctrl.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_DEFAULT);
+ }
+ } else {
+ @SuppressWarnings("deprecation")
+ int flags = View.SYSTEM_UI_FLAG_VISIBLE; // clear all flags
+ setSystemUiVisibility(decor, flags);
+ }
+
+ setTransparentSystemBars(activity, false);
+ useCutoutShortEdges(window, false);
+
+ decor.post(() -> decor.requestApplyInsets());
+ }
+
+ /*
+ * Make system bars transparent for Andorid versions prior to Android 15.
+ */
+ @SuppressWarnings("deprecation")
+ private static void setTransparentSystemBars(Activity activity, boolean transparent)
+ {
+ Window window = activity.getWindow();
+ if (window == null)
+ return;
+
+ if (edgeToEdgeEnabled(activity))
+ return;
+
+ // These are needed to operate on system bar colors
+ window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
+ | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
+ window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+
+ if (transparent) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ window.setStatusBarColor(Color.TRANSPARENT);
+ window.setNavigationBarColor(Color.TRANSPARENT);
+ } else {
+ // Android 9 and prior doesn't add the semi-transparent bars
+ // to avoid low contrast system icons, so try to mimick it
+ // by taking the current color and only increase the opacity.
+ int statusBarColor = window.getStatusBarColor();
+ int transparentStatusBar = statusBarColor & 0x00FFFFFF;
+ window.setStatusBarColor(transparentStatusBar);
+
+ int navigationBarColor = window.getNavigationBarColor();
+ int semiTransparentNavigationBar = navigationBarColor & 0x7FFFFFFF;
+ window.setNavigationBarColor(semiTransparentNavigationBar);
+ }
+ } else {
+ // Restore theme's system bars colors
+ int defaultStatusBarColor = getThemeDefaultStatusBarColor(activity);
+ window.setStatusBarColor(defaultStatusBarColor);
+
+ int defaultNavigationBarColor = getThemeDefaultNavigationBarColor(activity);
+ window.setNavigationBarColor(defaultNavigationBarColor);
+ }
+ }
+
+ @UsedFromNativeCode
+ static void showExpanded(Activity activity)
+ {
+ Window window = activity.getWindow();
+ if (window == null)
+ return;
+
+ final View decor = window.getDecorView();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ setDecorFitsSystemWindows(window, false);
+ WindowInsetsController ctrl = window.getInsetsController();
+ if (ctrl != null) {
+ ctrl.show(WindowInsets.Type.systemBars());
+ ctrl.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_DEFAULT);
+ }
+ } else {
+ @SuppressWarnings("deprecation")
+ int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+ setSystemUiVisibility(decor, flags);
+ }
+
+ setTransparentSystemBars(activity, true);
+ useCutoutShortEdges(window, true);
+
+ decor.post(() -> decor.requestApplyInsets());
+ }
+
+ @UsedFromNativeCode
+ public static void showFullScreen(Activity activity)
+ {
+ Window window = activity.getWindow();
+ if (window == null)
+ return;
+
+ final View decor = window.getDecorView();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ setDecorFitsSystemWindows(window, false);
+ WindowInsetsController ctrl = window.getInsetsController();
+ if (ctrl != null) {
+ ctrl.hide(WindowInsets.Type.systemBars());
+ ctrl.setSystemBarsBehavior(
+ WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
+ }
+ } else {
+ @SuppressWarnings("deprecation")
+ int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+ setSystemUiVisibility(decor, flags);
+ }
+
+ useCutoutShortEdges(window, true);
+
+ decor.post(() -> decor.requestApplyInsets());
+ }
+
+ private static boolean edgeToEdgeEnabled(Activity activity) {
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ return true;
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ return false;
+ int[] attrs = new int[] { android.R.attr.windowOptOutEdgeToEdgeEnforcement };
+ TypedArray ta = activity.getTheme().obtainStyledAttributes(attrs);
+ try {
+ return !ta.getBoolean(0, false);
+ } finally {
+ ta.recycle();
+ }
+ }
+
+ static boolean isFullScreen(Activity activity)
+ {
+ Window window = activity.getWindow();
+ if (window == null)
+ return false;
+
+ final View decor = window.getDecorView();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ WindowInsets insets = activity.getWindow().getDecorView().getRootWindowInsets();
+ if (insets != null)
+ return !insets.isVisible(WindowInsets.Type.statusBars());
+ } else {
+ @SuppressWarnings("deprecation")
+ int flags = decor.getSystemUiVisibility();
+ @SuppressWarnings("deprecation")
+ int immersiveMask = View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+ return (flags & immersiveMask) == immersiveMask;
+ }
+
+ return false;
+ }
+
+ static boolean isExpandedClientArea(Activity activity)
+ {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ return edgeToEdgeEnabled(activity);
+
+ @SuppressWarnings("deprecation")
+ int statusBarColor = activity.getWindow().getStatusBarColor();
+ // If the status bar is not fully opaque assume we have expanded client
+ // area and we're drawing under it.
+ int statusBarAlpha = statusBarColor >>> 24;
+ return statusBarAlpha != 0xFF;
+ }
+
+ static boolean decorFitsSystemWindows(Activity activity)
+ {
+ return !isFullScreen(activity) && !isExpandedClientArea(activity);
+ }
+
+ static void restoreFullScreenVisibility(Activity activity)
+ {
+ if (isFullScreen(activity))
+ showFullScreen(activity);
+ }
+
+ /*
+ * Convenience method to call deprecated API prior to Android R (30).
+ */
+ @SuppressWarnings ("deprecation")
+ private static void setSystemUiVisibility(View decorView, int flags)
+ {
+ decorView.setSystemUiVisibility(flags);
+ }
+
+ /*
+ * Set the status bar color scheme hint so that the system decides how to color the icons.
+ */
+ @UsedFromNativeCode
+ static void setStatusBarColorHint(Activity activity, boolean isLight)
+ {
+ Window window = activity.getWindow();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ WindowInsetsController controller = window.getInsetsController();
+ if (controller != null) {
+ int lightStatusBarMask = WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
+ int appearance = isLight ? lightStatusBarMask : 0;
+ controller.setSystemBarsAppearance(appearance, lightStatusBarMask);
+ }
+ } else {
+ @SuppressWarnings("deprecation")
+ int currentFlags = window.getDecorView().getSystemUiVisibility();
+ @SuppressWarnings("deprecation")
+ int lightStatusBarMask = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+ int appearance = isLight
+ ? currentFlags | lightStatusBarMask
+ : currentFlags & ~lightStatusBarMask;
+ setSystemUiVisibility(window.getDecorView(), appearance);
+ }
+ }
+
+ /*
+ * Set the navigation bar color scheme hint so that the system decides how to color the icons.
+ */
+ @UsedFromNativeCode
+ static void setNavigationBarColorHint(Activity activity, boolean isLight)
+ {
+ Window window = activity.getWindow();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ WindowInsetsController controller = window.getInsetsController();
+ if (controller != null) {
+ int lightNavigationBarMask = WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
+ int appearance = isLight ? lightNavigationBarMask : 0;
+ controller.setSystemBarsAppearance(appearance, lightNavigationBarMask);
+ }
+ } else {
+ @SuppressWarnings("deprecation")
+ int currentFlags = window.getDecorView().getSystemUiVisibility();
+ @SuppressWarnings("deprecation")
+ int lightNavigationBarMask = View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
+ int appearance = isLight
+ ? currentFlags | lightNavigationBarMask
+ : currentFlags & ~lightNavigationBarMask;
+ setSystemUiVisibility(window.getDecorView(), appearance);
+ }
+ }
+
+ private static int resolveColorAttribute(Activity activity, int attribute)
+ {
+ Theme theme = activity.getTheme();
+ Resources resources = activity.getResources();
+ TypedValue tv = new TypedValue();
+
+ if (theme.resolveAttribute(attribute, tv, true)) {
+ if (tv.resourceId != 0)
+ return resources.getColor(tv.resourceId, theme);
+ if (tv.type >= TypedValue.TYPE_FIRST_COLOR_INT && tv.type <= TypedValue.TYPE_LAST_COLOR_INT)
+ return tv.data;
+ }
+
+ return -1;
+ }
+
+ @SuppressWarnings("deprecation")
+ static int getThemeDefaultStatusBarColor(Activity activity)
+ {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ return -1;
+ return resolveColorAttribute(activity, android.R.attr.statusBarColor);
+ }
+
+ @SuppressWarnings("deprecation")
+ static int getThemeDefaultNavigationBarColor(Activity activity)
+ {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ return -1;
+ return resolveColorAttribute(activity, android.R.attr.navigationBarColor);
+ }
+
+ static void enableSystemBarsBackgroundDrawing(Window window)
+ {
+ // These are needed to operate on system bar colors
+ window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ @SuppressWarnings("deprecation")
+ final int translucentFlags = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
+ | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
+ window.clearFlags(translucentFlags);
+ }
+
+ @SuppressWarnings("deprecation")
+ static void setStatusBarColor(Window window, int color)
+ {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ return;
+ window.setStatusBarColor(color);
+ }
+
+ @SuppressWarnings("deprecation")
+ static void setNavigationBarColor(Window window, int color)
+ {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ return;
+ window.setNavigationBarColor(color);
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtWindowInterface.java b/src/android/jar/src/org/qtproject/qt/android/QtWindowInterface.java
index d42b3e6821e..1cd36f06f5c 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtWindowInterface.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtWindowInterface.java
@@ -7,5 +7,4 @@ interface QtWindowInterface {
default void removeTopLevelWindow(final int id) { }
default void bringChildToFront(final int id) { }
default void bringChildToBack(int id) { }
- default void setSystemUiVisibility(boolean isFullScreen, boolean expandedToCutout) { }
}
diff --git a/src/plugins/platforms/android/qandroidplatformtheme.cpp b/src/plugins/platforms/android/qandroidplatformtheme.cpp
index 822a5357107..0d8673aac03 100644
--- a/src/plugins/platforms/android/qandroidplatformtheme.cpp
+++ b/src/plugins/platforms/android/qandroidplatformtheme.cpp
@@ -27,7 +27,7 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQpaMenus, "qt.qpa.menus")
-Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtDisplayManager")
+Q_DECLARE_JNI_CLASS(QtWindowInsetsController, "org/qtproject/qt/android/QtWindowInsetsController")
using namespace Qt::StringLiterals;
@@ -448,9 +448,9 @@ void QAndroidPlatformTheme::requestColorScheme(Qt::ColorScheme scheme)
const auto iface = qGuiApp->nativeInterface<QNativeInterface::QAndroidApplication>();
iface->runOnAndroidMainThread([=]() {
bool isLight = scheme == Qt::ColorScheme::Light;
- QtJniTypes::QtDisplayManager::callStaticMethod("setStatusBarColorHint",
+ QtJniTypes::QtWindowInsetsController::callStaticMethod("setStatusBarColorHint",
iface->context().object<QtJniTypes::Activity>(), isLight);
- QtJniTypes::QtDisplayManager::callStaticMethod("setNavigationBarColorHint",
+ QtJniTypes::QtWindowInsetsController::callStaticMethod("setNavigationBarColorHint",
iface->context().object<QtJniTypes::Activity>(), isLight);
});
}
diff --git a/src/plugins/platforms/android/qandroidplatformwindow.cpp b/src/plugins/platforms/android/qandroidplatformwindow.cpp
index 937839ace0c..96c4bfa06f1 100644
--- a/src/plugins/platforms/android/qandroidplatformwindow.cpp
+++ b/src/plugins/platforms/android/qandroidplatformwindow.cpp
@@ -22,6 +22,7 @@ Q_DECLARE_JNI_CLASS(QtInputInterface, "org/qtproject/qt/android/QtInputInterface
Q_DECLARE_JNI_CLASS(QtInputConnectionListener,
"org/qtproject/qt/android/QtInputConnection$QtInputConnectionListener")
Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtWindowInterface")
+Q_DECLARE_JNI_CLASS(QtWindowInsetsController, "org/qtproject/qt/android/QtWindowInsetsController")
QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window)
: QPlatformWindow(window), m_nativeQtWindow(nullptr),
@@ -260,10 +261,17 @@ void QAndroidPlatformWindow::updateSystemUiVisibility()
const int flags = window()->flags();
const bool isNonRegularWindow = flags & (Qt::Popup | Qt::Dialog | Qt::Sheet) & ~Qt::Window;
if (!isNonRegularWindow) {
- const bool isFullScreen = (m_windowState & Qt::WindowFullScreen);
- const bool expandedToCutout = (flags & Qt::ExpandedClientAreaHint);
- QtAndroid::backendRegister()->callInterface<QtJniTypes::QtWindowInterface, void>(
- "setSystemUiVisibility", isFullScreen, expandedToCutout);
+ auto iface = qGuiApp->nativeInterface<QNativeInterface::QAndroidApplication>();
+ iface->runOnAndroidMainThread([=]() {
+ using namespace QtJniTypes;
+ auto activity = iface->context().object<Activity>();
+ if (m_windowState & Qt::WindowFullScreen)
+ QtWindowInsetsController::callStaticMethod("showFullScreen", activity);
+ else if (flags & Qt::ExpandedClientAreaHint)
+ QtWindowInsetsController::callStaticMethod("showExpanded", activity);
+ else
+ QtWindowInsetsController::callStaticMethod("showNormal", activity);
+ });
}
}