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