621 lines
23 KiB
C++
621 lines
23 KiB
C++
// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
|
// Copyright (C) 2021 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
|
|
|
#include "qandroidplatformintegration.h"
|
|
|
|
#include "androidjniaccessibility.h"
|
|
#include "androidjnimain.h"
|
|
#include "qabstracteventdispatcher.h"
|
|
#include "qandroideventdispatcher.h"
|
|
#include "qandroidplatformaccessibility.h"
|
|
#include "qandroidplatformbackingstore.h"
|
|
#include "qandroidplatformclipboard.h"
|
|
#include "qandroidplatformfontdatabase.h"
|
|
#include "qandroidplatformforeignwindow.h"
|
|
#include "qandroidplatformoffscreensurface.h"
|
|
#include "qandroidplatformopenglcontext.h"
|
|
#include "qandroidplatformopenglwindow.h"
|
|
#include "qandroidplatformscreen.h"
|
|
#include "qandroidplatformservices.h"
|
|
#include "qandroidplatformtheme.h"
|
|
#include "qandroidsystemlocale.h"
|
|
|
|
#include <QGuiApplication>
|
|
#include <QOffscreenSurface>
|
|
#include <QOpenGLContext>
|
|
#include <QThread>
|
|
#include <QtCore/QJniObject>
|
|
#include <QtGui/private/qeglpbuffer_p.h>
|
|
#include <QtGui/private/qguiapplication_p.h>
|
|
#include <QtGui/private/qoffscreensurface_p.h>
|
|
#include <qpa/qplatformoffscreensurface.h>
|
|
#include <qpa/qplatformwindow.h>
|
|
#include <qpa/qwindowsysteminterface.h>
|
|
|
|
#include <jni.h>
|
|
|
|
#if QT_CONFIG(vulkan)
|
|
#include "qandroidplatformvulkanwindow.h"
|
|
#include "qandroidplatformvulkaninstance.h"
|
|
#endif
|
|
|
|
#include <QtGui/qpa/qplatforminputcontextfactory_p.h>
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
using namespace Qt::StringLiterals;
|
|
|
|
Q_CONSTINIT QSize QAndroidPlatformIntegration::m_defaultScreenSize = QSize(320, 455);
|
|
Q_CONSTINIT QRect QAndroidPlatformIntegration::m_defaultAvailableGeometry = QRect(0, 0, 320, 455);
|
|
Q_CONSTINIT QSize QAndroidPlatformIntegration::m_defaultPhysicalSize = QSize(50, 71);
|
|
|
|
Qt::ScreenOrientation QAndroidPlatformIntegration::m_orientation = Qt::PrimaryOrientation;
|
|
Qt::ScreenOrientation QAndroidPlatformIntegration::m_nativeOrientation = Qt::PrimaryOrientation;
|
|
|
|
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_CLASS(List, "java/util/List")
|
|
|
|
namespace {
|
|
|
|
QAndroidPlatformScreen* createScreenForDisplayId(int displayId)
|
|
{
|
|
const QJniObject display = QJniObject::callStaticObjectMethod<QtJniTypes::Display>(
|
|
QtJniTypes::Traits<QtJniTypes::QtNative>::className(),
|
|
"getDisplay",
|
|
displayId);
|
|
if (!display.isValid())
|
|
return nullptr;
|
|
return new QAndroidPlatformScreen(display);
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteArray &resource)
|
|
{
|
|
if (resource=="JavaVM")
|
|
return QtAndroid::javaVM();
|
|
if (resource == "QtActivity") {
|
|
extern Q_CORE_EXPORT jobject qt_androidActivity();
|
|
return qt_androidActivity();
|
|
}
|
|
if (resource == "QtService") {
|
|
extern Q_CORE_EXPORT jobject qt_androidService();
|
|
return qt_androidService();
|
|
}
|
|
if (resource == "AndroidStyleData") {
|
|
if (m_androidStyle) {
|
|
if (m_androidStyle->m_styleData.isEmpty())
|
|
m_androidStyle->m_styleData = AndroidStyle::loadStyleData();
|
|
return &m_androidStyle->m_styleData;
|
|
}
|
|
else
|
|
return nullptr;
|
|
}
|
|
if (resource == "AndroidStandardPalette") {
|
|
if (m_androidStyle)
|
|
return &m_androidStyle->m_standardPalette;
|
|
|
|
return nullptr;
|
|
}
|
|
if (resource == "AndroidQWidgetFonts") {
|
|
if (m_androidStyle)
|
|
return &m_androidStyle->m_QWidgetsFonts;
|
|
|
|
return nullptr;
|
|
}
|
|
if (resource == "AndroidDeviceName") {
|
|
static QString deviceName = QtAndroid::deviceName();
|
|
return &deviceName;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void *QAndroidPlatformNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
|
|
{
|
|
#if QT_CONFIG(vulkan)
|
|
if (resource == "vkSurface") {
|
|
if (window->surfaceType() == QSurface::VulkanSurface) {
|
|
QAndroidPlatformVulkanWindow *w = static_cast<QAndroidPlatformVulkanWindow *>(window->handle());
|
|
// return a pointer to the VkSurfaceKHR, not the value
|
|
return w ? w->vkSurface() : nullptr;
|
|
}
|
|
}
|
|
#else
|
|
Q_UNUSED(resource);
|
|
Q_UNUSED(window);
|
|
#endif
|
|
return nullptr;
|
|
}
|
|
|
|
void *QAndroidPlatformNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context)
|
|
{
|
|
if (QEGLPlatformContext *platformContext = static_cast<QEGLPlatformContext *>(context->handle())) {
|
|
if (resource == "eglcontext")
|
|
return platformContext->eglContext();
|
|
else if (resource == "eglconfig")
|
|
return platformContext->eglConfig();
|
|
else if (resource == "egldisplay")
|
|
return platformContext->eglDisplay();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void QAndroidPlatformNativeInterface::customEvent(QEvent *event)
|
|
{
|
|
if (event->type() != QEvent::User)
|
|
return;
|
|
|
|
QMutexLocker lock(QtAndroid::platformInterfaceMutex());
|
|
QAndroidPlatformIntegration *api = static_cast<QAndroidPlatformIntegration *>(QGuiApplicationPrivate::platformIntegration());
|
|
QtAndroid::setAndroidPlatformIntegration(api);
|
|
|
|
#if QT_CONFIG(accessibility)
|
|
// Android accessibility activation event might have been already received
|
|
api->accessibility()->setActive(QtAndroidAccessibility::isActive());
|
|
#endif // QT_CONFIG(accessibility)
|
|
|
|
if (!m_running) {
|
|
m_running = true;
|
|
QtAndroid::notifyQtAndroidPluginRunning(m_running);
|
|
}
|
|
api->flushPendingUpdates();
|
|
}
|
|
|
|
QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶mList)
|
|
: m_touchDevice(nullptr)
|
|
#if QT_CONFIG(accessibility)
|
|
, m_accessibility(nullptr)
|
|
#endif
|
|
{
|
|
Q_UNUSED(paramList);
|
|
m_androidPlatformNativeInterface = new QAndroidPlatformNativeInterface();
|
|
|
|
m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
|
if (Q_UNLIKELY(m_eglDisplay == EGL_NO_DISPLAY))
|
|
qFatal("Could not open egl display");
|
|
|
|
EGLint major, minor;
|
|
if (Q_UNLIKELY(!eglInitialize(m_eglDisplay, &major, &minor)))
|
|
qFatal("Could not initialize egl display");
|
|
|
|
if (Q_UNLIKELY(!eglBindAPI(EGL_OPENGL_ES_API)))
|
|
qFatal("Could not bind GL_ES API");
|
|
|
|
m_primaryDisplayId = QJniObject::getStaticField<jint>(
|
|
QtJniTypes::Traits<QtJniTypes::Display>::className(), "DEFAULT_DISPLAY");
|
|
|
|
const QJniObject nativeDisplaysList = QJniObject::callStaticObjectMethod<QtJniTypes::List>(
|
|
QtJniTypes::Traits<QtJniTypes::QtNative>::className(),
|
|
"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 int displayId = display.callMethod<jint>("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) {
|
|
// 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();
|
|
|
|
m_androidFDB = new QAndroidPlatformFontDatabase();
|
|
m_androidPlatformServices = new QAndroidPlatformServices();
|
|
|
|
#ifndef QT_NO_CLIPBOARD
|
|
m_androidPlatformClipboard = new QAndroidPlatformClipboard();
|
|
#endif
|
|
|
|
m_androidSystemLocale = new QAndroidSystemLocale;
|
|
|
|
#if QT_CONFIG(accessibility)
|
|
m_accessibility = new QAndroidPlatformAccessibility();
|
|
#endif // QT_CONFIG(accessibility)
|
|
|
|
QJniObject javaActivity = QtAndroidPrivate::activity();
|
|
if (!javaActivity.isValid())
|
|
javaActivity = QtAndroidPrivate::service();
|
|
|
|
if (javaActivity.isValid()) {
|
|
QJniObject resources = javaActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;");
|
|
QJniObject configuration = resources.callObjectMethod("getConfiguration", "()Landroid/content/res/Configuration;");
|
|
|
|
int touchScreen = configuration.getField<jint>("touchscreen");
|
|
if (touchScreen == QJniObject::getStaticField<jint>("android/content/res/Configuration", "TOUCHSCREEN_FINGER")
|
|
|| touchScreen == QJniObject::getStaticField<jint>("android/content/res/Configuration", "TOUCHSCREEN_STYLUS"))
|
|
{
|
|
QJniObject pm = javaActivity.callObjectMethod("getPackageManager", "()Landroid/content/pm/PackageManager;");
|
|
Q_ASSERT(pm.isValid());
|
|
int maxTouchPoints = 1;
|
|
if (pm.callMethod<jboolean>("hasSystemFeature","(Ljava/lang/String;)Z",
|
|
QJniObject::getStaticObjectField("android/content/pm/PackageManager",
|
|
"FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND",
|
|
"Ljava/lang/String;").object())) {
|
|
maxTouchPoints = 10;
|
|
} else if (pm.callMethod<jboolean>("hasSystemFeature","(Ljava/lang/String;)Z",
|
|
QJniObject::getStaticObjectField("android/content/pm/PackageManager",
|
|
"FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT",
|
|
"Ljava/lang/String;").object())) {
|
|
maxTouchPoints = 4;
|
|
} else if (pm.callMethod<jboolean>("hasSystemFeature","(Ljava/lang/String;)Z",
|
|
QJniObject::getStaticObjectField("android/content/pm/PackageManager",
|
|
"FEATURE_TOUCHSCREEN_MULTITOUCH",
|
|
"Ljava/lang/String;").object())) {
|
|
maxTouchPoints = 2;
|
|
}
|
|
|
|
m_touchDevice = new QPointingDevice("Android touchscreen", 1,
|
|
QInputDevice::DeviceType::TouchScreen,
|
|
QPointingDevice::PointerType::Finger,
|
|
QPointingDevice::Capability::Position
|
|
| QPointingDevice::Capability::Area
|
|
| QPointingDevice::Capability::Pressure
|
|
| QPointingDevice::Capability::NormalizedPosition,
|
|
maxTouchPoints,
|
|
0);
|
|
QWindowSystemInterface::registerInputDevice(m_touchDevice);
|
|
}
|
|
|
|
auto contentResolver = javaActivity.callObjectMethod("getContentResolver", "()Landroid/content/ContentResolver;");
|
|
Q_ASSERT(contentResolver.isValid());
|
|
QJniObject txtShowPassValue = QJniObject::callStaticObjectMethod(
|
|
"android/provider/Settings$System",
|
|
"getString",
|
|
"(Landroid/content/ContentResolver;Ljava/lang/String;)Ljava/lang/String;",
|
|
contentResolver.object(),
|
|
QJniObject::getStaticObjectField("android/provider/Settings$System",
|
|
"TEXT_SHOW_PASSWORD",
|
|
"Ljava/lang/String;").object());
|
|
if (txtShowPassValue.isValid()) {
|
|
bool ok = false;
|
|
const int txtShowPass = txtShowPassValue.toString().toInt(&ok);
|
|
m_showPasswordEnabled = ok ? (txtShowPass == 1) : false;
|
|
}
|
|
}
|
|
|
|
// We can't safely notify the jni bridge that we're up and running just yet, so let's postpone
|
|
// it for now.
|
|
QCoreApplication::postEvent(m_androidPlatformNativeInterface, new QEvent(QEvent::User));
|
|
}
|
|
|
|
static bool needsBasicRenderloopWorkaround()
|
|
{
|
|
static bool needsWorkaround =
|
|
QtAndroid::deviceName().compare("samsung SM-T211"_L1, Qt::CaseInsensitive) == 0
|
|
|| QtAndroid::deviceName().compare("samsung SM-T210"_L1, Qt::CaseInsensitive) == 0
|
|
|| QtAndroid::deviceName().compare("samsung SM-T215"_L1, Qt::CaseInsensitive) == 0;
|
|
return needsWorkaround;
|
|
}
|
|
|
|
void QAndroidPlatformIntegration::initialize()
|
|
{
|
|
const QString icStr = QPlatformInputContextFactory::requested();
|
|
if (icStr.isNull())
|
|
m_inputContext.reset(new QAndroidInputContext);
|
|
else
|
|
m_inputContext.reset(QPlatformInputContextFactory::create(icStr));
|
|
}
|
|
|
|
bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
|
|
{
|
|
switch (cap) {
|
|
case ApplicationState: return true;
|
|
case ThreadedPixmaps: return true;
|
|
case NativeWidgets: return QtAndroidPrivate::activity().isValid();
|
|
case OpenGL: return QtAndroidPrivate::activity().isValid();
|
|
case ForeignWindows: return QtAndroidPrivate::activity().isValid();
|
|
case ThreadedOpenGL: return !needsBasicRenderloopWorkaround() && QtAndroidPrivate::activity().isValid();
|
|
case RasterGLSurface: return QtAndroidPrivate::activity().isValid();
|
|
case TopStackedNativeChildWindows: return false;
|
|
case MaximizeUsingFullscreenGeometry: return true;
|
|
default:
|
|
return QPlatformIntegration::hasCapability(cap);
|
|
}
|
|
}
|
|
|
|
QPlatformBackingStore *QAndroidPlatformIntegration::createPlatformBackingStore(QWindow *window) const
|
|
{
|
|
if (!QtAndroidPrivate::activity().isValid())
|
|
return nullptr;
|
|
|
|
return new QAndroidPlatformBackingStore(window);
|
|
}
|
|
|
|
QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
|
|
{
|
|
if (!QtAndroidPrivate::activity().isValid())
|
|
return nullptr;
|
|
QSurfaceFormat format(context->format());
|
|
format.setAlphaBufferSize(8);
|
|
format.setRedBufferSize(8);
|
|
format.setGreenBufferSize(8);
|
|
format.setBlueBufferSize(8);
|
|
auto ctx = new QAndroidPlatformOpenGLContext(format, context->shareHandle(), m_eglDisplay);
|
|
return ctx;
|
|
}
|
|
|
|
QOpenGLContext *QAndroidPlatformIntegration::createOpenGLContext(EGLContext context, EGLDisplay display, QOpenGLContext *shareContext) const
|
|
{
|
|
return QEGLPlatformContext::createFrom<QAndroidPlatformOpenGLContext>(context, display, m_eglDisplay, shareContext);
|
|
}
|
|
|
|
QPlatformOffscreenSurface *QAndroidPlatformIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
|
|
{
|
|
if (!QtAndroidPrivate::activity().isValid())
|
|
return nullptr;
|
|
|
|
QSurfaceFormat format(surface->requestedFormat());
|
|
format.setAlphaBufferSize(8);
|
|
format.setRedBufferSize(8);
|
|
format.setGreenBufferSize(8);
|
|
format.setBlueBufferSize(8);
|
|
|
|
return new QEGLPbuffer(m_eglDisplay, format, surface);
|
|
}
|
|
|
|
QOffscreenSurface *QAndroidPlatformIntegration::createOffscreenSurface(ANativeWindow *nativeSurface) const
|
|
{
|
|
if (!QtAndroidPrivate::activity().isValid() || !nativeSurface)
|
|
return nullptr;
|
|
|
|
auto *surface = new QOffscreenSurface;
|
|
auto *surfacePrivate = QOffscreenSurfacePrivate::get(surface);
|
|
surfacePrivate->platformOffscreenSurface = new QAndroidPlatformOffscreenSurface(nativeSurface, m_eglDisplay, surface);
|
|
return surface;
|
|
}
|
|
|
|
QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *window) const
|
|
{
|
|
if (!QtAndroidPrivate::activity().isValid())
|
|
return nullptr;
|
|
|
|
#if QT_CONFIG(vulkan)
|
|
if (window->surfaceType() == QSurface::VulkanSurface)
|
|
return new QAndroidPlatformVulkanWindow(window);
|
|
#endif
|
|
|
|
return new QAndroidPlatformOpenGLWindow(window, m_eglDisplay);
|
|
}
|
|
|
|
QPlatformWindow *QAndroidPlatformIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const
|
|
{
|
|
return new QAndroidPlatformForeignWindow(window, nativeHandle);
|
|
}
|
|
|
|
QAbstractEventDispatcher *QAndroidPlatformIntegration::createEventDispatcher() const
|
|
{
|
|
return new QAndroidEventDispatcher;
|
|
}
|
|
|
|
QAndroidPlatformIntegration::~QAndroidPlatformIntegration()
|
|
{
|
|
if (m_eglDisplay != EGL_NO_DISPLAY)
|
|
eglTerminate(m_eglDisplay);
|
|
|
|
delete m_androidPlatformNativeInterface;
|
|
delete m_androidFDB;
|
|
delete m_androidSystemLocale;
|
|
|
|
#ifndef QT_NO_CLIPBOARD
|
|
delete m_androidPlatformClipboard;
|
|
#endif
|
|
|
|
QtAndroid::setAndroidPlatformIntegration(NULL);
|
|
}
|
|
|
|
QPlatformFontDatabase *QAndroidPlatformIntegration::fontDatabase() const
|
|
{
|
|
return m_androidFDB;
|
|
}
|
|
|
|
#ifndef QT_NO_CLIPBOARD
|
|
QPlatformClipboard *QAndroidPlatformIntegration::clipboard() const
|
|
{
|
|
return m_androidPlatformClipboard;
|
|
}
|
|
#endif
|
|
|
|
QPlatformInputContext *QAndroidPlatformIntegration::inputContext() const
|
|
{
|
|
return m_inputContext.data();
|
|
}
|
|
|
|
QPlatformNativeInterface *QAndroidPlatformIntegration::nativeInterface() const
|
|
{
|
|
return m_androidPlatformNativeInterface;
|
|
}
|
|
|
|
QPlatformServices *QAndroidPlatformIntegration::services() const
|
|
{
|
|
return m_androidPlatformServices;
|
|
}
|
|
|
|
QVariant QAndroidPlatformIntegration::styleHint(StyleHint hint) const
|
|
{
|
|
switch (hint) {
|
|
case PasswordMaskDelay:
|
|
// this number is from a hard-coded value in Android code (cf. PasswordTransformationMethod)
|
|
return m_showPasswordEnabled ? 1500 : 0;
|
|
case ShowIsMaximized:
|
|
return true;
|
|
default:
|
|
return QPlatformIntegration::styleHint(hint);
|
|
}
|
|
}
|
|
|
|
Qt::WindowState QAndroidPlatformIntegration::defaultWindowState(Qt::WindowFlags flags) const
|
|
{
|
|
// Don't maximize dialogs on Android
|
|
if (flags & Qt::Dialog & ~Qt::Window)
|
|
return Qt::WindowNoState;
|
|
|
|
return QPlatformIntegration::defaultWindowState(flags);
|
|
}
|
|
|
|
static const auto androidThemeName = "android"_L1;
|
|
QStringList QAndroidPlatformIntegration::themeNames() const
|
|
{
|
|
return QStringList(QString(androidThemeName));
|
|
}
|
|
|
|
QPlatformTheme *QAndroidPlatformIntegration::createPlatformTheme(const QString &name) const
|
|
{
|
|
if (androidThemeName == name)
|
|
return QAndroidPlatformTheme::instance(m_androidPlatformNativeInterface);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void QAndroidPlatformIntegration::setDefaultDisplayMetrics(int availableLeft, int availableTop,
|
|
int availableWidth, int availableHeight,
|
|
int physicalWidth, int physicalHeight,
|
|
int screenWidth, int screenHeight)
|
|
{
|
|
m_defaultAvailableGeometry = QRect(availableLeft, availableTop,
|
|
availableWidth, availableHeight);
|
|
m_defaultPhysicalSize = QSize(physicalWidth, physicalHeight);
|
|
m_defaultScreenSize = QSize(screenWidth, screenHeight);
|
|
}
|
|
|
|
void QAndroidPlatformIntegration::setScreenOrientation(Qt::ScreenOrientation currentOrientation,
|
|
Qt::ScreenOrientation nativeOrientation)
|
|
{
|
|
m_orientation = currentOrientation;
|
|
m_nativeOrientation = nativeOrientation;
|
|
}
|
|
|
|
void QAndroidPlatformIntegration::flushPendingUpdates()
|
|
{
|
|
if (m_primaryScreen) {
|
|
m_primaryScreen->setSizeParameters(m_defaultPhysicalSize, m_defaultScreenSize,
|
|
m_defaultAvailableGeometry);
|
|
}
|
|
}
|
|
|
|
#if QT_CONFIG(accessibility)
|
|
QPlatformAccessibility *QAndroidPlatformIntegration::accessibility() const
|
|
{
|
|
return m_accessibility;
|
|
}
|
|
#endif
|
|
|
|
void QAndroidPlatformIntegration::setAvailableGeometry(const QRect &availableGeometry)
|
|
{
|
|
if (m_primaryScreen)
|
|
QMetaObject::invokeMethod(m_primaryScreen, "setAvailableGeometry", Qt::AutoConnection, Q_ARG(QRect, availableGeometry));
|
|
}
|
|
|
|
void QAndroidPlatformIntegration::setPhysicalSize(int width, int height)
|
|
{
|
|
if (m_primaryScreen)
|
|
QMetaObject::invokeMethod(m_primaryScreen, "setPhysicalSize", Qt::AutoConnection, Q_ARG(QSize, QSize(width, height)));
|
|
}
|
|
|
|
void QAndroidPlatformIntegration::setScreenSize(int width, int height)
|
|
{
|
|
if (m_primaryScreen)
|
|
QMetaObject::invokeMethod(m_primaryScreen, "setSize", Qt::AutoConnection, Q_ARG(QSize, QSize(width, height)));
|
|
}
|
|
|
|
Qt::ColorScheme QAndroidPlatformIntegration::m_colorScheme = Qt::ColorScheme::Light;
|
|
|
|
void QAndroidPlatformIntegration::setColorScheme(Qt::ColorScheme colorScheme)
|
|
{
|
|
if (m_colorScheme == colorScheme)
|
|
return;
|
|
m_colorScheme = colorScheme;
|
|
|
|
QMetaObject::invokeMethod(qGuiApp,
|
|
[] () { QAndroidPlatformTheme::instance()->updateColorScheme();});
|
|
}
|
|
|
|
void QAndroidPlatformIntegration::setScreenSizeParameters(const QSize &physicalSize,
|
|
const QSize &screenSize,
|
|
const QRect &availableGeometry)
|
|
{
|
|
if (m_primaryScreen) {
|
|
QMetaObject::invokeMethod(m_primaryScreen, "setSizeParameters", Qt::AutoConnection,
|
|
Q_ARG(QSize, physicalSize), Q_ARG(QSize, screenSize),
|
|
Q_ARG(QRect, availableGeometry));
|
|
}
|
|
}
|
|
|
|
void QAndroidPlatformIntegration::setRefreshRate(qreal refreshRate)
|
|
{
|
|
if (m_primaryScreen)
|
|
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
|
|
{
|
|
return new QAndroidPlatformVulkanInstance(instance);
|
|
}
|
|
|
|
#endif // QT_CONFIG(vulkan)
|
|
|
|
QT_END_NAMESPACE
|