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