7#if QT_CONFIG(accessibility)
8#include "androidjniaccessibility.h"
13#if QT_CONFIG(accessibility)
14#include "qandroidplatformaccessibility.h"
21#include "qandroidplatformopenglcontext.h"
29#include <QGuiApplication>
30#include <QOffscreenSurface>
31#include <QOpenGLContext>
33#include <QtCore/QJniObject>
35#include <QtGui/private/qeglpbuffer_p.h>
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>
47#include "qandroidplatformvulkanwindow.h"
48#include "qandroidplatformvulkaninstance.h"
51#include <QtGui/qpa/qplatforminputcontextfactory_p.h>
55using namespace Qt::StringLiterals;
63Q_DECLARE_JNI_CLASS(Display,
"android/view/Display")
65Q_DECLARE_JNI_CLASS(List,
"java/util/List")
71 const QJniObject display = QtJniTypes::QtDisplayManager::callStaticMethod<QtJniTypes::Display>(
72 "getDisplay", QtAndroidPrivate::context(), displayId);
73 if (!display.isValid())
78static bool isValidAndroidContextForRendering()
80 return QtAndroid::isQtApplication() ? QtAndroidPrivate::activity().isValid()
81 : QtAndroidPrivate::context().isValid();
88 if (resource==
"JavaVM")
89 return QtAndroidPrivate::javaVM();
90 if (resource ==
"QtActivity") {
91 extern Q_CORE_EXPORT jobject qt_androidActivity();
92 return qt_androidActivity();
94 if (resource ==
"QtService") {
95 extern Q_CORE_EXPORT jobject qt_androidService();
96 return qt_androidService();
98 if (resource ==
"AndroidStyleData") {
100 if (m_androidStyle->m_styleData.isEmpty())
101 m_androidStyle->m_styleData = AndroidStyle::loadStyleData();
102 return &m_androidStyle->m_styleData;
107 if (resource ==
"AndroidStandardPalette") {
109 return &m_androidStyle->m_standardPalette;
113 if (resource ==
"AndroidQWidgetFonts") {
115 return &m_androidStyle->m_QWidgetsFonts;
119 if (resource ==
"AndroidDeviceName") {
120 static QString deviceName = QtAndroid::deviceName();
129 if (resource ==
"vkSurface") {
130 if (window->surfaceType() == QSurface::VulkanSurface) {
131 QAndroidPlatformVulkanWindow *w =
static_cast<QAndroidPlatformVulkanWindow *>(window->handle());
133 return w ? w->vkSurface() :
nullptr;
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();
163 if (event->type() != QEvent::User)
170#if QT_CONFIG(accessibility)
172 api->accessibility()->setActive(QtAndroidAccessibility::isActive());
180#if QT_CONFIG(accessibility)
188 m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
189 if (Q_UNLIKELY(m_eglDisplay == EGL_NO_DISPLAY))
190 qFatal(
"Could not open egl display");
193 if (Q_UNLIKELY(!eglInitialize(m_eglDisplay, &major, &minor)))
194 qFatal(
"Could not initialize egl display");
196 if (Q_UNLIKELY(!eglBindAPI(EGL_OPENGL_ES_API)))
197 qFatal(
"Could not bind GL_ES API");
200 using namespace QtJniTypes;
201 m_primaryDisplayId = Display::getStaticField<jint>(
"DEFAULT_DISPLAY");
202 const QJniObject nativeDisplaysList = QtDisplayManager::callStaticMethod<List>(
203 "getAvailableDisplays", QtAndroidPrivate::context());
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);
214 m_primaryScreen = screen;
216 QWindowSystemInterface::handleScreenAdded(screen, isPrimary);
217 m_screens[displayId] = screen;
220 if (numberOfAvailableDisplays == 0) {
222 auto defaultScreen =
new QAndroidPlatformScreen(QJniObject {});
223 m_primaryScreen = defaultScreen;
224 QWindowSystemInterface::handleScreenAdded(defaultScreen,
true);
227 m_mainThread = QThread::currentThread();
229 m_androidFDB =
new QAndroidPlatformFontDatabase();
230 m_androidPlatformServices.reset(
new QAndroidPlatformServices);
232#ifndef QT_NO_CLIPBOARD
233 m_androidPlatformClipboard =
new QAndroidPlatformClipboard();
238#if QT_CONFIG(accessibility)
239 m_accessibility =
new QAndroidPlatformAccessibility();
242 QJniObject javaActivity = QtAndroidPrivate::activity();
243 if (!javaActivity.isValid())
244 javaActivity = QtAndroidPrivate::service();
246 if (javaActivity.isValid()) {
247 QJniObject resources = javaActivity.callObjectMethod(
"getResources",
"()Landroid/content/res/Resources;");
248 QJniObject configuration = resources.callObjectMethod(
"getConfiguration",
"()Landroid/content/res/Configuration;");
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"))
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())) {
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())) {
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())) {
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,
283 QWindowSystemInterface::registerInputDevice(m_touchDevice);
285 QWindowSystemInterface::registerInputDevice(
286 new QInputDevice(
"Virtual keyboard"_L1, 0, QInputDevice::DeviceType::Keyboard,
290 auto contentResolver = javaActivity.callObjectMethod(
"getContentResolver",
"()Landroid/content/ContentResolver;");
291 Q_ASSERT(contentResolver.isValid());
292 QJniObject txtShowPassValue = QJniObject::callStaticObjectMethod(
293 "android/provider/Settings$System",
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()) {
302 const int txtShowPass = txtShowPassValue.toString().toInt(&ok);
303 m_showPasswordEnabled = ok ? (txtShowPass == 1) :
false;
309 QCoreApplication::postEvent(m_androidPlatformNativeInterface,
new QEvent(QEvent::User));
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;
323 const auto icStrs = QPlatformInputContextFactory::requested();
324 if (icStrs.isEmpty())
325 m_inputContext.reset(
new QAndroidInputContext);
327 m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
333 case ApplicationState:
return true;
334 case ThreadedPixmaps:
return true;
335 case NativeWidgets:
return QtAndroidPrivate::activity().isValid();
337 return isValidAndroidContextForRendering();
339 return isValidAndroidContextForRendering();
342 case TopStackedNativeChildWindows:
return false;
343 case MaximizeUsingFullscreenGeometry:
return true;
346 case ScreenWindowGrabbing:
return false;
348 return QPlatformIntegration::hasCapability(cap);
354 if (!QtAndroidPrivate::activity().isValid())
357 return new QRhiBackingStore(window);
361QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context)
const
363 if (!isValidAndroidContextForRendering())
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);
374QOpenGLContext *QAndroidPlatformIntegration::createOpenGLContext(EGLContext context, EGLDisplay display, QOpenGLContext *shareContext)
const
376 return QEGLPlatformContext::createFrom<QAndroidPlatformOpenGLContext>(context, display, m_eglDisplay, shareContext);
379QPlatformOffscreenSurface *QAndroidPlatformIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface)
const
381 if (!QtAndroidPrivate::activity().isValid())
384 QSurfaceFormat format(surface->requestedFormat());
385 format.setAlphaBufferSize(8);
386 format.setRedBufferSize(8);
387 format.setGreenBufferSize(8);
388 format.setBlueBufferSize(8);
390 return new QEGLPbuffer(m_eglDisplay, format, surface);
393QOffscreenSurface *QAndroidPlatformIntegration::createOffscreenSurface(ANativeWindow *nativeSurface)
const
395 if (!QtAndroidPrivate::activity().isValid() || !nativeSurface)
398 auto *surface =
new QOffscreenSurface;
399 auto *surfacePrivate = QOffscreenSurfacePrivate::get(surface);
400 surfacePrivate->platformOffscreenSurface =
new QAndroidPlatformOffscreenSurface(nativeSurface, m_eglDisplay, surface);
407 if (!isValidAndroidContextForRendering())
411 if (window->surfaceType() == QSurface::VulkanSurface)
412 return new QAndroidPlatformVulkanWindow(window);
416 return new QAndroidPlatformOpenGLWindow(window, m_eglDisplay);
424 return new QAndroidPlatformForeignWindow(window, nativeHandle);
435 if (m_eglDisplay != EGL_NO_DISPLAY)
436 eglTerminate(m_eglDisplay);
439 delete m_androidPlatformNativeInterface;
441 delete m_androidSystemLocale;
443#ifndef QT_NO_CLIPBOARD
444 delete m_androidPlatformClipboard;
447 QtAndroid::setAndroidPlatformIntegration(NULL);
455#ifndef QT_NO_CLIPBOARD
458 return m_androidPlatformClipboard;
464 return m_inputContext.data();
469 return m_androidPlatformNativeInterface;
474 return m_androidPlatformServices.data();
480 case PasswordMaskDelay:
482 return m_showPasswordEnabled ? 1500 : 0;
483 case ShowIsMaximized:
486 return QPlatformIntegration::styleHint(hint);
493 if (flags & Qt::Dialog & ~Qt::Window)
494 return Qt::WindowNoState;
496 return QPlatformIntegration::defaultWindowState(flags);
502 return QStringList(QString(androidThemeName));
514 Qt::ScreenOrientation nativeOrientation)
516 m_orientation = currentOrientation;
517 m_nativeOrientation = nativeOrientation;
523 m_primaryScreen->setAvailableGeometry(m_primaryScreen->availableGeometry());
526#if QT_CONFIG(accessibility)
527QPlatformAccessibility *QAndroidPlatformIntegration::accessibility()
const
529 return m_accessibility;
533extern "C" JNIEXPORT
bool JNICALL
534Java_org_qtproject_qt_android_QtNativeAccessibility_accessibilitySupported(JNIEnv *, jobject)
536 #if QT_CONFIG(accessibility)
546 QMetaObject::invokeMethod(m_primaryScreen,
"setAvailableGeometry", Qt::AutoConnection, Q_ARG(QRect, availableGeometry));
552 QMetaObject::invokeMethod(m_primaryScreen,
"setPhysicalSize", Qt::AutoConnection, Q_ARG(QSize, QSize(width, height)));
558 QMetaObject::invokeMethod(m_primaryScreen,
"setSize", Qt::AutoConnection, Q_ARG(QSize, QSize(width, height)));
565 if (m_colorScheme == colorScheme)
567 m_colorScheme = colorScheme;
569 QMetaObject::invokeMethod(qGuiApp,
570 [] () { QAndroidPlatformTheme::instance()->updateColorScheme();});
576 QMetaObject::invokeMethod(m_primaryScreen,
"setRefreshRate", Qt::AutoConnection,
577 Q_ARG(qreal, refreshRate));
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)
588 const bool isPrimary = (m_primaryDisplayId == displayId);
590 m_primaryScreen = it->second;
591 QWindowSystemInterface::handleScreenAdded(it->second, isPrimary);
593 qWarning() <<
"Display with id" << displayId <<
"already exists.";
599 auto it = m_screens.find(displayId);
600 if (it == m_screens.end() || it->second ==
nullptr) {
605 QSize size = QAndroidPlatformScreen::sizeForDisplayId(displayId);
606 if (screen->geometry().size() != size) {
607 screen->setPhysicalSizeFromPixels(size);
608 screen->setSize(size);
618 auto it = m_screens.find(displayId);
620 if (it == m_screens.end())
623 if (it->second !=
nullptr)
624 QWindowSystemInterface::handleScreenRemoved(it->second);
631QPlatformVulkanInstance *QAndroidPlatformIntegration::createPlatformVulkanInstance(QVulkanInstance *instance)
const
633 return new QAndroidPlatformVulkanInstance(instance);
void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration)
QBasicMutex * platformInterfaceMutex()
Q_DECLARE_JNI_CLASS(MotionEvent, "android/view/MotionEvent")