diff options
author | Wojciech Błaszak <wojciech.blaszak@siili.com> | 2022-07-22 13:05:56 +0200 |
---|---|---|
committer | Petri Virkkunen <petri.virkkunen@qt.io> | 2022-10-26 15:32:52 +0300 |
commit | fbf586db2c587e7ba83cf1bfe8e5b912310d6bdb (patch) | |
tree | 3a59b5ad77fe4e0790d65050b0e56feb0b141ba2 | |
parent | c7b93d471d763b5e7986305deb4d0d83d7b69068 (diff) |
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 <assam.boudjelthia@qt.io>
4 files changed, 102 insertions, 56 deletions
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtNative.java b/src/android/jar/src/org/qtproject/qt/android/QtNative.java index f2ab7bb131..d4cbf75083 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtNative.java @@ -8,6 +8,7 @@ import java.io.File; import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Objects; import java.util.concurrent.Semaphore; import java.util.HashMap; @@ -37,6 +38,8 @@ import android.view.Menu; import android.view.MotionEvent; import android.view.View; import android.view.InputDevice; +import android.view.Display; +import android.hardware.display.DisplayManager; import android.database.Cursor; import android.provider.DocumentsContract; @@ -592,6 +595,18 @@ public class QtNative }); } + public static List<Display> getAvailableDisplays() + { + Context context = getContext(); + DisplayManager displayManager = + (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); + if (displayManager != null) { + Display[] displays = displayManager.getDisplays(); + return Arrays.asList(displays); + } + return new ArrayList<Display>(); + } + public static boolean startApplication(String params, String mainLib) throws Exception { if (params == null) 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<jint>( + QtJniTypes::className<QtJniTypes::Display>(), "DEFAULT_DISPLAY"); + + const QJniObject nativeDisplaysList = QJniObject::callStaticObjectMethod<QtJniTypes::List>( + QtJniTypes::className<QtJniTypes::QtNative>(), + "getAvailableDisplays"); + + const int numberOfAvailableDisplays = nativeDisplaysList.callMethod<jint>("size"); + for (int i = 0; i < numberOfAvailableDisplays; ++i) { + const QJniObject display = + nativeDisplaysList.callObjectMethod<jobject, jint>("get", jint(i)); + + const bool isPrimary = (primaryDisplayId == display.callMethod<jint>("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<jfloat>("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<jint>("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<jint>("getModeId")) - m_currentMode = m_modes.size(); - m_modes << Mode { .size = QSize { mode.callMethod<jint>("getPhysicalHeight"), - mode.callMethod<jint>("getPhysicalWidth") }, - .refreshRate = mode.callMethod<jfloat>("getRefreshRate") }; - } + m_size = QSize(displayObject.callMethod<jint>("getWidth"), displayObject.callMethod<jint>("getHeight")); + m_name = displayObject.callObjectMethod<jstring>("getName").toString(); + m_refreshRate = displayObject.callMethod<jfloat>("getRefreshRate"); + + if (QNativeInterface::QAndroidApplication::sdkVersion() >= 23) { + const QJniObject currentMode = displayObject.callObjectMethod<QtJniTypes::DisplayMode>("getMode"); + const jint currentModeId = currentMode.callMethod<jint>("getModeId"); + + const QJniObject supportedModes = displayObject.callObjectMethod<QtJniTypes::DisplayMode[]>( + "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<jint>("getPhysicalWidth"); + const int physicalHeight = mode.callMethod<jint>("getPhysicalHeight"); + + if (currentModeId == mode.callMethod<jint>("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<jfloat>("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; |