Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
QtWindowInsetsController.java
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4package org.qtproject.qt.android;
5
6import android.app.Activity;
7import android.content.res.Resources;
8import android.content.res.TypedArray;
9import android.os.Build;
10import android.view.View;
11import android.view.WindowInsets;
12import android.view.WindowManager;
13import android.view.WindowInsetsController;
14import android.view.Window;
15
16import android.graphics.Color;
17import android.util.TypedValue;
18import android.content.res.Resources.Theme;
19
20class QtWindowInsetsController
21{
22 /*
23 * Convenience method to call deprecated API prior to Android R (30).
24 */
25 @SuppressWarnings ("deprecation")
26 private static void setDecorFitsSystemWindows(Window window, boolean enable)
27 {
28 final int sdk = Build.VERSION.SDK_INT;
29 if (sdk < Build.VERSION_CODES.R || sdk > Build.VERSION_CODES.VANILLA_ICE_CREAM)
30 return;
31 window.setDecorFitsSystemWindows(enable);
32 }
33
34 private static void useCutoutShortEdges(Window window, boolean enabled)
35 {
36 if (window == null)
37 return;
38
39 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
40 WindowManager.LayoutParams layoutParams = window.getAttributes();
41 layoutParams.layoutInDisplayCutoutMode = enabled
42 ? WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
43 : WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
44 window.setAttributes(layoutParams);
45 }
46 }
47
48 @UsedFromNativeCode
49 static void showNormal(Activity activity)
50 {
51 Window window = activity.getWindow();
52 if (window == null)
53 return;
54
55 final View decor = window.getDecorView();
56 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
57 setDecorFitsSystemWindows(window, true);
58 WindowInsetsController ctrl = window.getInsetsController();
59 if (ctrl != null) {
60 ctrl.show(WindowInsets.Type.systemBars());
61 ctrl.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_DEFAULT);
62 }
63 } else {
64 @SuppressWarnings("deprecation")
65 int flags = View.SYSTEM_UI_FLAG_VISIBLE; // clear all flags
66 setSystemUiVisibility(decor, flags);
67 }
68
69 setTransparentSystemBars(activity, false);
70 useCutoutShortEdges(window, false);
71
72 decor.post(() -> decor.requestApplyInsets());
73 }
74
75 /*
76 * Make system bars transparent for Andorid versions prior to Android 15.
77 */
78 @SuppressWarnings("deprecation")
79 private static void setTransparentSystemBars(Activity activity, boolean transparent)
80 {
81 Window window = activity.getWindow();
82 if (window == null)
83 return;
84
85 if (edgeToEdgeEnabled(activity))
86 return;
87
88 // These are needed to operate on system bar colors
89 window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
90 | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
91 window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
92
93 if (transparent) {
94 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
95 window.setStatusBarColor(Color.TRANSPARENT);
96 window.setNavigationBarColor(Color.TRANSPARENT);
97 } else {
98 // Android 9 and prior doesn't add the semi-transparent bars
99 // to avoid low contrast system icons, so try to mimick it
100 // by taking the current color and only increase the opacity.
101 int statusBarColor = window.getStatusBarColor();
102 int transparentStatusBar = statusBarColor & 0x00FFFFFF;
103 window.setStatusBarColor(transparentStatusBar);
104
105 int navigationBarColor = window.getNavigationBarColor();
106 int semiTransparentNavigationBar = navigationBarColor & 0x7FFFFFFF;
107 window.setNavigationBarColor(semiTransparentNavigationBar);
108 }
109 } else {
110 // Restore theme's system bars colors
111 int defaultStatusBarColor = getThemeDefaultStatusBarColor(activity);
112 window.setStatusBarColor(defaultStatusBarColor);
113
114 int defaultNavigationBarColor = getThemeDefaultNavigationBarColor(activity);
115 window.setNavigationBarColor(defaultNavigationBarColor);
116 }
117 }
118
119 @UsedFromNativeCode
120 static void showExpanded(Activity activity)
121 {
122 Window window = activity.getWindow();
123 if (window == null)
124 return;
125
126 final View decor = window.getDecorView();
127 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
128 setDecorFitsSystemWindows(window, false);
129 WindowInsetsController ctrl = window.getInsetsController();
130 if (ctrl != null) {
131 ctrl.show(WindowInsets.Type.systemBars());
132 ctrl.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_DEFAULT);
133 }
134 } else {
135 @SuppressWarnings("deprecation")
136 int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
137 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
138 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
139 setSystemUiVisibility(decor, flags);
140 }
141
142 setTransparentSystemBars(activity, true);
143 useCutoutShortEdges(window, true);
144
145 decor.post(() -> decor.requestApplyInsets());
146 }
147
148 @UsedFromNativeCode
149 public static void showFullScreen(Activity activity)
150 {
151 Window window = activity.getWindow();
152 if (window == null)
153 return;
154
155 final View decor = window.getDecorView();
156 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
157 setDecorFitsSystemWindows(window, false);
158 WindowInsetsController ctrl = window.getInsetsController();
159 if (ctrl != null) {
160 ctrl.hide(WindowInsets.Type.systemBars());
161 ctrl.setSystemBarsBehavior(
162 WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
163 }
164 } else {
165 @SuppressWarnings("deprecation")
166 int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
167 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
168 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
169 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
170 | View.SYSTEM_UI_FLAG_FULLSCREEN
171 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
172 setSystemUiVisibility(decor, flags);
173 }
174
175 useCutoutShortEdges(window, true);
176
177 decor.post(() -> decor.requestApplyInsets());
178 }
179
180 private static boolean edgeToEdgeEnabled(Activity activity) {
181 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.VANILLA_ICE_CREAM)
182 return true;
183 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM)
184 return false;
185 int[] attrs = new int[] { android.R.attr.windowOptOutEdgeToEdgeEnforcement };
186 TypedArray ta = activity.getTheme().obtainStyledAttributes(attrs);
187 try {
188 return !ta.getBoolean(0, false);
189 } finally {
190 ta.recycle();
191 }
192 }
193
194 static boolean isFullScreen(Activity activity)
195 {
196 Window window = activity.getWindow();
197 if (window == null)
198 return false;
199
200 final View decor = window.getDecorView();
201 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
202 WindowInsets insets = activity.getWindow().getDecorView().getRootWindowInsets();
203 if (insets != null)
204 return !insets.isVisible(WindowInsets.Type.statusBars());
205 } else {
206 @SuppressWarnings("deprecation")
207 int flags = decor.getSystemUiVisibility();
208 @SuppressWarnings("deprecation")
209 int immersiveMask = View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
210 return (flags & immersiveMask) == immersiveMask;
211 }
212
213 return false;
214 }
215
216 static boolean isExpandedClientArea(Activity activity)
217 {
218 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM)
219 return edgeToEdgeEnabled(activity);
220
221 @SuppressWarnings("deprecation")
222 int statusBarColor = activity.getWindow().getStatusBarColor();
223 // If the status bar is not fully opaque assume we have expanded client
224 // area and we're drawing under it.
225 int statusBarAlpha = statusBarColor >>> 24;
226 return statusBarAlpha != 0xFF;
227 }
228
229 static boolean decorFitsSystemWindows(Activity activity)
230 {
231 return !isFullScreen(activity) && !isExpandedClientArea(activity);
232 }
233
234 static void restoreFullScreenVisibility(Activity activity)
235 {
236 if (isFullScreen(activity))
237 showFullScreen(activity);
238 }
239
240 /*
241 * Convenience method to call deprecated API prior to Android R (30).
242 */
243 @SuppressWarnings ("deprecation")
244 private static void setSystemUiVisibility(View decorView, int flags)
245 {
246 decorView.setSystemUiVisibility(flags);
247 }
248
249 /*
250 * Set the status bar color scheme hint so that the system decides how to color the icons.
251 */
252 @UsedFromNativeCode
253 static void setStatusBarColorHint(Activity activity, boolean isLight)
254 {
255 Window window = activity.getWindow();
256 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
257 WindowInsetsController controller = window.getInsetsController();
258 if (controller != null) {
259 int lightStatusBarMask = WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
260 int appearance = isLight ? lightStatusBarMask : 0;
261 controller.setSystemBarsAppearance(appearance, lightStatusBarMask);
262 }
263 } else {
264 @SuppressWarnings("deprecation")
265 int currentFlags = window.getDecorView().getSystemUiVisibility();
266 @SuppressWarnings("deprecation")
267 int lightStatusBarMask = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
268 int appearance = isLight
269 ? currentFlags | lightStatusBarMask
270 : currentFlags & ~lightStatusBarMask;
271 setSystemUiVisibility(window.getDecorView(), appearance);
272 }
273 }
274
275 /*
276 * Set the navigation bar color scheme hint so that the system decides how to color the icons.
277 */
278 @UsedFromNativeCode
279 static void setNavigationBarColorHint(Activity activity, boolean isLight)
280 {
281 Window window = activity.getWindow();
282 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
283 WindowInsetsController controller = window.getInsetsController();
284 if (controller != null) {
285 int lightNavigationBarMask = WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
286 int appearance = isLight ? lightNavigationBarMask : 0;
287 controller.setSystemBarsAppearance(appearance, lightNavigationBarMask);
288 }
289 } else {
290 @SuppressWarnings("deprecation")
291 int currentFlags = window.getDecorView().getSystemUiVisibility();
292 @SuppressWarnings("deprecation")
293 int lightNavigationBarMask = View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
294 int appearance = isLight
295 ? currentFlags | lightNavigationBarMask
296 : currentFlags & ~lightNavigationBarMask;
297 setSystemUiVisibility(window.getDecorView(), appearance);
298 }
299 }
300
301 private static int resolveColorAttribute(Activity activity, int attribute)
302 {
303 Theme theme = activity.getTheme();
304 Resources resources = activity.getResources();
305 TypedValue tv = new TypedValue();
306
307 if (theme.resolveAttribute(attribute, tv, true)) {
308 if (tv.resourceId != 0)
309 return resources.getColor(tv.resourceId, theme);
310 if (tv.type >= TypedValue.TYPE_FIRST_COLOR_INT && tv.type <= TypedValue.TYPE_LAST_COLOR_INT)
311 return tv.data;
312 }
313
314 return -1;
315 }
316
317 @SuppressWarnings("deprecation")
318 static int getThemeDefaultStatusBarColor(Activity activity)
319 {
320 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM)
321 return -1;
322 return resolveColorAttribute(activity, android.R.attr.statusBarColor);
323 }
324
325 @SuppressWarnings("deprecation")
326 static int getThemeDefaultNavigationBarColor(Activity activity)
327 {
328 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM)
329 return -1;
330 return resolveColorAttribute(activity, android.R.attr.navigationBarColor);
331 }
332
333 static void enableSystemBarsBackgroundDrawing(Window window)
334 {
335 // These are needed to operate on system bar colors
336 window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
337 @SuppressWarnings("deprecation")
338 final int translucentFlags = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
339 | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
340 window.clearFlags(translucentFlags);
341 }
342
343 @SuppressWarnings("deprecation")
344 static void setStatusBarColor(Window window, int color)
345 {
346 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM)
347 return;
348 window.setStatusBarColor(color);
349 }
350
351 @SuppressWarnings("deprecation")
352 static void setNavigationBarColor(Window window, int color)
353 {
354 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM)
355 return;
356 window.setNavigationBarColor(color);
357 }
358}
Q_CORE_EXPORT QtJniTypes::Activity activity()
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage return
static struct AttrInfo attrs[]
EGLOutputLayerEXT EGLint attribute
GLbitfield flags
GLuint color
[setDefaultFactory]
GLboolean enable
#define enabled
aWidget window() -> setWindowTitle("New Window Title")
[2]
manager post(request, myJson, this, [this](QRestReply &reply) { if(!reply.isSuccess()) { } if(std::optional json=reply.readJson()) { } })
if(foo.startsWith("("+type+") 0x")) ... QString hello("hello")
[0]