Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qandroidplatformintegration.cpp
Go to the documentation of this file.
1// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
2// Copyright (C) 2021 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
7
8#if QT_CONFIG(accessibility)
9#include "androidjniaccessibility.h"
10#endif
11#include "androidjnimain.h"
14#if QT_CONFIG(accessibility)
15#include "qandroidplatformaccessibility.h"
16#endif
21#if QT_CONFIG(egl)
22#include "qandroidplatformopenglcontext.h"
23#endif
29
30#include <QGuiApplication>
31#include <QOffscreenSurface>
32#include <QOpenGLContext>
33#include <QThread>
34#include <QtCore/QJniObject>
35#if QT_CONFIG(egl)
36#include <QtGui/private/qeglpbuffer_p.h>
37#endif
38#include <QtGui/private/qguiapplication_p.h>
39#include <QtGui/private/qoffscreensurface_p.h>
40#include <QtGui/private/qrhibackingstore_p.h>
41#include <qpa/qplatformoffscreensurface.h>
42#include <qpa/qplatformwindow.h>
43#include <qpa/qwindowsysteminterface.h>
44
45#include <jni.h>
46
47#if QT_CONFIG(vulkan)
48#include "qandroidplatformvulkanwindow.h"
49#include "qandroidplatformvulkaninstance.h"
50#endif
51
52#include <QtGui/qpa/qplatforminputcontextfactory_p.h>
53
55
56using namespace Qt::StringLiterals;
57
58Qt::ScreenOrientation QAndroidPlatformIntegration::m_orientation = Qt::PrimaryOrientation;
59Qt::ScreenOrientation QAndroidPlatformIntegration::m_nativeOrientation = Qt::PrimaryOrientation;
60
61bool QAndroidPlatformIntegration::m_showPasswordEnabled = false;
62
63Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtDisplayManager")
64Q_DECLARE_JNI_CLASS(Display, "android/view/Display")
65
66Q_DECLARE_JNI_CLASS(List, "java/util/List")
67
68namespace {
69
70QAndroidPlatformScreen* createScreenForDisplayId(int displayId)
71{
72 const QJniObject display = QtJniTypes::QtDisplayManager::callStaticMethod<QtJniTypes::Display>(
73 "getDisplay", QtAndroidPrivate::context(), displayId);
74 if (!display.isValid())
75 return nullptr;
76 return new QAndroidPlatformScreen(display);
77}
78
79static bool isValidAndroidContextForRendering()
80{
81 return QtAndroid::isQtApplication() ? QtAndroidPrivate::activity().isValid()
82 : QtAndroidPrivate::context().isValid();
83}
84
85} // anonymous namespace
86
88{
89 if (resource=="JavaVM")
90 return QtAndroidPrivate::javaVM();
91 if (resource == "QtActivity") {
92 extern Q_CORE_EXPORT jobject qt_androidActivity();
93 return qt_androidActivity();
94 }
95 if (resource == "QtService") {
96 extern Q_CORE_EXPORT jobject qt_androidService();
97 return qt_androidService();
98 }
99 if (resource == "AndroidStyleData") {
100 if (m_androidStyle) {
101 if (m_androidStyle->m_styleData.isEmpty())
102 m_androidStyle->m_styleData = AndroidStyle::loadStyleData();
103 return &m_androidStyle->m_styleData;
104 }
105 else
106 return nullptr;
107 }
108 if (resource == "AndroidStandardPalette") {
109 if (m_androidStyle)
110 return &m_androidStyle->m_standardPalette;
111
112 return nullptr;
113 }
114 if (resource == "AndroidQWidgetFonts") {
115 if (m_androidStyle)
116 return &m_androidStyle->m_QWidgetsFonts;
117
118 return nullptr;
119 }
120 if (resource == "AndroidDeviceName") {
121 static QString deviceName = QtAndroid::deviceName();
122 return &deviceName;
123 }
124 return 0;
125}
126
127void *QAndroidPlatformNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
128{
129#if QT_CONFIG(vulkan)
130 if (resource == "vkSurface") {
131 if (window->surfaceType() == QSurface::VulkanSurface) {
132 QAndroidPlatformVulkanWindow *w = static_cast<QAndroidPlatformVulkanWindow *>(window->handle());
133 // return a pointer to the VkSurfaceKHR, not the value
134 return w ? w->vkSurface() : nullptr;
135 }
136 }
137#else
138 Q_UNUSED(resource);
139 Q_UNUSED(window);
140#endif
141 return nullptr;
142}
143
144void *QAndroidPlatformNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context)
145{
146#if QT_CONFIG(egl)
147 if (QEGLPlatformContext *platformContext = static_cast<QEGLPlatformContext *>(context->handle())) {
148 if (resource == "eglcontext")
149 return platformContext->eglContext();
150 else if (resource == "eglconfig")
151 return platformContext->eglConfig();
152 else if (resource == "egldisplay")
153 return platformContext->eglDisplay();
154 }
155#else
156 Q_UNUSED(resource)
157 Q_UNUSED(context)
158#endif
159 return nullptr;
160}
161
162void QAndroidPlatformNativeInterface::customEvent(QEvent *event)
163{
164 if (event->type() != QEvent::User)
165 return;
166
167 QMutexLocker lock(QtAndroid::platformInterfaceMutex());
168 QAndroidPlatformIntegration *api = static_cast<QAndroidPlatformIntegration *>(QGuiApplicationPrivate::platformIntegration());
170
171#if QT_CONFIG(accessibility)
172 // Android accessibility activation event might have been already received
173 api->accessibility()->setActive(QtAndroidAccessibility::isActive());
174#endif // QT_CONFIG(accessibility)
175
177}
178
180 : m_touchDevice(nullptr)
181#if QT_CONFIG(accessibility)
182 , m_accessibility(nullptr)
183#endif
184{
185 Q_UNUSED(paramList);
186 m_androidPlatformNativeInterface = new QAndroidPlatformNativeInterface();
187
188#if QT_CONFIG(egl)
189 m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
190 if (Q_UNLIKELY(m_eglDisplay == EGL_NO_DISPLAY))
191 qFatal("Could not open egl display");
192
193 EGLint major, minor;
194 if (Q_UNLIKELY(!eglInitialize(m_eglDisplay, &major, &minor)))
195 qFatal("Could not initialize egl display");
196
197 if (Q_UNLIKELY(!eglBindAPI(EGL_OPENGL_ES_API)))
198 qFatal("Could not bind GL_ES API");
199#endif
200
201 using namespace QtJniTypes;
202 m_primaryDisplayId = Display::getStaticField<jint>("DEFAULT_DISPLAY");
203 const QJniObject nativeDisplaysList = QtDisplayManager::callStaticMethod<List>(
204 "getAvailableDisplays", QtAndroidPrivate::context());
205
206 const int numberOfAvailableDisplays = nativeDisplaysList.callMethod<jint>("size");
207 for (int i = 0; i < numberOfAvailableDisplays; ++i) {
208 const QJniObject display =
209 nativeDisplaysList.callObjectMethod<jobject, jint>("get", jint(i));
210 const int displayId = display.callMethod<jint>("getDisplayId");
211 const bool isPrimary = (m_primaryDisplayId == displayId);
212 auto screen = new QAndroidPlatformScreen(display);
213
214 if (isPrimary)
215 m_primaryScreen = screen;
216
217 QWindowSystemInterface::handleScreenAdded(screen, isPrimary);
218 m_screens[displayId] = screen;
219 }
220
221 if (numberOfAvailableDisplays == 0) {
222 // If no displays are found, add a dummy display
223 auto defaultScreen = new QAndroidPlatformScreen(QJniObject {});
224 m_primaryScreen = defaultScreen;
225 QWindowSystemInterface::handleScreenAdded(defaultScreen, true);
226 }
227
228 m_mainThread = QThread::currentThread();
229
230 m_androidFDB = new QAndroidPlatformFontDatabase();
231 m_androidPlatformServices.reset(new QAndroidPlatformServices);
232
233#ifndef QT_NO_CLIPBOARD
234 m_androidPlatformClipboard = new QAndroidPlatformClipboard();
235#endif
236
237 m_androidSystemLocale = new QAndroidSystemLocale;
238
239#if QT_CONFIG(accessibility)
240 m_accessibility = new QAndroidPlatformAccessibility();
241#endif // QT_CONFIG(accessibility)
242
243 QJniObject javaActivity = QtAndroidPrivate::activity();
244 if (!javaActivity.isValid())
245 javaActivity = QtAndroidPrivate::service();
246
247 if (javaActivity.isValid()) {
248 QJniObject resources = javaActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;");
249 QJniObject configuration = resources.callObjectMethod("getConfiguration", "()Landroid/content/res/Configuration;");
250
251 int touchScreen = configuration.getField<jint>("touchscreen");
252 if (touchScreen == QJniObject::getStaticField<jint>("android/content/res/Configuration", "TOUCHSCREEN_FINGER")
253 || touchScreen == QJniObject::getStaticField<jint>("android/content/res/Configuration", "TOUCHSCREEN_STYLUS"))
254 {
255 QJniObject pm = javaActivity.callObjectMethod("getPackageManager", "()Landroid/content/pm/PackageManager;");
256 Q_ASSERT(pm.isValid());
257 int maxTouchPoints = 1;
258 if (pm.callMethod<jboolean>("hasSystemFeature","(Ljava/lang/String;)Z",
259 QJniObject::getStaticObjectField("android/content/pm/PackageManager",
260 "FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND",
261 "Ljava/lang/String;").object())) {
262 maxTouchPoints = 10;
263 } else if (pm.callMethod<jboolean>("hasSystemFeature","(Ljava/lang/String;)Z",
264 QJniObject::getStaticObjectField("android/content/pm/PackageManager",
265 "FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT",
266 "Ljava/lang/String;").object())) {
267 maxTouchPoints = 4;
268 } else if (pm.callMethod<jboolean>("hasSystemFeature","(Ljava/lang/String;)Z",
269 QJniObject::getStaticObjectField("android/content/pm/PackageManager",
270 "FEATURE_TOUCHSCREEN_MULTITOUCH",
271 "Ljava/lang/String;").object())) {
272 maxTouchPoints = 2;
273 }
274
275 m_touchDevice = new QPointingDevice("Android touchscreen", 1,
276 QInputDevice::DeviceType::TouchScreen,
277 QPointingDevice::PointerType::Finger,
278 QPointingDevice::Capability::Position
279 | QPointingDevice::Capability::Area
280 | QPointingDevice::Capability::Pressure
281 | QPointingDevice::Capability::NormalizedPosition,
282 maxTouchPoints,
283 0);
284 QWindowSystemInterface::registerInputDevice(m_touchDevice);
285
286 QWindowSystemInterface::registerInputDevice(
287 new QInputDevice("Virtual keyboard"_L1, 0, QInputDevice::DeviceType::Keyboard,
288 {}, qApp));
289 }
290
291 auto contentResolver = javaActivity.callObjectMethod("getContentResolver", "()Landroid/content/ContentResolver;");
292 Q_ASSERT(contentResolver.isValid());
293 QJniObject txtShowPassValue = QJniObject::callStaticObjectMethod(
294 "android/provider/Settings$System",
295 "getString",
296 "(Landroid/content/ContentResolver;Ljava/lang/String;)Ljava/lang/String;",
297 contentResolver.object(),
298 QJniObject::getStaticObjectField("android/provider/Settings$System",
299 "TEXT_SHOW_PASSWORD",
300 "Ljava/lang/String;").object());
301 if (txtShowPassValue.isValid()) {
302 bool ok = false;
303 const int txtShowPass = txtShowPassValue.toString().toInt(&ok);
304 m_showPasswordEnabled = ok ? (txtShowPass == 1) : false;
305 }
306 }
307
308 // We can't safely notify the jni bridge that we're up and running just yet, so let's postpone
309 // it for now.
310 QCoreApplication::postEvent(m_androidPlatformNativeInterface, new QEvent(QEvent::User));
311}
312
314{
315 static bool needsWorkaround =
316 QtAndroid::deviceName().compare("samsung SM-T211"_L1, Qt::CaseInsensitive) == 0
317 || QtAndroid::deviceName().compare("samsung SM-T210"_L1, Qt::CaseInsensitive) == 0
318 || QtAndroid::deviceName().compare("samsung SM-T215"_L1, Qt::CaseInsensitive) == 0;
319 return needsWorkaround;
320}
321
323{
324 const auto icStrs = QPlatformInputContextFactory::requested();
325 if (icStrs.isEmpty())
326 m_inputContext.reset(new QAndroidInputContext);
327 else
328 m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
329}
330
332{
333 switch (cap) {
334 case ApplicationState: return true;
335 case ThreadedPixmaps: return true;
336 case NativeWidgets: return QtAndroidPrivate::activity().isValid();
337 case OpenGL:
338 return isValidAndroidContextForRendering();
339 case ForeignWindows:
340 return isValidAndroidContextForRendering();
341 case ThreadedOpenGL:
342 return !needsBasicRenderloopWorkaround() && isValidAndroidContextForRendering();
343 case TopStackedNativeChildWindows: return false;
344 case MaximizeUsingFullscreenGeometry: return true;
345 // FIXME QTBUG-118849 - we do not implement grabWindow() anymore, calling it will return
346 // a null QPixmap also for raster windows - for OpenGL windows this was always true
347 case ScreenWindowGrabbing: return false;
348 case OffscreenSurface: return QtAndroidPrivate::activity().isValid();
349 default:
350 return QPlatformIntegration::hasCapability(cap);
351 }
352}
353
355{
356 if (!QtAndroidPrivate::activity().isValid())
357 return nullptr;
358
359 return new QRhiBackingStore(window);
360}
361
362#if QT_CONFIG(egl)
363QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
364{
365 if (!isValidAndroidContextForRendering())
366 return nullptr;
367 QSurfaceFormat format(context->format());
368 format.setAlphaBufferSize(8);
369 format.setRedBufferSize(8);
370 format.setGreenBufferSize(8);
371 format.setBlueBufferSize(8);
372 auto ctx = new QAndroidPlatformOpenGLContext(format, context->shareHandle(), m_eglDisplay);
373 return ctx;
374}
375
376QOpenGLContext *QAndroidPlatformIntegration::createOpenGLContext(EGLContext context, EGLDisplay display, QOpenGLContext *shareContext) const
377{
378 return QEGLPlatformContext::createFrom<QAndroidPlatformOpenGLContext>(context, display, m_eglDisplay, shareContext);
379}
380
381QPlatformOffscreenSurface *QAndroidPlatformIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
382{
383 if (!QtAndroidPrivate::activity().isValid())
384 return nullptr;
385
386 QSurfaceFormat format(surface->requestedFormat());
387 format.setAlphaBufferSize(8);
388 format.setRedBufferSize(8);
389 format.setGreenBufferSize(8);
390 format.setBlueBufferSize(8);
391
392 return new QEGLPbuffer(m_eglDisplay, format, surface);
393}
394
395QOffscreenSurface *QAndroidPlatformIntegration::createOffscreenSurface(ANativeWindow *nativeSurface) const
396{
397 if (!QtAndroidPrivate::activity().isValid() || !nativeSurface)
398 return nullptr;
399
400 auto *surface = new QOffscreenSurface;
401 auto *surfacePrivate = QOffscreenSurfacePrivate::get(surface);
402 surfacePrivate->platformOffscreenSurface = new QAndroidPlatformOffscreenSurface(nativeSurface, m_eglDisplay, surface);
403 return surface;
404}
405#endif
406
408{
409 if (!isValidAndroidContextForRendering())
410 return nullptr;
411
412#if QT_CONFIG(vulkan)
413 if (window->surfaceType() == QSurface::VulkanSurface)
414 return new QAndroidPlatformVulkanWindow(window);
415#endif
416
417#if QT_CONFIG(egl)
418 return new QAndroidPlatformOpenGLWindow(window, m_eglDisplay);
419#endif
420
421 return nullptr;
422}
423
424QPlatformWindow *QAndroidPlatformIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const
425{
426 return new QAndroidPlatformForeignWindow(window, nativeHandle);
427}
428
433
435{
436#if QT_CONFIG(egl)
437 if (m_eglDisplay != EGL_NO_DISPLAY)
438 eglTerminate(m_eglDisplay);
439#endif
440
441 delete m_androidPlatformNativeInterface;
442 delete m_androidFDB;
443 delete m_androidSystemLocale;
444
445#ifndef QT_NO_CLIPBOARD
446 delete m_androidPlatformClipboard;
447#endif
448
450}
451
453{
454 return m_androidFDB;
455}
456
457#ifndef QT_NO_CLIPBOARD
459{
460 return m_androidPlatformClipboard;
461}
462#endif
463
465{
466 return m_inputContext.data();
467}
468
470{
471 return m_androidPlatformNativeInterface;
472}
473
475{
476 return m_androidPlatformServices.data();
477}
478
479QVariant QAndroidPlatformIntegration::styleHint(StyleHint hint) const
480{
481 switch (hint) {
482 case PasswordMaskDelay:
483 // this number is from a hard-coded value in Android code (cf. PasswordTransformationMethod)
484 return m_showPasswordEnabled ? 1500 : 0;
485 case ShowIsMaximized:
486 return true;
487 default:
488 return QPlatformIntegration::styleHint(hint);
489 }
490}
491
493{
494 // Don't maximize dialogs on Android
495 if (flags & Qt::Dialog & ~Qt::Window)
496 return Qt::WindowNoState;
497
498 return QPlatformIntegration::defaultWindowState(flags);
499}
500
501static const auto androidThemeName = "android"_L1;
503{
504 return QStringList(QString(androidThemeName));
505}
506
508{
509 if (androidThemeName == name)
510 return QAndroidPlatformTheme::instance(m_androidPlatformNativeInterface);
511
512 return 0;
513}
514
515void QAndroidPlatformIntegration::setScreenOrientation(Qt::ScreenOrientation currentOrientation,
516 Qt::ScreenOrientation nativeOrientation)
517{
518 m_orientation = currentOrientation;
519 m_nativeOrientation = nativeOrientation;
520}
521
523{
524 if (m_primaryScreen)
525 m_primaryScreen->setAvailableGeometry(m_primaryScreen->availableGeometry());
526}
527
528#if QT_CONFIG(accessibility)
529QPlatformAccessibility *QAndroidPlatformIntegration::accessibility() const
530{
531 return m_accessibility;
532}
533#endif
534
535extern "C" JNIEXPORT bool JNICALL
536Java_org_qtproject_qt_android_QtNativeAccessibility_accessibilitySupported(JNIEnv *, jobject)
537{
538 #if QT_CONFIG(accessibility)
539 return true;
540 #endif // QT_CONFIG(accessibility)
541
542 return false;
543}
544
545void QAndroidPlatformIntegration::setAvailableGeometry(const QRect &availableGeometry)
546{
547 if (m_primaryScreen)
548 QMetaObject::invokeMethod(m_primaryScreen, "setAvailableGeometry", Qt::AutoConnection, Q_ARG(QRect, availableGeometry));
549}
550
552{
553 if (m_primaryScreen)
554 QMetaObject::invokeMethod(m_primaryScreen, "setPhysicalSize", Qt::AutoConnection, Q_ARG(QSize, QSize(width, height)));
555}
556
557void QAndroidPlatformIntegration::setScreenSize(int width, int height)
558{
559 if (m_primaryScreen)
560 QMetaObject::invokeMethod(m_primaryScreen, "setSize", Qt::AutoConnection, Q_ARG(QSize, QSize(width, height)));
561}
562
563Qt::ColorScheme QAndroidPlatformIntegration::m_colorScheme = Qt::ColorScheme::Light;
564
565void QAndroidPlatformIntegration::updateColorScheme(Qt::ColorScheme colorScheme)
566{
567 if (m_colorScheme == colorScheme)
568 return;
569 m_colorScheme = colorScheme;
570
571 QMetaObject::invokeMethod(qGuiApp,
572 [] () { QAndroidPlatformTheme::instance()->updateColorScheme();});
573}
574
576{
577 if (m_primaryScreen)
578 QMetaObject::invokeMethod(m_primaryScreen, "setRefreshRate", Qt::AutoConnection,
579 Q_ARG(qreal, refreshRate));
580}
581
583{
584 auto result = m_screens.insert(displayId, nullptr);
585 if (result.first->second == nullptr) {
586 auto it = result.first;
587 it->second = createScreenForDisplayId(displayId);
588 if (it->second == nullptr)
589 return;
590 const bool isPrimary = (m_primaryDisplayId == displayId);
591 if (isPrimary)
592 m_primaryScreen = it->second;
593 QWindowSystemInterface::handleScreenAdded(it->second, isPrimary);
594 } else {
595 qWarning() << "Display with id" << displayId << "already exists.";
596 }
597}
598
600{
601 auto it = m_screens.find(displayId);
602 if (it == m_screens.end() || it->second == nullptr) {
603 handleScreenAdded(displayId);
604 }
605
606 if (QAndroidPlatformScreen *screen = it->second) {
607 QSize size = QAndroidPlatformScreen::sizeForDisplayId(displayId);
608 if (screen->geometry().size() != size) {
609 screen->setPhysicalSizeFromPixels(size);
610 screen->setSize(size);
611 }
612 }
613
614 // We do not do handle changes in rotation, refresh rate and density
615 // as they are done under QtDisplayManager.
616}
617
619{
620 auto it = m_screens.find(displayId);
621
622 if (it == m_screens.end())
623 return;
624
625 if (it->second != nullptr)
626 QWindowSystemInterface::handleScreenRemoved(it->second);
627
628 m_screens.erase(it);
629}
630
631#if QT_CONFIG(vulkan)
632
633QPlatformVulkanInstance *QAndroidPlatformIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const
634{
635 return new QAndroidPlatformVulkanInstance(instance);
636}
637
638#endif // QT_CONFIG(vulkan)
639
640QT_END_NAMESPACE
QPlatformFontDatabase * fontDatabase() const override
Accessor for the platform integration's fontdatabase.
QPlatformWindow * createForeignWindow(QWindow *window, WId nativeHandle) const override
void initialize() override
Performs initialization steps that depend on having an event dispatcher available.
QPlatformInputContext * inputContext() const override
Returns the platforms input context.
QStringList themeNames() const override
QPlatformNativeInterface * nativeInterface() const override
QPlatformTheme * createPlatformTheme(const QString &name) const override
QPlatformBackingStore * createPlatformBackingStore(QWindow *window) const override
Factory function for QPlatformBackingStore.
void setAvailableGeometry(const QRect &availableGeometry)
void setScreenSize(int width, int height)
void setPhysicalSize(int width, int height)
bool hasCapability(QPlatformIntegration::Capability cap) const override
QPlatformWindow * createPlatformWindow(QWindow *window) const override
Factory function for QPlatformWindow.
QPlatformClipboard * clipboard() const override
Accessor for the platform integration's clipboard.
Qt::WindowState defaultWindowState(Qt::WindowFlags flags) const override
QAndroidPlatformIntegration(const QStringList &paramList)
QAbstractEventDispatcher * createEventDispatcher() const override
Factory function for the GUI event dispatcher.
QVariant styleHint(StyleHint hint) const override
QPlatformServices * services() const override
void * nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) override
void * nativeResourceForWindow(const QByteArray &resource, QWindow *window) override
void * nativeResourceForIntegration(const QByteArray &resource) override
static QAndroidPlatformTheme * instance(QAndroidPlatformNativeInterface *androidPlatformNativeInterface=nullptr)
Combined button and popup list for selecting options.
void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration)
QBasicMutex * platformInterfaceMutex()
QString deviceName()
static const auto androidThemeName
static bool needsBasicRenderloopWorkaround()
Q_DECLARE_JNI_CLASS(MotionEvent, "android/view/MotionEvent")