Android: fix 180 degree orientation issue
On android documentation orientation changes are sent via onConfigurationChanged callback. Previous implementation based orientation detection to onSizeChanged callback. That callback is not called when orientation turns 180 degrees. i.e. between landscape and inverted landscape. This fix adds detection to on onConfigurationChanged to catch those cases. Fixes: QTBUG-118887 Fixes: QTBUG-118236 Pick-to: 6.5 Change-Id: Ie2f81798de97e460de839f7ebfde9a9efa25909f Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io> (cherry picked from commit 6209079c7a34c4656e6e110ae5194feb19f6134a) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
61885e26e4
commit
7aeffcebbd
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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<void>("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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user