From fbf586db2c587e7ba83cf1bfe8e5b912310d6bdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20B=C5=82aszak?= Date: Fri, 22 Jul 2022 13:05:56 +0200 Subject: QGuiApplication on Android can now detect multiple displays - Extending QtNative.java with access to DisplayManager and get details about available displays - Extending Android Platform Integration with display's list handling - Change QAndroidPlatformScreen to initialize itself from QJniObject representation of an android Display object - Move initialization of Primary display from QAndroidPlatformScreen to QAndroidPlatformIntegration Change-Id: I3d8f97f5cf9f81bbecc8716c25ff323097e57a15 Reviewed-by: Assam Boudjelthia --- .../android/qandroidplatformintegration.cpp | 36 +++++++- .../platforms/android/qandroidplatformscreen.cpp | 102 +++++++++++---------- .../platforms/android/qandroidplatformscreen.h | 5 +- 3 files changed, 87 insertions(+), 56 deletions(-) (limited to 'src/plugins/platforms/android') diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index 890f978768..57546bdbca 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -56,6 +56,11 @@ Qt::ScreenOrientation QAndroidPlatformIntegration::m_nativeOrientation = Qt::Pri bool QAndroidPlatformIntegration::m_showPasswordEnabled = false; static bool m_running = false; +Q_DECLARE_JNI_CLASS(QtNative, "org/qtproject/qt/android/QtNative") +Q_DECLARE_JNI_CLASS(Display, "android/view/Display") + +Q_DECLARE_JNI_TYPE(List, "Ljava/util/List;") + void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteArray &resource) { if (resource=="JavaVM") @@ -163,10 +168,33 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶ if (Q_UNLIKELY(!eglBindAPI(EGL_OPENGL_ES_API))) qFatal("Could not bind GL_ES API"); - m_primaryScreen = new QAndroidPlatformScreen(); - QWindowSystemInterface::handleScreenAdded(m_primaryScreen); - m_primaryScreen->setSizeParameters(m_defaultPhysicalSize, m_defaultScreenSize, - m_defaultAvailableGeometry); + static const int primaryDisplayId = QJniObject::getStaticField( + QtJniTypes::className(), "DEFAULT_DISPLAY"); + + const QJniObject nativeDisplaysList = QJniObject::callStaticObjectMethod( + QtJniTypes::className(), + "getAvailableDisplays"); + + const int numberOfAvailableDisplays = nativeDisplaysList.callMethod("size"); + for (int i = 0; i < numberOfAvailableDisplays; ++i) { + const QJniObject display = + nativeDisplaysList.callObjectMethod("get", jint(i)); + + const bool isPrimary = (primaryDisplayId == display.callMethod("getDisplayId")); + auto screen = new QAndroidPlatformScreen(display); + + if (isPrimary) + m_primaryScreen = screen; + + QWindowSystemInterface::handleScreenAdded(screen, isPrimary); + } + + if (numberOfAvailableDisplays == 0) { + // If no displays are found, add a dummy display + auto defaultScreen = new QAndroidPlatformScreen(QJniObject {}); + m_primaryScreen = defaultScreen; + QWindowSystemInterface::handleScreenAdded(defaultScreen, true); + } m_mainThread = QThread::currentThread(); diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp index d2bb9f09f1..1c867f435d 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -52,11 +52,17 @@ private: # define PROFILE_SCOPE #endif -QAndroidPlatformScreen::QAndroidPlatformScreen() +Q_DECLARE_JNI_CLASS(Display, "android/view/Display") + +Q_DECLARE_JNI_TYPE(DisplayMode, "Landroid/view/Display$Mode;") + +QAndroidPlatformScreen::QAndroidPlatformScreen(const QJniObject &displayObject) : QObject(), QPlatformScreen() { m_availableGeometry = QAndroidPlatformIntegration::m_defaultAvailableGeometry; m_size = QAndroidPlatformIntegration::m_defaultScreenSize; + m_physicalSize = QAndroidPlatformIntegration::m_defaultPhysicalSize; + // Raster only apps should set QT_ANDROID_RASTER_IMAGE_DEPTH to 16 // is way much faster than 32 if (qEnvironmentVariableIntValue("QT_ANDROID_RASTER_IMAGE_DEPTH") == 16) { @@ -66,54 +72,52 @@ QAndroidPlatformScreen::QAndroidPlatformScreen() m_format = QImage::Format_ARGB32_Premultiplied; m_depth = 32; } - m_physicalSize = QAndroidPlatformIntegration::m_defaultPhysicalSize; - connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, &QAndroidPlatformScreen::applicationStateChanged); - QJniObject activity(QtAndroid::activity()); - if (!activity.isValid()) - return; - QJniObject display; - if (QNativeInterface::QAndroidApplication::sdkVersion() < 30) { - display = activity.callObjectMethod("getWindowManager", "()Landroid/view/WindowManager;") - .callObjectMethod("getDefaultDisplay", "()Landroid/view/Display;"); - } else { - display = activity.callObjectMethod("getDisplay", "()Landroid/view/Display;"); - } - if (!display.isValid()) - return; - - m_name = display.callObjectMethod("getName", "()Ljava/lang/String;").toString(); - m_refreshRate = display.callMethod("getRefreshRate"); + connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, + &QAndroidPlatformScreen::applicationStateChanged); - if (QNativeInterface::QAndroidApplication::sdkVersion() < 23) { - m_modes << Mode { .size = m_physicalSize.toSize(), .refreshRate = m_refreshRate }; + if (!displayObject.isValid()) return; - } - QJniEnvironment env; - const jint currentMode = display.callObjectMethod("getMode", "()Landroid/view/Display$Mode;") - .callMethod("getModeId"); - const auto modes = display.callObjectMethod("getSupportedModes", - "()[Landroid/view/Display$Mode;"); - const auto modesArray = jobjectArray(modes.object()); - const auto sz = env->GetArrayLength(modesArray); - for (jsize i = 0; i < sz; ++i) { - auto mode = QJniObject::fromLocalRef(env->GetObjectArrayElement(modesArray, i)); - if (currentMode == mode.callMethod("getModeId")) - m_currentMode = m_modes.size(); - m_modes << Mode { .size = QSize { mode.callMethod("getPhysicalHeight"), - mode.callMethod("getPhysicalWidth") }, - .refreshRate = mode.callMethod("getRefreshRate") }; - } + m_size = QSize(displayObject.callMethod("getWidth"), displayObject.callMethod("getHeight")); + m_name = displayObject.callObjectMethod("getName").toString(); + m_refreshRate = displayObject.callMethod("getRefreshRate"); + + if (QNativeInterface::QAndroidApplication::sdkVersion() >= 23) { + const QJniObject currentMode = displayObject.callObjectMethod("getMode"); + const jint currentModeId = currentMode.callMethod("getModeId"); + + const QJniObject supportedModes = displayObject.callObjectMethod( + "getSupportedModes"); + const auto modeArray = jobjectArray(supportedModes.object()); + + QJniEnvironment env; + const auto size = env->GetArrayLength(modeArray); + for (jsize i = 0; i < size; ++i) { + const auto mode = QJniObject::fromLocalRef(env->GetObjectArrayElement(modeArray, i)); + const int physicalWidth = mode.callMethod("getPhysicalWidth"); + const int physicalHeight = mode.callMethod("getPhysicalHeight"); + + if (currentModeId == mode.callMethod("getModeId")) { + m_currentMode = i; + m_physicalSize = QSize { + physicalWidth, + physicalHeight + }; + } - if (m_modes.isEmpty()) - m_modes << Mode { .size = m_physicalSize.toSize(), .refreshRate = m_refreshRate }; + m_modes << QPlatformScreen::Mode { + .size = QSize { physicalWidth, physicalHeight }, + .refreshRate = mode.callMethod("getRefreshRate") + }; + } + } } QAndroidPlatformScreen::~QAndroidPlatformScreen() { - if (m_id != -1) { - QtAndroid::destroySurface(m_id); + if (m_surfaceId != -1) { + QtAndroid::destroySurface(m_surfaceId); m_surfaceWaitCondition.wakeOne(); releaseSurface(); } @@ -304,9 +308,9 @@ void QAndroidPlatformScreen::setAvailableGeometry(const QRect &rect) } } - if (m_id != -1) { + if (m_surfaceId != -1) { releaseSurface(); - QtAndroid::setSurfaceGeometry(m_id, rect); + QtAndroid::setSurfaceGeometry(m_surfaceId, rect); } } @@ -317,8 +321,8 @@ void QAndroidPlatformScreen::applicationStateChanged(Qt::ApplicationState state) if (state <= Qt::ApplicationHidden) { lockSurface(); - QtAndroid::destroySurface(m_id); - m_id = -1; + QtAndroid::destroySurface(m_surfaceId); + m_surfaceId = -1; releaseSurface(); unlockSurface(); } @@ -361,17 +365,17 @@ void QAndroidPlatformScreen::doRedraw(QImage* screenGrabImage) } if (!hasVisibleRasterWindows) { lockSurface(); - if (m_id != -1) { - QtAndroid::destroySurface(m_id); + if (m_surfaceId != -1) { + QtAndroid::destroySurface(m_surfaceId); releaseSurface(); - m_id = -1; + m_surfaceId = -1; } unlockSurface(); return; } QMutexLocker lock(&m_surfaceMutex); - if (m_id == -1 && m_rasterSurfaces) { - m_id = QtAndroid::createSurface(this, geometry(), true, m_depth); + if (m_surfaceId == -1 && m_rasterSurfaces) { + m_surfaceId = QtAndroid::createSurface(this, geometry(), true, m_depth); AndroidDeadlockProtector protector; if (!protector.acquire()) return; diff --git a/src/plugins/platforms/android/qandroidplatformscreen.h b/src/plugins/platforms/android/qandroidplatformscreen.h index ef8371e72d..390bda0416 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.h +++ b/src/plugins/platforms/android/qandroidplatformscreen.h @@ -24,7 +24,7 @@ class QAndroidPlatformScreen: public QObject, public QPlatformScreen, public And { Q_OBJECT public: - QAndroidPlatformScreen(); + QAndroidPlatformScreen(const QJniObject &displayObject); ~QAndroidPlatformScreen(); QRect geometry() const override { return QRect(QPoint(), m_size); } @@ -38,7 +38,6 @@ public: int currentMode() const override { return m_currentMode; } int preferredMode() const override { return m_currentMode; } qreal refreshRate() const override { return m_refreshRate; } - inline QWindow *topWindow() const; QWindow *topLevelAt(const QPoint & p) const override; @@ -94,7 +93,7 @@ private slots: void doRedraw(QImage *screenGrabImage = nullptr); private: - int m_id = -1; + int m_surfaceId = -1; QAtomicInt m_rasterSurfaces = 0; ANativeWindow* m_nativeSurface = nullptr; QWaitCondition m_surfaceWaitCondition; -- cgit v1.2.3