From d85c6527b514e36ab06bdf4228113d458e16cae0 Mon Sep 17 00:00:00 2001 From: Ivan Solovev Date: Mon, 21 Mar 2022 17:35:29 +0100 Subject: [PATCH] Android: fix fullscreen handling Commit a35a7fcb5a713956e97bc87ccbd273737c7418df introduced the usage of insets to correctly take into account the default Android status bars and other reserved regions. However in practice that does not work as expected - the bottom inset is always reported to be non-zero, even when fullscreen mode is enabled. To fix the issue, FLAG_FULLSCREEN is explicitly checked before applying the insets. Fixes: QTBUG-99624 Pick-to: 6.3 6.2 Change-Id: I8b25f0b06447cd452c42ef072493e3137e25f38b Reviewed-by: Assam Boudjelthia --- .../org/qtproject/qt/android/QtLayout.java | 25 ++++++++++--- .../widgets/kernel/qwidget/tst_qwidget.cpp | 37 +++++++++++++++++++ 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt/android/QtLayout.java b/src/android/jar/src/org/qtproject/qt/android/QtLayout.java index 7cb694dacfc..6c52a004220 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtLayout.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtLayout.java @@ -49,6 +49,7 @@ import android.view.Display; import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; +import android.view.WindowManager; public class QtLayout extends ViewGroup { @@ -112,11 +113,25 @@ public class QtLayout extends ViewGroup } boolean isFullScreenView = h == realMetrics.heightPixels; - - int insetLeft = isFullScreenView ? insets.getSystemWindowInsetLeft() : 0; - int insetTop = isFullScreenView ? insets.getSystemWindowInsetTop() : 0; - int insetRight = isFullScreenView ? insets.getSystemWindowInsetRight() : 0; - int insetBottom = isFullScreenView ? insets.getSystemWindowInsetBottom() : 0; + // The code uses insets for fullscreen mode only. However in practice + // the insets can be reported incorrectly. Both on Android 6 and Android 11 + // a non-zero bottom inset is reported even when the + // WindowManager.LayoutParams.FLAG_FULLSCREEN flag is set. + // To avoid that, add an extra check for the fullscreen mode. + // The insets-related logic is not removed for the case when + // isFullScreenView == true, but hasFlagFullscreen == false, although + // I can't get such case in my tests. + final int windowFlags = ((Activity)getContext()).getWindow().getAttributes().flags; + final boolean hasFlagFullscreen = + (windowFlags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; + int insetLeft = + (isFullScreenView && !hasFlagFullscreen) ? insets.getSystemWindowInsetLeft() : 0; + int insetTop = + (isFullScreenView && !hasFlagFullscreen) ? insets.getSystemWindowInsetTop() : 0; + int insetRight = + (isFullScreenView && !hasFlagFullscreen) ? insets.getSystemWindowInsetRight() : 0; + int insetBottom = + (isFullScreenView && !hasFlagFullscreen) ? insets.getSystemWindowInsetBottom() : 0; int usableAreaWidth = w - insetLeft - insetRight; int usableAreaHeight = h - insetTop - insetBottom; diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 3e6fd735d95..432b1e91892 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -445,6 +445,10 @@ private slots: void activateWhileModalHidden(); +#ifdef Q_OS_ANDROID + void showFullscreenAndroid(); +#endif + private: const QString m_platform; QSize m_testWidgetSize; @@ -12693,5 +12697,38 @@ void tst_QWidget::activateWhileModalHidden() QCOMPARE(QApplication::activeWindow(), &window); } +#ifdef Q_OS_ANDROID +void tst_QWidget::showFullscreenAndroid() +{ + QWidget w; + w.setAutoFillBackground(true); + QPalette p = w.palette(); + p.setColor(QPalette::Window, Qt::red); + w.setPalette(p); + + // Need to toggle showFullScreen() twice, see QTBUG-101968 + w.showFullScreen(); + QVERIFY(QTest::qWaitForWindowExposed(&w)); + w.show(); + QVERIFY(QTest::qWaitForWindowExposed(&w)); + w.showFullScreen(); + QVERIFY(QTest::qWaitForWindowExposed(&w)); + + // Make sure that the lower part of the screen contains the red widget, not + // the buttons. + + const QRect fullGeometry = w.screen()->geometry(); + // Take a rect of (20 x 20) from the bottom area + const QRect grabArea(10, fullGeometry.height() - 30, 20, 20); + const QImage img = grabFromWidget(&w, grabArea).toImage().convertedTo(QImage::Format_RGB32); + + QPixmap expectedPix(20, 20); + expectedPix.fill(Qt::red); + const QImage expectedImg = expectedPix.toImage().convertedTo(QImage::Format_RGB32); + + QCOMPARE(img, expectedImg); +} +#endif // Q_OS_ANDROID + QTEST_MAIN(tst_QWidget) #include "tst_qwidget.moc"