Android: implement safe areas margins
Rely on Android APIs (old and new) to calculate safe area margins, which takes into account the cutout regions and the system bars. Task-number: QTBUG-131519 Task-number: QTBUG-98989 Change-Id: Ie69e6c54df30c76e67d9ca96518e13f9898e6312 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
parent
b63e274a8a
commit
c2b94a15c1
@ -6,11 +6,18 @@ package org.qtproject.qt.android;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
|
||||
import android.graphics.Insets;
|
||||
|
||||
import android.view.DisplayCutout;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowInsets;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@ -25,6 +32,7 @@ class QtWindow extends QtLayout implements QtSurfaceInterface {
|
||||
private final QtInputConnection.QtInputConnectionListener m_inputConnectionListener;
|
||||
|
||||
private static native void setSurface(int windowId, Surface surface);
|
||||
private static native void safeAreaMarginsChanged(Insets insets);
|
||||
static native void windowFocusChanged(boolean hasFocus, int id);
|
||||
static native void updateWindows();
|
||||
|
||||
@ -67,6 +75,46 @@ class QtWindow extends QtLayout implements QtSurfaceInterface {
|
||||
});
|
||||
m_gestureDetector.setIsLongpressEnabled(true);
|
||||
});
|
||||
|
||||
if (getContext() instanceof QtActivityBase) {
|
||||
View decorView = ((Activity) context).getWindow().getDecorView();
|
||||
decorView.setOnApplyWindowInsetsListener((view, insets) -> {
|
||||
Insets safeInsets;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
int types = WindowInsets.Type.displayCutout() | WindowInsets.Type.systemBars();
|
||||
safeInsets = insets.getInsets(types);
|
||||
} else {
|
||||
int left = 0;
|
||||
int top = 0;
|
||||
int right = 0;
|
||||
int bottom = 0;
|
||||
|
||||
int visibility = view.getSystemUiVisibility();
|
||||
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
|
||||
left = insets.getSystemWindowInsetLeft();
|
||||
top = insets.getSystemWindowInsetTop();
|
||||
right = insets.getSystemWindowInsetRight();
|
||||
bottom = insets.getSystemWindowInsetBottom();
|
||||
}
|
||||
|
||||
// Android 9 and 10 emulators don't seem to be able
|
||||
// to handle this, but let's have the logic here anyway
|
||||
DisplayCutout cutout = insets.getDisplayCutout();
|
||||
if (cutout != null) {
|
||||
left = Math.max(left, cutout.getSafeInsetLeft());
|
||||
top = Math.max(top, cutout.getSafeInsetTop());
|
||||
right = Math.max(right, cutout.getSafeInsetRight());
|
||||
bottom = Math.max(bottom, cutout.getSafeInsetBottom());
|
||||
}
|
||||
|
||||
safeInsets = Insets.of(left, top, right, bottom);
|
||||
}
|
||||
|
||||
safeAreaMarginsChanged(safeInsets);
|
||||
|
||||
return insets;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <qguiapplication.h>
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
#include <private/qhighdpiscaling_p.h>
|
||||
#include <private/qjnihelpers_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -21,6 +22,7 @@ Q_DECLARE_JNI_CLASS(QtWindowInterface, "org/qtproject/qt/android/QtWindowInterfa
|
||||
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")
|
||||
|
||||
QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window)
|
||||
: QPlatformWindow(window), m_nativeQtWindow(nullptr),
|
||||
@ -126,13 +128,12 @@ void QAndroidPlatformWindow::raise()
|
||||
|
||||
QMargins QAndroidPlatformWindow::safeAreaMargins() const
|
||||
{
|
||||
if ((m_windowState & Qt::WindowMaximized) && (window()->flags() & Qt::ExpandedClientAreaHint)) {
|
||||
QRect availableGeometry = platformScreen()->availableGeometry();
|
||||
return QMargins(availableGeometry.left(), availableGeometry.top(),
|
||||
availableGeometry.right(), availableGeometry.bottom());
|
||||
} else {
|
||||
return QPlatformWindow::safeAreaMargins();
|
||||
}
|
||||
return m_safeAreaMargins;
|
||||
}
|
||||
|
||||
void QAndroidPlatformWindow::setSafeAreaMargins(const QMargins safeMargins)
|
||||
{
|
||||
m_safeAreaMargins = safeMargins;
|
||||
}
|
||||
|
||||
void QAndroidPlatformWindow::setGeometry(const QRect &rect)
|
||||
@ -382,6 +383,42 @@ void QAndroidPlatformWindow::windowFocusChanged(JNIEnv *env, jobject object,
|
||||
}
|
||||
}
|
||||
|
||||
void QAndroidPlatformWindow::safeAreaMarginsChanged(JNIEnv *env, jobject object, QtJniTypes::Insets insets)
|
||||
{
|
||||
Q_UNUSED(env)
|
||||
Q_UNUSED(object)
|
||||
|
||||
if (!qGuiApp)
|
||||
return;
|
||||
|
||||
const auto tlw = qGuiApp->topLevelWindows();
|
||||
if (tlw.isEmpty())
|
||||
return;
|
||||
|
||||
QMargins safeMargins;
|
||||
if (insets.isValid()) {
|
||||
safeMargins = QMargins(
|
||||
insets.getField<int>("left"),
|
||||
insets.getField<int>("top"),
|
||||
insets.getField<int>("right"),
|
||||
insets.getField<int>("bottom"));
|
||||
}
|
||||
|
||||
for (QWindow *window : qGuiApp->topLevelWindows()) {
|
||||
if (!window->handle())
|
||||
continue;
|
||||
|
||||
auto *pWindow = static_cast<QAndroidPlatformWindow *>(window->handle());
|
||||
if (!pWindow)
|
||||
return;
|
||||
|
||||
if (safeMargins != pWindow->safeAreaMargins()) {
|
||||
pWindow->setSafeAreaMargins(safeMargins);
|
||||
QWindowSystemInterface::handleSafeAreaMarginsChanged(window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void updateWindows(JNIEnv *env, jobject object)
|
||||
{
|
||||
Q_UNUSED(env)
|
||||
@ -425,11 +462,12 @@ QMutexLocker<QMutex> QAndroidPlatformWindow::destructionGuard()
|
||||
bool QAndroidPlatformWindow::registerNatives(QJniEnvironment &env)
|
||||
{
|
||||
if (!env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtWindow>::className(),
|
||||
{
|
||||
Q_JNI_NATIVE_METHOD(updateWindows),
|
||||
Q_JNI_NATIVE_SCOPED_METHOD(setSurface, QAndroidPlatformWindow),
|
||||
Q_JNI_NATIVE_SCOPED_METHOD(windowFocusChanged, QAndroidPlatformWindow)
|
||||
})) {
|
||||
{
|
||||
Q_JNI_NATIVE_METHOD(updateWindows),
|
||||
Q_JNI_NATIVE_SCOPED_METHOD(setSurface, QAndroidPlatformWindow),
|
||||
Q_JNI_NATIVE_SCOPED_METHOD(windowFocusChanged, QAndroidPlatformWindow),
|
||||
Q_JNI_NATIVE_SCOPED_METHOD(safeAreaMarginsChanged, QAndroidPlatformWindow)
|
||||
})) {
|
||||
qCCritical(lcQpaWindow) << "RegisterNatives failed for"
|
||||
<< QtJniTypes::Traits<QtJniTypes::QtWindow>::className();
|
||||
return false;
|
||||
|
@ -20,6 +20,7 @@ QT_BEGIN_NAMESPACE
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcQpaWindow)
|
||||
Q_DECLARE_JNI_CLASS(QtWindow, "org/qtproject/qt/android/QtWindow")
|
||||
Q_DECLARE_JNI_CLASS(Surface, "android/view/Surface")
|
||||
Q_DECLARE_JNI_CLASS(Insets, "android/graphics/Insets")
|
||||
|
||||
class QAndroidPlatformScreen;
|
||||
|
||||
@ -53,6 +54,7 @@ public:
|
||||
QAndroidPlatformScreen *platformScreen() const;
|
||||
|
||||
QMargins safeAreaMargins() const override;
|
||||
void setSafeAreaMargins(const QMargins safeMargins);
|
||||
|
||||
void propagateSizeHints() override;
|
||||
void requestActivateWindow() override;
|
||||
@ -99,11 +101,15 @@ protected:
|
||||
QMutex m_surfaceMutex;
|
||||
QMutex m_destructionMutex;
|
||||
|
||||
QMargins m_safeAreaMargins;
|
||||
|
||||
private:
|
||||
static void setSurface(JNIEnv *env, jobject obj, jint windowId, QtJniTypes::Surface surface);
|
||||
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(setSurface)
|
||||
static void windowFocusChanged(JNIEnv *env, jobject object, jboolean focus, jint windowId);
|
||||
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(windowFocusChanged)
|
||||
static void safeAreaMarginsChanged(JNIEnv *env, jobject obj, QtJniTypes::Insets insets);
|
||||
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(safeAreaMarginsChanged)
|
||||
|
||||
[[nodiscard]] QMutexLocker<QMutex> destructionGuard();
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user