summaryrefslogtreecommitdiffstats
path: root/src/android/jar
diff options
context:
space:
mode:
Diffstat (limited to 'src/android/jar')
-rw-r--r--src/android/jar/CMakeLists.txt1
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java18
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java21
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java20
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java271
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java5
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtLoader.java2
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtNative.java5
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtView.java49
-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
11 files changed, 429 insertions, 322 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 aca9e3d3c11..78763e65905 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java
@@ -102,9 +102,11 @@ public class QtActivityBase extends Activity
requestWindowFeature(Window.FEATURE_ACTION_BAR);
if (!m_isCustomThemeSet) {
- setTheme(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ?
- android.R.style.Theme_DeviceDefault_DayNight :
- android.R.style.Theme_Holo_Light);
+ @SuppressWarnings("deprecation")
+ int themeId = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
+ ? android.R.style.Theme_DeviceDefault_DayNight
+ : android.R.style.Theme_Holo_Light;
+ setTheme(themeId);
}
if (QtNative.getStateDetails().isStarted) {
@@ -168,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().reinstateFullScreen();
+ QtWindowInsetsController.restoreFullScreenVisibility(this);
}
}
@@ -311,9 +313,7 @@ public class QtActivityBase extends Activity
return;
QtNative.setStarted(savedInstanceState.getBoolean("Started"));
- boolean isFullScreen = savedInstanceState.getBoolean("isFullScreen");
- boolean expandedToCutout = savedInstanceState.getBoolean("expandedToCutout");
- m_delegate.displayManager().setSystemUiVisibility(isFullScreen, expandedToCutout);
+ QtWindowInsetsController.restoreFullScreenVisibility(this);
// FIXME restore all surfaces
}
@@ -329,8 +329,6 @@ public class QtActivityBase extends Activity
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
- outState.putBoolean("isFullScreen", m_delegate.displayManager().isFullScreen());
- outState.putBoolean("expandedToCutout", m_delegate.displayManager().expandedToCutout());
outState.putBoolean("Started", QtNative.getStateDetails().isStarted);
}
@@ -339,7 +337,7 @@ public class QtActivityBase extends Activity
{
super.onWindowFocusChanged(hasFocus);
if (hasFocus)
- m_delegate.displayManager().reinstateFullScreen();
+ 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 118845efcec..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();
@@ -138,9 +123,9 @@ class QtActivityDelegate extends QtActivityDelegateBase
int orientation = m_activity.getResources().getConfiguration().orientation;
setUpSplashScreen(orientation);
m_activity.registerForContextMenu(m_layout);
- m_activity.setContentView(m_layout,
- new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
+ ViewGroup.LayoutParams rootParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+ m_activity.setContentView(m_layout, rootParams);
handleUiModeChange();
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 35f519ca9a4..7f6163f164d 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java
@@ -46,7 +46,9 @@ abstract class QtActivityDelegateBase
m_activity = activity;
QtNative.setActivity(m_activity);
m_displayManager = new QtDisplayManager(m_activity);
- m_inputDelegate = new QtInputDelegate(m_displayManager::reinstateFullScreen);
+ m_inputDelegate = new QtInputDelegate(() -> {
+ QtWindowInsetsController.restoreFullScreenVisibility(m_activity);
+ });
m_accessibilityDelegate = new QtAccessibilityDelegate();
}
@@ -105,20 +107,20 @@ abstract class QtActivityDelegateBase
Configuration config = resources.getConfiguration();
int uiMode = config.uiMode & Configuration.UI_MODE_NIGHT_MASK;
- if (m_displayManager.decorFitsSystemWindows()) {
+ 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 8736dfab771..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
@@ -47,9 +37,6 @@ class QtDisplayManager
static native void handleScreenDensityChanged(double density);
// screen methods
- private boolean m_isFullScreen = false;
- private boolean m_expandedToCutout = false;
-
private static int m_previousRotation = -1;
private final DisplayManager.DisplayListener m_displayListener;
@@ -136,264 +123,6 @@ class QtDisplayManager
}
@SuppressWarnings("deprecation")
- void setSystemUiVisibilityPreAndroidR(View decorView)
- {
- int systemUiVisibility;
-
- if (m_isFullScreen || m_expandedToCutout) {
- systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
- if (m_isFullScreen) {
- systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
- }
- } else {
- systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
- }
-
- decorView.setSystemUiVisibility(systemUiVisibility);
- }
-
- void setSystemUiVisibility(boolean isFullScreen, boolean expandedToCutout)
- {
- if (m_isFullScreen == isFullScreen && m_expandedToCutout == expandedToCutout)
- return;
-
- m_isFullScreen = isFullScreen;
- m_expandedToCutout = expandedToCutout;
-
- Window window = m_activity.getWindow();
- View decorView = window.getDecorView();
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- int cutoutMode;
- if (m_isFullScreen || m_expandedToCutout) {
- window.setDecorFitsSystemWindows(false);
- cutoutMode = LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
- } else {
- window.setDecorFitsSystemWindows(true);
- cutoutMode = LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
- }
- LayoutParams layoutParams = window.getAttributes();
- layoutParams.layoutInDisplayCutoutMode = cutoutMode;
- window.setAttributes(layoutParams);
-
- final WindowInsetsController insetsControl = window.getInsetsController();
- if (insetsControl != null) {
- int sysBarsBehavior;
- if (m_isFullScreen) {
- insetsControl.hide(WindowInsets.Type.systemBars());
- sysBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
- } else {
- insetsControl.show(WindowInsets.Type.systemBars());
- sysBarsBehavior = WindowInsetsController.BEHAVIOR_DEFAULT;
- }
- insetsControl.setSystemBarsBehavior(sysBarsBehavior);
- }
- } else {
- setSystemUiVisibilityPreAndroidR(decorView);
- }
-
- if (!isFullScreen && !edgeToEdgeEnabled(m_activity)) {
- // 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);
-
- // Handle transparent status and navigation bars
- if (m_expandedToCutout) {
- 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
- Theme theme = m_activity.getTheme();
- TypedValue typedValue = new TypedValue();
-
- theme.resolveAttribute(android.R.attr.statusBarColor, typedValue, true);
- int defaultStatusBarColor = typedValue.data;
- window.setStatusBarColor(defaultStatusBarColor);
-
- theme.resolveAttribute(android.R.attr.navigationBarColor, typedValue, true);
- int defaultNavigationBarColor = typedValue.data;
- window.setNavigationBarColor(defaultNavigationBarColor);
- }
- }
-
- decorView.post(() -> decorView.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();
- }
- }
-
- boolean isFullScreen()
- {
- return m_isFullScreen;
- }
-
- boolean expandedToCutout()
- {
- return m_expandedToCutout;
- }
-
- boolean decorFitsSystemWindows()
- {
- return !isFullScreen() && !expandedToCutout();
- }
-
- void reinstateFullScreen()
- {
- if (m_isFullScreen) {
- m_isFullScreen = false;
- setSystemUiVisibility(true, m_expandedToCutout);
- }
- }
-
- /*
- * 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)
{
Activity activity = (Activity) context;
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java
index ca271c5dd62..e0c6c00a8fd 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java
@@ -9,6 +9,7 @@ import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Looper;
import android.os.ResultReceiver;
import android.text.method.MetaKeyKeyListener;
import android.util.DisplayMetrics;
@@ -166,7 +167,7 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt
} else {
if (m_imm == null)
return;
- m_imm.showSoftInput(m_currentEditText, 0, new ResultReceiver(new Handler()) {
+ m_imm.showSoftInput(m_currentEditText, 0, new ResultReceiver(new Handler(Looper.getMainLooper())) {
@Override
@SuppressWarnings("fallthrough")
protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -278,7 +279,7 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt
activity.getWindow().getInsetsController().hide(Type.ime());
} else {
m_imm.hideSoftInputFromWindow(m_currentEditText.getWindowToken(), 0,
- new ResultReceiver(new Handler()) {
+ new ResultReceiver(new Handler(Looper.getMainLooper())) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
switch (resultCode) {
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtLoader.java b/src/android/jar/src/org/qtproject/qt/android/QtLoader.java
index 8fd0213eb91..6d7c0624272 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtLoader.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtLoader.java
@@ -345,7 +345,7 @@ abstract class QtLoader {
if (metadata == null || !metadata.containsKey(key))
return "";
- return String.valueOf(metadata.get(key));
+ return String.valueOf(metadata.getString(key));
}
@SuppressLint("DiscouragedApi")
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtNative.java b/src/android/jar/src/org/qtproject/qt/android/QtNative.java
index 080bb787a2d..7e4632f6792 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtNative.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtNative.java
@@ -361,8 +361,11 @@ public class QtNative
if (m_stateDetails.isStarted)
return;
+ getQtThread().run(() -> initAndroidQpaPlugin());
final String qtParams = mainLib + " " + params;
getQtThread().post(() -> { startQtNativeApplication(qtParams); });
+ waitForServiceSetup();
+ setStarted(true);
}
@UsedFromNativeCode
@@ -428,7 +431,9 @@ public class QtNative
}
// application methods
+ static native boolean initAndroidQpaPlugin();
static native void startQtNativeApplication(String params);
+ static native void waitForServiceSetup();
static native void terminateQtNativeApplication();
static native boolean updateNativeActivity();
// application methods
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtView.java b/src/android/jar/src/org/qtproject/qt/android/QtView.java
index b60c58013f5..e245f731ce8 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtView.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtView.java
@@ -25,11 +25,11 @@ abstract class QtView extends ViewGroup implements QtNative.AppStateDetailsListe
void onQtWindowLoaded();
}
- protected QtWindow m_window;
- protected long m_windowReference;
- protected long m_parentWindowReference;
- protected QtWindowListener m_windowListener;
- protected final QtEmbeddedViewInterface m_viewInterface;
+ private QtWindow m_window;
+ private long m_windowReference;
+ private long m_parentWindowReference;
+ private QtWindowListener m_windowListener;
+ private final QtEmbeddedViewInterface m_viewInterface;
// Implement in subclass to handle the creation of the QWindow and its parent container.
// TODO could we take care of the parent window creation and parenting outside of the
// window creation method to simplify things if user would extend this? Preferably without
@@ -164,10 +164,43 @@ abstract class QtView extends ViewGroup implements QtNative.AppStateDetailsListe
m_windowReference = windowReference;
}
- long windowReference() {
+ long getWindowReference() {
return m_windowReference;
}
+ void setQtWindow(QtWindow qtWindow) {
+ m_window = qtWindow;
+ }
+
+ QtWindow getQtWindow() {
+ return m_window;
+ }
+
+ long getParentWindowReference()
+ {
+ return m_parentWindowReference;
+ }
+
+ void setParentWindowReference(long reference)
+ {
+ m_parentWindowReference = reference;
+ }
+
+ QtWindowListener getWindowListener()
+ {
+ return m_windowListener;
+ }
+
+ void setWindowListener(QtWindowListener listner)
+ {
+ m_windowListener = listner;
+ }
+
+ QtEmbeddedViewInterface getViewInterface()
+ {
+ return m_viewInterface;
+ }
+
// Set the visibility of the underlying QWindow. If visible is true, showNormal() is called.
// If false, the window is hidden.
void setWindowVisible(boolean visible) {
@@ -203,10 +236,6 @@ abstract class QtView extends ViewGroup implements QtNative.AppStateDetailsListe
setWindowReference(0L);
}
- QtWindow getQtWindow() {
- return m_window;
- }
-
@Override
public void onAppStateDetailsChanged(QtNative.ApplicationStateDetails details) {
if (!details.isStarted) {
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) { }
}