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 7b19d483f11..e385432dd86 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java @@ -113,7 +113,7 @@ public class QtActivityDelegate extends QtActivityDelegateBase m_activity.setContentView(m_layout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - QtDisplayManager.handleOrientationChanges(m_activity, false); + QtDisplayManager.handleOrientationChanges(m_activity); handleUiModeChange(m_activity.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK); 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 131dc855129..b6a52fb22f4 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java @@ -64,7 +64,6 @@ class QtDisplayManager { @Override public void onDisplayChanged(int displayId) { - handleOrientationChanges(m_activity, false); Display display = (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) ? m_activity.getWindowManager().getDefaultDisplay() : m_activity.getDisplay(); @@ -80,35 +79,17 @@ class QtDisplayManager { }; } - private static boolean isSameSizeForOrientations(int r1, int r2) { - return (r1 == r2) || - (r1 == Surface.ROTATION_0 && r2 == Surface.ROTATION_180) - || (r1 == Surface.ROTATION_180 && r2 == Surface.ROTATION_0) - || (r1 == Surface.ROTATION_90 && r2 == Surface.ROTATION_270) - || (r1 == Surface.ROTATION_270 && r2 == Surface.ROTATION_90); - } - - static void handleOrientationChanges(Activity activity, boolean sizeChanged) + static void handleOrientationChanges(Activity activity) { int currentRotation = getDisplayRotation(activity); - int nativeOrientation = getNativeOrientation(activity, currentRotation); - if (m_previousRotation == currentRotation) return; - - // If the the current and previous rotations are similar then QtLayout.onSizeChanged() - // might not be called, so we can already update the orientation, and rely on this to - // called again once the resize event is sent. - // Note: Android 10 emulator seems to not always send an event when the orientation - // changes, could be a bug in the emulator. - boolean noResizeNeeded = isSameSizeForOrientations(m_previousRotation, currentRotation); - if (m_previousRotation == -1 || sizeChanged || noResizeNeeded) { - QtDisplayManager.handleOrientationChanged(currentRotation, nativeOrientation); - m_previousRotation = currentRotation; - } + int nativeOrientation = getNativeOrientation(activity, currentRotation); + QtDisplayManager.handleOrientationChanged(currentRotation, nativeOrientation); + m_previousRotation = currentRotation; } - private static int getDisplayRotation(Activity activity) { + public static int getDisplayRotation(Activity activity) { Display display = Build.VERSION.SDK_INT < Build.VERSION_CODES.R ? activity.getWindowManager().getDefaultDisplay() : activity.getDisplay(); diff --git a/src/android/jar/src/org/qtproject/qt/android/QtRootLayout.java b/src/android/jar/src/org/qtproject/qt/android/QtRootLayout.java index 54f4ea1ee08..3dae587a710 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtRootLayout.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtRootLayout.java @@ -9,6 +9,8 @@ import android.content.Context; import android.os.Build; import android.util.DisplayMetrics; import android.view.Display; +import android.content.res.Configuration; +import android.view.Surface; /** A layout which corresponds to one Activity, i.e. is the root layout where the top level window @@ -16,10 +18,10 @@ import android.view.Display; */ public class QtRootLayout extends QtLayout { - private int m_activityDisplayRotation = -1; private int m_ownDisplayRotation = -1; private int m_nativeOrientation = -1; + private int m_previousRotation = -1; public QtRootLayout(Context context) { @@ -67,8 +69,30 @@ public class QtRootLayout extends QtLayout // a bit later. return; } - QtDisplayManager.setApplicationDisplayMetrics(activity, w, h); - QtDisplayManager.handleOrientationChanges(activity, true); + QtDisplayManager.handleOrientationChanges(activity); + } + + @Override + public void onConfigurationChanged(Configuration configuration) + { + Context context = getContext(); + if (context instanceof Activity) { + Activity activity = (Activity)context; + //if orientation change is betwen invertedPortrait and portrait or + //invertedLandscape and landscape, we do not get sizeChanged callback. + int rotation = QtDisplayManager.getDisplayRotation(activity); + if (isSameSizeForOrientations(rotation, m_previousRotation)) + QtDisplayManager.handleOrientationChanges(activity); + m_previousRotation = rotation; + } + } + + public boolean isSameSizeForOrientations(int r1, int r2) { + return (r1 == r2) || + (r1 == Surface.ROTATION_0 && r2 == Surface.ROTATION_180) + || (r1 == Surface.ROTATION_180 && r2 == Surface.ROTATION_0) + || (r1 == Surface.ROTATION_90 && r2 == Surface.ROTATION_270) + || (r1 == Surface.ROTATION_270 && r2 == Surface.ROTATION_90); } } diff --git a/tests/auto/corelib/platform/android/tst_android.cpp b/tests/auto/corelib/platform/android/tst_android.cpp index e03308a883d..07b939969c0 100644 --- a/tests/auto/corelib/platform/android/tst_android.cpp +++ b/tests/auto/corelib/platform/android/tst_android.cpp @@ -312,11 +312,39 @@ void tst_Android::orientationChange_data() const QSize portraitSize = QGuiApplication::primaryScreen()->size(); const QSize landscapeSize = QSize(portraitSize.height(), portraitSize.width()); + // Rotations without 180 degree or inverted portrait, assuming that the device is in portrait + // position. These are ok for Android 6(API 23), 8 (API 27) and 14 (API 34) QTest::newRow("InvertedLandscape") << 8 << Qt::InvertedLandscapeOrientation << landscapeSize; - QTest::newRow("InvertedPortrait") << 9 << Qt::InvertedPortraitOrientation << portraitSize; - QTest::newRow("Landscape") << 0 << Qt::LandscapeOrientation << landscapeSize; - // Leave Portrait till the end QTest::newRow("Portrait") << 1 << Qt::PortraitOrientation << portraitSize; + QTest::newRow("Landscape") << 0 << Qt::LandscapeOrientation << landscapeSize; + QTest::newRow("Portrait2") << 1 << Qt::PortraitOrientation << portraitSize; + + // Rotations over inverted portrait doing only 90 degree turns. + QTest::newRow("InvertedLandscape2") << 8 << Qt::InvertedLandscapeOrientation << landscapeSize; + QTest::newRow("InvertedPortrait") << 9 << Qt::InvertedPortraitOrientation << portraitSize; + QTest::newRow("Landscape2") << 0 << Qt::LandscapeOrientation << landscapeSize; + QTest::newRow("InvertedPortrait2") << 9 << Qt::InvertedPortraitOrientation << portraitSize; + QTest::newRow("InvertedLandscape3") << 8 << Qt::InvertedLandscapeOrientation << landscapeSize; + + // Rotations with 180 degree turns. + // Android 6 (API23) Does not understand these transitions. + if (QNativeInterface::QAndroidApplication::sdkVersion() > __ANDROID_API_M__) { + QTest::newRow("Landscape3") << 0 << Qt::LandscapeOrientation << landscapeSize; + QTest::newRow("InvertedLandscape4") + << 8 << Qt::InvertedLandscapeOrientation << landscapeSize; + QTest::newRow("Portrait3") << 1 << Qt::PortraitOrientation << portraitSize; + } else { + qWarning() << "180 degree turn rotation test cases are not run on Android 6 (API 23) and " + "below."; + } + // Android 8 (API 27) does not understand portrait-'inverted portrait'-portrait transition. + if (QNativeInterface::QAndroidApplication::sdkVersion() > __ANDROID_API_O_MR1__) { + QTest::newRow("InvertedPortrait3") << 9 << Qt::InvertedPortraitOrientation << portraitSize; + QTest::newRow("Portrait4") << 1 << Qt::PortraitOrientation << portraitSize; + } else { + qWarning() << "Portrait-'Inverted portrait'-Portrait rotation test cases are not run on " + "Android 8 (API 27) and below."; + } } void tst_Android::orientationChange() @@ -329,11 +357,13 @@ void tst_Android::orientationChange() QWidget widget; widget.show(); + QScreen *screen = QGuiApplication::primaryScreen(); + QSignalSpy orientationSpy(screen, SIGNAL(orientationChanged(Qt::ScreenOrientation))); + auto context = QNativeInterface::QAndroidApplication::context(); context.callMethod("setRequestedOrientation", nativeOrientation); - QScreen *screen = QGuiApplication::primaryScreen(); - QSignalSpy orientationSpy(screen, SIGNAL(orientationChanged(Qt::ScreenOrientation))); + orientationSpy.wait(); QTRY_COMPARE(screen->orientation(), expected); QCOMPARE(orientationSpy.size(), 1); QCOMPARE(screen->size(), screenSize);