From 9ce8d4890fdeaa02cc8a7687158d7453bbc7fd49 Mon Sep 17 00:00:00 2001 From: Piotr Mikolajczyk Date: Fri, 25 Nov 2022 12:43:26 +0100 Subject: Add handling of screen hotplug When a display is connected to an Android device a notification is sent to the platform layer of the application. The QAndroidPlatformIntegration will create a platform screen and add it to QWindowSystem. Task-number: QAA-1257 Change-Id: Id2cf6b47363630c3b5c93c0bc778e2058d8372b3 Reviewed-by: Assam Boudjelthia --- src/plugins/platforms/android/androidjnimain.cpp | 23 +++++++- .../android/qandroidplatformintegration.cpp | 65 +++++++++++++++++++++- .../android/qandroidplatformintegration.h | 17 ++++++ 3 files changed, 101 insertions(+), 4 deletions(-) (limited to 'src/plugins/platforms/android') diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 9ce899d4a3..5b066fb5a5 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -755,6 +755,24 @@ static void handleRefreshRateChanged(JNIEnv */*env*/, jclass /*cls*/, jfloat ref m_androidPlatformIntegration->setRefreshRate(refreshRate); } +static void handleScreenAdded(JNIEnv */*env*/, jclass /*cls*/, jint displayId) +{ + if (m_androidPlatformIntegration) + m_androidPlatformIntegration->handleScreenAdded(displayId); +} + +static void handleScreenChanged(JNIEnv */*env*/, jclass /*cls*/, jint displayId) +{ + if (m_androidPlatformIntegration) + m_androidPlatformIntegration->handleScreenChanged(displayId); +} + +static void handleScreenRemoved(JNIEnv */*env*/, jclass /*cls*/, jint displayId) +{ + if (m_androidPlatformIntegration) + m_androidPlatformIntegration->handleScreenRemoved(displayId); +} + static void handleUiDarkModeChanged(JNIEnv */*env*/, jobject /*thiz*/, jint newUiMode) { QAndroidPlatformIntegration::setAppearance( @@ -795,7 +813,10 @@ static JNINativeMethod methods[] = { { "onActivityResult", "(IILandroid/content/Intent;)V", (void *)onActivityResult }, { "onNewIntent", "(Landroid/content/Intent;)V", (void *)onNewIntent }, { "onBind", "(Landroid/content/Intent;)Landroid/os/IBinder;", (void *)onBind }, - { "handleRefreshRateChanged", "(F)V", (void *)handleRefreshRateChanged } + { "handleRefreshRateChanged", "(F)V", (void *)handleRefreshRateChanged }, + { "handleScreenAdded", "(I)V", (void *)handleScreenAdded }, + { "handleScreenChanged", "(I)V", (void *)handleScreenChanged }, + { "handleScreenRemoved", "(I)V", (void *)handleScreenRemoved } }; #define FIND_AND_CHECK_CLASS(CLASS_NAME) \ diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index 0d5b473477..dec9082eca 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -61,6 +61,21 @@ Q_DECLARE_JNI_CLASS(Display, "android/view/Display") Q_DECLARE_JNI_TYPE(List, "Ljava/util/List;") +namespace { + +QAndroidPlatformScreen* createScreenForDisplayId(int displayId) +{ + const QJniObject display = QJniObject::callStaticObjectMethod( + QtJniTypes::className(), + "getDisplay", + displayId); + if (!display.isValid()) + return nullptr; + return new QAndroidPlatformScreen(display); +} + +} // anonymous namespace + void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteArray &resource) { if (resource=="JavaVM") @@ -168,7 +183,7 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶ if (Q_UNLIKELY(!eglBindAPI(EGL_OPENGL_ES_API))) qFatal("Could not bind GL_ES API"); - static const int primaryDisplayId = QJniObject::getStaticField( + m_primaryDisplayId = QJniObject::getStaticField( QtJniTypes::className(), "DEFAULT_DISPLAY"); const QJniObject nativeDisplaysList = QJniObject::callStaticObjectMethod( @@ -179,14 +194,15 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶ for (int i = 0; i < numberOfAvailableDisplays; ++i) { const QJniObject display = nativeDisplaysList.callObjectMethod("get", jint(i)); - - const bool isPrimary = (primaryDisplayId == display.callMethod("getDisplayId")); + const int displayId = display.callMethod("getDisplayId"); + const bool isPrimary = (m_primaryDisplayId == displayId); auto screen = new QAndroidPlatformScreen(display); if (isPrimary) m_primaryScreen = screen; QWindowSystemInterface::handleScreenAdded(screen, isPrimary); + m_screens[displayId] = screen; } if (numberOfAvailableDisplays == 0) { @@ -545,6 +561,49 @@ void QAndroidPlatformIntegration::setRefreshRate(qreal refreshRate) QMetaObject::invokeMethod(m_primaryScreen, "setRefreshRate", Qt::AutoConnection, Q_ARG(qreal, refreshRate)); } + +void QAndroidPlatformIntegration::handleScreenAdded(int displayId) +{ + auto result = m_screens.insert(displayId, nullptr); + if (result.first->second == nullptr) { + auto it = result.first; + it->second = createScreenForDisplayId(displayId); + if (it->second == nullptr) + return; + const bool isPrimary = (m_primaryDisplayId == displayId); + if (isPrimary) + m_primaryScreen = it->second; + QWindowSystemInterface::handleScreenAdded(it->second, isPrimary); + } else { + qWarning() << "Display with id" << displayId << "already exists."; + } +} + +void QAndroidPlatformIntegration::handleScreenChanged(int displayId) +{ + auto it = m_screens.find(displayId); + if (it == m_screens.end() || it->second == nullptr) { + handleScreenAdded(displayId); + } + // We do not do anything more here as handling of change of + // rotation and refresh rate is done in QtActivityDelegate java class + // which calls QAndroidPlatformIntegration::setOrientation, and + // QAndroidPlatformIntegration::setRefreshRate accordingly. +} + +void QAndroidPlatformIntegration::handleScreenRemoved(int displayId) +{ + auto it = m_screens.find(displayId); + + if (it == m_screens.end()) + return; + + if (it->second != nullptr) + QWindowSystemInterface::handleScreenRemoved(it->second); + + m_screens.erase(it); +} + #if QT_CONFIG(vulkan) QPlatformVulkanInstance *QAndroidPlatformIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const diff --git a/src/plugins/platforms/android/qandroidplatformintegration.h b/src/plugins/platforms/android/qandroidplatformintegration.h index 4685ba32d4..8463dc8949 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.h +++ b/src/plugins/platforms/android/qandroidplatformintegration.h @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include @@ -75,6 +77,10 @@ public: QPlatformFontDatabase *fontDatabase() const override; + void handleScreenAdded(int displayId); + void handleScreenChanged(int displayId); + void handleScreenRemoved(int displayId); + #ifndef QT_NO_CLIPBOARD QPlatformClipboard *clipboard() const override; #endif @@ -132,6 +138,17 @@ private: QAndroidPlatformNativeInterface *m_androidPlatformNativeInterface; QAndroidPlatformServices *m_androidPlatformServices; + // Handling the multiple screens connected. Every display is identified + // with an unique (autoincremented) displayID. The values of this ID will + // not repeat during the OS runtime. We use this value as the key in the + // storage of screens. + QFlatMap + , QVarLengthArray + , QVarLengthArray > m_screens; + // ID of the primary display, in documentation it is said to be always 0, + // but nevertheless it is retrieved + int m_primaryDisplayId = 0; + #ifndef QT_NO_CLIPBOARD QPlatformClipboard *m_androidPlatformClipboard; #endif -- cgit v1.2.3