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>
This commit is contained in:
parent
c7b93d471d
commit
fbf586db2c
@ -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)
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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())
|
||||
connect(qGuiApp, &QGuiApplication::applicationStateChanged, this,
|
||||
&QAndroidPlatformScreen::applicationStateChanged);
|
||||
|
||||
if (!displayObject.isValid())
|
||||
return;
|
||||
|
||||
m_name = display.callObjectMethod("getName", "()Ljava/lang/String;").toString();
|
||||
m_refreshRate = display.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) {
|
||||
m_modes << Mode { .size = m_physicalSize.toSize(), .refreshRate = m_refreshRate };
|
||||
return;
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
m_modes << QPlatformScreen::Mode {
|
||||
.size = QSize { physicalWidth, physicalHeight },
|
||||
.refreshRate = mode.callMethod<jfloat>("getRefreshRate")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
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") };
|
||||
}
|
||||
|
||||
if (m_modes.isEmpty())
|
||||
m_modes << Mode { .size = m_physicalSize.toSize(), .refreshRate = m_refreshRate };
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user