9#if QT_CONFIG(accessibility)
10#include "androidjniaccessibility.h"
15#if QT_CONFIG(accessibility)
16#include "qandroidplatformaccessibility.h"
19#if QT_CONFIG(draganddrop)
20#include "qandroidplatformdrag.h"
26#include "qandroidplatformopenglcontext.h"
33#include <QGuiApplication>
34#include <QOffscreenSurface>
35#include <QOpenGLContext>
37#include <QtCore/QJniObject>
39#include <QtGui/private/qeglpbuffer_p.h>
41#include <QtGui/private/qguiapplication_p.h>
42#include <QtGui/private/qoffscreensurface_p.h>
43#include <QtGui/private/qrhibackingstore_p.h>
44#include <qpa/qplatformoffscreensurface.h>
45#include <qpa/qplatformwindow.h>
46#include <qpa/qwindowsysteminterface.h>
51#include "qandroidplatformvulkanwindow.h"
52#include "qandroidplatformvulkaninstance.h"
55#include <QtGui/qpa/qplatforminputcontextfactory_p.h>
59using namespace Qt::StringLiterals;
67Q_DECLARE_JNI_CLASS(Display,
"android/view/Display")
69Q_DECLARE_JNI_CLASS(List,
"java/util/List")
75 const QJniObject display = QtJniTypes::QtDisplayManager::callStaticMethod<QtJniTypes::Display>(
76 "getDisplay", QtAndroidPrivate::context(), displayId);
77 if (!display.isValid())
82static bool isValidAndroidContextForRendering()
84 return QtAndroid::isQtApplication() ? QtAndroidPrivate::activity().isValid()
85 : QtAndroidPrivate::context().isValid();
92 if (resource==
"JavaVM")
93 return QtAndroidPrivate::javaVM();
94 if (resource ==
"QtActivity") {
95 extern Q_CORE_EXPORT jobject qt_androidActivity();
96 return qt_androidActivity();
98 if (resource ==
"QtService") {
99 extern Q_CORE_EXPORT jobject qt_androidService();
100 return qt_androidService();
102 if (resource ==
"AndroidStyleData") {
103 if (m_androidStyle) {
104 if (m_androidStyle->m_styleData.isEmpty())
105 m_androidStyle->m_styleData = AndroidStyle::loadStyleData();
106 return &m_androidStyle->m_styleData;
111 if (resource ==
"AndroidStandardPalette") {
113 return &m_androidStyle->m_standardPalette;
117 if (resource ==
"AndroidQWidgetFonts") {
119 return &m_androidStyle->m_QWidgetsFonts;
123 if (resource ==
"AndroidDeviceName") {
124 static QString deviceName = QtAndroid::deviceName();
133 if (resource ==
"vkSurface") {
134 if (window->surfaceType() == QSurface::VulkanSurface) {
135 QAndroidPlatformVulkanWindow *w =
static_cast<QAndroidPlatformVulkanWindow *>(window->handle());
137 return w ? w->vkSurface() :
nullptr;
150 if (QEGLPlatformContext *platformContext =
static_cast<QEGLPlatformContext *>(context->handle())) {
151 if (resource ==
"eglcontext")
152 return platformContext->eglContext();
153 else if (resource ==
"eglconfig")
154 return platformContext->eglConfig();
155 else if (resource ==
"egldisplay")
156 return platformContext->eglDisplay();
167 if (event->type() != QEvent::User)
174#if QT_CONFIG(accessibility)
176 api->accessibility()->setActive(QtAndroidAccessibility::isActive());
184#if QT_CONFIG(accessibility)
192 m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
193 if (Q_UNLIKELY(m_eglDisplay == EGL_NO_DISPLAY))
194 qFatal(
"Could not open egl display");
197 if (Q_UNLIKELY(!eglInitialize(m_eglDisplay, &major, &minor)))
198 qFatal(
"Could not initialize egl display");
200 if (Q_UNLIKELY(!eglBindAPI(EGL_OPENGL_ES_API)))
201 qFatal(
"Could not bind GL_ES API");
204 using namespace QtJniTypes;
205 m_primaryDisplayId = Display::getStaticField<jint>(
"DEFAULT_DISPLAY");
206 const QJniObject nativeDisplaysList = QtDisplayManager::callStaticMethod<List>(
207 "getAvailableDisplays", QtAndroidPrivate::context());
209 const int numberOfAvailableDisplays = nativeDisplaysList.callMethod<jint>(
"size");
210 for (
int i = 0; i < numberOfAvailableDisplays; ++i) {
211 const QJniObject display =
212 nativeDisplaysList.callObjectMethod<jobject, jint>(
"get", jint(i));
213 const int displayId = display.callMethod<jint>(
"getDisplayId");
214 const bool isPrimary = (m_primaryDisplayId == displayId);
218 m_primaryScreen = screen;
220 QWindowSystemInterface::handleScreenAdded(screen, isPrimary);
221 m_screens[displayId] = screen;
224 if (numberOfAvailableDisplays == 0) {
226 auto defaultScreen =
new QAndroidPlatformScreen(QJniObject {});
227 m_primaryScreen = defaultScreen;
228 QWindowSystemInterface::handleScreenAdded(defaultScreen,
true);
231 m_mainThread = QThread::currentThread();
233 m_androidFDB =
new QAndroidPlatformFontDatabase();
234 m_androidPlatformServices.reset(
new QAndroidPlatformServices);
236#ifndef QT_NO_CLIPBOARD
237 m_androidPlatformClipboard =
new QAndroidPlatformClipboard();
240#if QT_CONFIG(draganddrop)
241 m_androidPlatformDrag =
new QAndroidPlatformDrag();
244#if QT_CONFIG(accessibility)
245 m_accessibility =
new QAndroidPlatformAccessibility();
248 QJniObject javaActivity = QtAndroidPrivate::activity();
249 if (!javaActivity.isValid())
250 javaActivity = QtAndroidPrivate::service();
252 if (javaActivity.isValid()) {
253 QJniObject resources = javaActivity.callObjectMethod(
"getResources",
"()Landroid/content/res/Resources;");
254 QJniObject configuration = resources.callObjectMethod(
"getConfiguration",
"()Landroid/content/res/Configuration;");
256 int touchScreen = configuration.getField<jint>(
"touchscreen");
257 if (touchScreen == QJniObject::getStaticField<jint>(
"android/content/res/Configuration",
"TOUCHSCREEN_FINGER")
258 || touchScreen == QJniObject::getStaticField<jint>(
"android/content/res/Configuration",
"TOUCHSCREEN_STYLUS"))
260 QJniObject pm = javaActivity.callObjectMethod(
"getPackageManager",
"()Landroid/content/pm/PackageManager;");
261 Q_ASSERT(pm.isValid());
262 int maxTouchPoints = 1;
263 if (pm.callMethod<jboolean>(
"hasSystemFeature",
"(Ljava/lang/String;)Z",
264 QJniObject::getStaticObjectField(
"android/content/pm/PackageManager",
265 "FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND",
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_DISTINCT",
271 "Ljava/lang/String;").object())) {
273 }
else if (pm.callMethod<jboolean>(
"hasSystemFeature",
"(Ljava/lang/String;)Z",
274 QJniObject::getStaticObjectField(
"android/content/pm/PackageManager",
275 "FEATURE_TOUCHSCREEN_MULTITOUCH",
276 "Ljava/lang/String;").object())) {
280 m_touchDevice =
new QPointingDevice(
"Android touchscreen", 1,
281 QInputDevice::DeviceType::TouchScreen,
282 QPointingDevice::PointerType::Finger,
283 QPointingDevice::Capability::Position
284 | QPointingDevice::Capability::Area
285 | QPointingDevice::Capability::Pressure,
288 QWindowSystemInterface::registerInputDevice(m_touchDevice);
290 QWindowSystemInterface::registerInputDevice(
291 new QInputDevice(
"Virtual keyboard"_L1, 0, QInputDevice::DeviceType::Keyboard,
295 auto contentResolver = javaActivity.callObjectMethod(
"getContentResolver",
"()Landroid/content/ContentResolver;");
296 Q_ASSERT(contentResolver.isValid());
297 QJniObject txtShowPassValue = QJniObject::callStaticObjectMethod(
298 "android/provider/Settings$System",
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()) {
307 const int txtShowPass = txtShowPassValue.toString().toInt(&ok);
308 m_showPasswordEnabled = ok ? (txtShowPass == 1) :
false;
314 QCoreApplication::postEvent(m_androidPlatformNativeInterface,
new QEvent(QEvent::User));
319 static bool needsWorkaround =
323 return needsWorkaround;
328 const auto icStrs = QPlatformInputContextFactory::requested();
329 if (icStrs.isEmpty())
330 m_inputContext.reset(
new QAndroidInputContext);
332 m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
338 case ApplicationState:
return true;
339 case ThreadedPixmaps:
return true;
340 case NativeWidgets:
return QtAndroidPrivate::activity().isValid();
342 return isValidAndroidContextForRendering();
344 return isValidAndroidContextForRendering();
347 case TopStackedNativeChildWindows:
return false;
348 case ChildWindows:
return true;
349 case MaximizeUsingFullscreenGeometry:
return true;
352 case ScreenWindowGrabbing:
return false;
353 case OffscreenSurface:
return QtAndroidPrivate::activity().isValid();
355 return QPlatformIntegration::hasCapability(cap);
361 if (!QtAndroidPrivate::activity().isValid())
364 return new QRhiBackingStore(window);
368static void fillUnsetColorBufferSizes(QSurfaceFormat &format)
370 if (format.redBufferSize() < 0) format.setRedBufferSize(8);
371 if (format.greenBufferSize() < 0) format.setGreenBufferSize(8);
372 if (format.blueBufferSize() < 0) format.setBlueBufferSize(8);
373 if (format.alphaBufferSize() < 0) format.setAlphaBufferSize(8);
376QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context)
const
378 if (!isValidAndroidContextForRendering())
380 QSurfaceFormat format(context->format());
381 fillUnsetColorBufferSizes(format);
382 auto ctx =
new QAndroidPlatformOpenGLContext(format, context->shareHandle(), m_eglDisplay);
386QOpenGLContext *QAndroidPlatformIntegration::createOpenGLContext(EGLContext context, EGLDisplay display, QOpenGLContext *shareContext)
const
388 return QEGLPlatformContext::createFrom<QAndroidPlatformOpenGLContext>(context, display, m_eglDisplay, shareContext);
391QPlatformOffscreenSurface *QAndroidPlatformIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface)
const
393 if (!QtAndroidPrivate::activity().isValid())
396 QSurfaceFormat format(surface->requestedFormat());
397 fillUnsetColorBufferSizes(format);
399 return new QEGLPbuffer(m_eglDisplay, format, surface);
402QOffscreenSurface *QAndroidPlatformIntegration::createOffscreenSurface(ANativeWindow *nativeSurface)
const
404 if (!QtAndroidPrivate::activity().isValid() || !nativeSurface)
407 auto *surface =
new QOffscreenSurface;
408 auto *surfacePrivate = QOffscreenSurfacePrivate::get(surface);
409 surfacePrivate->platformOffscreenSurface =
new QAndroidPlatformOffscreenSurface(nativeSurface, m_eglDisplay, surface);
416 if (!isValidAndroidContextForRendering())
420 if (window->surfaceType() == QSurface::VulkanSurface)
421 return new QAndroidPlatformVulkanWindow(window);
425 return new QAndroidPlatformOpenGLWindow(window, m_eglDisplay);
433 return new QAndroidPlatformForeignWindow(window, nativeHandle);
444 if (m_eglDisplay != EGL_NO_DISPLAY)
445 eglTerminate(m_eglDisplay);
448 delete m_androidPlatformNativeInterface;
451#ifndef QT_NO_CLIPBOARD
452 delete m_androidPlatformClipboard;
455#if QT_CONFIG(draganddrop)
456 delete m_androidPlatformDrag;
467#ifndef QT_NO_CLIPBOARD
470 return m_androidPlatformClipboard;
474#if QT_CONFIG(draganddrop)
475QPlatformDrag *QAndroidPlatformIntegration::drag()
const
477 return m_androidPlatformDrag;
483 return m_inputContext.data();
488 return m_androidPlatformNativeInterface;
493 return m_androidPlatformServices.data();
499 case PasswordMaskDelay:
501 return m_showPasswordEnabled ? 1500 : 0;
502 case ShowIsMaximized:
505 return QPlatformIntegration::styleHint(hint);
512 if (flags & Qt::Dialog & ~Qt::Window)
513 return Qt::WindowNoState;
515 return QPlatformIntegration::defaultWindowState(flags);
521 return QStringList(QString(androidThemeName));
533 Qt::ScreenOrientation nativeOrientation)
535 m_orientation = currentOrientation;
536 m_nativeOrientation = nativeOrientation;
541 if (!m_primaryScreen)
546 const QRect availableDefault = QAndroidPlatformScreen::defaultAvailableGeometry();
547 m_primaryScreen->setAvailableGeometry(availableDefault.isNull() ?
548 m_primaryScreen->availableGeometry() : availableDefault);
551#if QT_CONFIG(accessibility)
552QPlatformAccessibility *QAndroidPlatformIntegration::accessibility()
const
554 return m_accessibility;
558extern "C" JNIEXPORT
bool JNICALL
559Java_org_qtproject_qt_android_QtNativeAccessibility_accessibilitySupported(JNIEnv *, jobject)
561 #if QT_CONFIG(accessibility)
571 QMetaObject::invokeMethod(m_primaryScreen,
"setAvailableGeometry", Qt::AutoConnection, Q_ARG(QRect, availableGeometry));
577 QMetaObject::invokeMethod(m_primaryScreen,
"setPhysicalSize", Qt::AutoConnection, Q_ARG(QSize, QSize(width, height)));
583 QMetaObject::invokeMethod(m_primaryScreen,
"setSize", Qt::AutoConnection, Q_ARG(QSize, QSize(width, height)));
590 if (m_colorScheme == colorScheme)
592 m_colorScheme = colorScheme;
594 QMetaObject::invokeMethod(qGuiApp,
595 [] () { QAndroidPlatformTheme::instance()->updateColorScheme();});
601 QMetaObject::invokeMethod(m_primaryScreen,
"setRefreshRate", Qt::AutoConnection,
602 Q_ARG(qreal, refreshRate));
607 auto result = m_screens.insert(displayId,
nullptr);
608 if (result.first->second ==
nullptr) {
609 auto it = result.first;
610 it->second = createScreenForDisplayId(displayId);
611 if (it->second ==
nullptr)
613 const bool isPrimary = (m_primaryDisplayId == displayId);
615 m_primaryScreen = it->second;
616 QWindowSystemInterface::handleScreenAdded(it->second, isPrimary);
618 qWarning() <<
"Display with id" << displayId <<
"already exists.";
624 auto it = m_screens.find(displayId);
625 if (it == m_screens.end() || it->second ==
nullptr) {
630 QSize size = QAndroidPlatformScreen::sizeForDisplayId(displayId);
631 if (screen->geometry().size() != size) {
632 screen->setSize(size);
642 auto it = m_screens.find(displayId);
644 if (it == m_screens.end())
647 if (it->second !=
nullptr)
648 QWindowSystemInterface::handleScreenRemoved(it->second);
655QPlatformVulkanInstance *QAndroidPlatformIntegration::createPlatformVulkanInstance(QVulkanInstance *instance)
const
657 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")