8#if QT_CONFIG(accessibility)
9#include "androidjniaccessibility.h"
14#if QT_CONFIG(accessibility)
15#include "qandroidplatformaccessibility.h"
22#include "qandroidplatformopenglcontext.h"
30#include <QGuiApplication>
31#include <QOffscreenSurface>
32#include <QOpenGLContext>
34#include <QtCore/QJniObject>
36#include <QtGui/private/qeglpbuffer_p.h>
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>
48#include "qandroidplatformvulkanwindow.h"
49#include "qandroidplatformvulkaninstance.h"
52#include <QtGui/qpa/qplatforminputcontextfactory_p.h>
56using namespace Qt::StringLiterals;
64Q_DECLARE_JNI_CLASS(Display,
"android/view/Display")
66Q_DECLARE_JNI_CLASS(List,
"java/util/List")
72 const QJniObject display = QtJniTypes::QtDisplayManager::callStaticMethod<QtJniTypes::Display>(
73 "getDisplay", QtAndroidPrivate::context(), displayId);
74 if (!display.isValid())
79static bool isValidAndroidContextForRendering()
81 return QtAndroid::isQtApplication() ? QtAndroidPrivate::activity().isValid()
82 : QtAndroidPrivate::context().isValid();
89 if (resource==
"JavaVM")
90 return QtAndroidPrivate::javaVM();
91 if (resource ==
"QtActivity") {
92 extern Q_CORE_EXPORT jobject qt_androidActivity();
93 return qt_androidActivity();
95 if (resource ==
"QtService") {
96 extern Q_CORE_EXPORT jobject qt_androidService();
97 return qt_androidService();
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;
108 if (resource ==
"AndroidStandardPalette") {
110 return &m_androidStyle->m_standardPalette;
114 if (resource ==
"AndroidQWidgetFonts") {
116 return &m_androidStyle->m_QWidgetsFonts;
120 if (resource ==
"AndroidDeviceName") {
121 static QString deviceName = QtAndroid::deviceName();
130 if (resource ==
"vkSurface") {
131 if (window->surfaceType() == QSurface::VulkanSurface) {
132 QAndroidPlatformVulkanWindow *w =
static_cast<QAndroidPlatformVulkanWindow *>(window->handle());
134 return w ? w->vkSurface() :
nullptr;
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();
164 if (event->type() != QEvent::User)
171#if QT_CONFIG(accessibility)
173 api->accessibility()->setActive(QtAndroidAccessibility::isActive());
181#if QT_CONFIG(accessibility)
189 m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
190 if (Q_UNLIKELY(m_eglDisplay == EGL_NO_DISPLAY))
191 qFatal(
"Could not open egl display");
194 if (Q_UNLIKELY(!eglInitialize(m_eglDisplay, &major, &minor)))
195 qFatal(
"Could not initialize egl display");
197 if (Q_UNLIKELY(!eglBindAPI(EGL_OPENGL_ES_API)))
198 qFatal(
"Could not bind GL_ES API");
201 using namespace QtJniTypes;
202 m_primaryDisplayId = Display::getStaticField<jint>(
"DEFAULT_DISPLAY");
203 const QJniObject nativeDisplaysList = QtDisplayManager::callStaticMethod<List>(
204 "getAvailableDisplays", QtAndroidPrivate::context());
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);
215 m_primaryScreen = screen;
217 QWindowSystemInterface::handleScreenAdded(screen, isPrimary);
218 m_screens[displayId] = screen;
221 if (numberOfAvailableDisplays == 0) {
223 auto defaultScreen =
new QAndroidPlatformScreen(QJniObject {});
224 m_primaryScreen = defaultScreen;
225 QWindowSystemInterface::handleScreenAdded(defaultScreen,
true);
228 m_mainThread = QThread::currentThread();
230 m_androidFDB =
new QAndroidPlatformFontDatabase();
231 m_androidPlatformServices.reset(
new QAndroidPlatformServices);
233#ifndef QT_NO_CLIPBOARD
234 m_androidPlatformClipboard =
new QAndroidPlatformClipboard();
239#if QT_CONFIG(accessibility)
240 m_accessibility =
new QAndroidPlatformAccessibility();
243 QJniObject javaActivity = QtAndroidPrivate::activity();
244 if (!javaActivity.isValid())
245 javaActivity = QtAndroidPrivate::service();
247 if (javaActivity.isValid()) {
248 QJniObject resources = javaActivity.callObjectMethod(
"getResources",
"()Landroid/content/res/Resources;");
249 QJniObject configuration = resources.callObjectMethod(
"getConfiguration",
"()Landroid/content/res/Configuration;");
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"))
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())) {
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())) {
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())) {
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,
284 QWindowSystemInterface::registerInputDevice(m_touchDevice);
286 QWindowSystemInterface::registerInputDevice(
287 new QInputDevice(
"Virtual keyboard"_L1, 0, QInputDevice::DeviceType::Keyboard,
291 auto contentResolver = javaActivity.callObjectMethod(
"getContentResolver",
"()Landroid/content/ContentResolver;");
292 Q_ASSERT(contentResolver.isValid());
293 QJniObject txtShowPassValue = QJniObject::callStaticObjectMethod(
294 "android/provider/Settings$System",
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()) {
303 const int txtShowPass = txtShowPassValue.toString().toInt(&ok);
304 m_showPasswordEnabled = ok ? (txtShowPass == 1) :
false;
310 QCoreApplication::postEvent(m_androidPlatformNativeInterface,
new QEvent(QEvent::User));
315 static bool needsWorkaround =
319 return needsWorkaround;
324 const auto icStrs = QPlatformInputContextFactory::requested();
325 if (icStrs.isEmpty())
326 m_inputContext.reset(
new QAndroidInputContext);
328 m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
334 case ApplicationState:
return true;
335 case ThreadedPixmaps:
return true;
336 case NativeWidgets:
return QtAndroidPrivate::activity().isValid();
338 return isValidAndroidContextForRendering();
340 return isValidAndroidContextForRendering();
343 case TopStackedNativeChildWindows:
return false;
344 case MaximizeUsingFullscreenGeometry:
return true;
347 case ScreenWindowGrabbing:
return false;
348 case OffscreenSurface:
return QtAndroidPrivate::activity().isValid();
350 return QPlatformIntegration::hasCapability(cap);
356 if (!QtAndroidPrivate::activity().isValid())
359 return new QRhiBackingStore(window);
363QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context)
const
365 if (!isValidAndroidContextForRendering())
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);
376QOpenGLContext *QAndroidPlatformIntegration::createOpenGLContext(EGLContext context, EGLDisplay display, QOpenGLContext *shareContext)
const
378 return QEGLPlatformContext::createFrom<QAndroidPlatformOpenGLContext>(context, display, m_eglDisplay, shareContext);
381QPlatformOffscreenSurface *QAndroidPlatformIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface)
const
383 if (!QtAndroidPrivate::activity().isValid())
386 QSurfaceFormat format(surface->requestedFormat());
387 format.setAlphaBufferSize(8);
388 format.setRedBufferSize(8);
389 format.setGreenBufferSize(8);
390 format.setBlueBufferSize(8);
392 return new QEGLPbuffer(m_eglDisplay, format, surface);
395QOffscreenSurface *QAndroidPlatformIntegration::createOffscreenSurface(ANativeWindow *nativeSurface)
const
397 if (!QtAndroidPrivate::activity().isValid() || !nativeSurface)
400 auto *surface =
new QOffscreenSurface;
401 auto *surfacePrivate = QOffscreenSurfacePrivate::get(surface);
402 surfacePrivate->platformOffscreenSurface =
new QAndroidPlatformOffscreenSurface(nativeSurface, m_eglDisplay, surface);
409 if (!isValidAndroidContextForRendering())
413 if (window->surfaceType() == QSurface::VulkanSurface)
414 return new QAndroidPlatformVulkanWindow(window);
418 return new QAndroidPlatformOpenGLWindow(window, m_eglDisplay);
426 return new QAndroidPlatformForeignWindow(window, nativeHandle);
437 if (m_eglDisplay != EGL_NO_DISPLAY)
438 eglTerminate(m_eglDisplay);
441 delete m_androidPlatformNativeInterface;
443 delete m_androidSystemLocale;
445#ifndef QT_NO_CLIPBOARD
446 delete m_androidPlatformClipboard;
457#ifndef QT_NO_CLIPBOARD
460 return m_androidPlatformClipboard;
466 return m_inputContext.data();
471 return m_androidPlatformNativeInterface;
476 return m_androidPlatformServices.data();
482 case PasswordMaskDelay:
484 return m_showPasswordEnabled ? 1500 : 0;
485 case ShowIsMaximized:
488 return QPlatformIntegration::styleHint(hint);
495 if (flags & Qt::Dialog & ~Qt::Window)
496 return Qt::WindowNoState;
498 return QPlatformIntegration::defaultWindowState(flags);
504 return QStringList(QString(androidThemeName));
516 Qt::ScreenOrientation nativeOrientation)
518 m_orientation = currentOrientation;
519 m_nativeOrientation = nativeOrientation;
525 m_primaryScreen->setAvailableGeometry(m_primaryScreen->availableGeometry());
528#if QT_CONFIG(accessibility)
529QPlatformAccessibility *QAndroidPlatformIntegration::accessibility()
const
531 return m_accessibility;
535extern "C" JNIEXPORT
bool JNICALL
536Java_org_qtproject_qt_android_QtNativeAccessibility_accessibilitySupported(JNIEnv *, jobject)
538 #if QT_CONFIG(accessibility)
548 QMetaObject::invokeMethod(m_primaryScreen,
"setAvailableGeometry", Qt::AutoConnection, Q_ARG(QRect, availableGeometry));
554 QMetaObject::invokeMethod(m_primaryScreen,
"setPhysicalSize", Qt::AutoConnection, Q_ARG(QSize, QSize(width, height)));
560 QMetaObject::invokeMethod(m_primaryScreen,
"setSize", Qt::AutoConnection, Q_ARG(QSize, QSize(width, height)));
567 if (m_colorScheme == colorScheme)
569 m_colorScheme = colorScheme;
571 QMetaObject::invokeMethod(qGuiApp,
572 [] () { QAndroidPlatformTheme::instance()->updateColorScheme();});
578 QMetaObject::invokeMethod(m_primaryScreen,
"setRefreshRate", Qt::AutoConnection,
579 Q_ARG(qreal, refreshRate));
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)
590 const bool isPrimary = (m_primaryDisplayId == displayId);
592 m_primaryScreen = it->second;
593 QWindowSystemInterface::handleScreenAdded(it->second, isPrimary);
595 qWarning() <<
"Display with id" << displayId <<
"already exists.";
601 auto it = m_screens.find(displayId);
602 if (it == m_screens.end() || it->second ==
nullptr) {
607 QSize size = QAndroidPlatformScreen::sizeForDisplayId(displayId);
608 if (screen->geometry().size() != size) {
609 screen->setPhysicalSizeFromPixels(size);
610 screen->setSize(size);
620 auto it = m_screens.find(displayId);
622 if (it == m_screens.end())
625 if (it->second !=
nullptr)
626 QWindowSystemInterface::handleScreenRemoved(it->second);
633QPlatformVulkanInstance *QAndroidPlatformIntegration::createPlatformVulkanInstance(QVulkanInstance *instance)
const
635 return new QAndroidPlatformVulkanInstance(instance);
Combined button and popup list for selecting options.
void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration)
QBasicMutex * platformInterfaceMutex()
Q_DECLARE_JNI_CLASS(MotionEvent, "android/view/MotionEvent")