summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWojciech Błaszak <wojciech.blaszak@siili.com>2022-07-22 13:05:56 +0200
committerPetri Virkkunen <petri.virkkunen@qt.io>2022-10-26 15:32:52 +0300
commitfbf586db2c587e7ba83cf1bfe8e5b912310d6bdb (patch)
tree3a59b5ad77fe4e0790d65050b0e56feb0b141ba2
parentc7b93d471d763b5e7986305deb4d0d83d7b69068 (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>
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtNative.java15
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.cpp36
-rw-r--r--src/plugins/platforms/android/qandroidplatformscreen.cpp102
-rw-r--r--src/plugins/platforms/android/qandroidplatformscreen.h5
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 &para
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;