Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
androidjnimain.cpp
Go to the documentation of this file.
1// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
2// Copyright (C) 2022 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
5#include <dlfcn.h>
6#include <pthread.h>
7#include <qplugin.h>
8#include <semaphore.h>
9
13#include "androidjniinput.h"
14#include "androidjnimain.h"
15#include "androidjnimenu.h"
23
24#include <android/api-level.h>
25#include <android/asset_manager_jni.h>
26#include <android/bitmap.h>
27
28#include <QtCore/private/qjnihelpers_p.h>
29#include <QtCore/qbasicatomic.h>
30#include <QtCore/qjnienvironment.h>
31#include <QtCore/qjniobject.h>
32#include <QtCore/qprocess.h>
33#include <QtCore/qresource.h>
34#include <QtCore/qscopeguard.h>
35#include <QtCore/qthread.h>
36#include <QtGui/private/qguiapplication_p.h>
37#include <QtGui/private/qhighdpiscaling_p.h>
38
39#include <qpa/qwindowsysteminterface.h>
40
41
42using namespace Qt::StringLiterals;
43
45
46static JavaVM *m_javaVM = nullptr;
47static jclass m_applicationClass = nullptr;
48static jobject m_classLoaderObject = nullptr;
49static jmethodID m_loadClassMethodID = nullptr;
50static AAssetManager *m_assetManager = nullptr;
51static jobject m_assets = nullptr;
52static jobject m_resourcesObj = nullptr;
53
54static jclass m_qtActivityClass = nullptr;
55static jclass m_qtServiceClass = nullptr;
56
59
60static jclass m_bitmapClass = nullptr;
61static jmethodID m_createBitmapMethodID = nullptr;
62static jobject m_ARGB_8888_BitmapConfigValue = nullptr;
63static jobject m_RGB_565_BitmapConfigValue = nullptr;
64
65static jclass m_bitmapDrawableClass = nullptr;
66static jmethodID m_bitmapDrawableConstructorMethodID = nullptr;
67
68extern "C" typedef int (*Main)(int, char **); //use the standard main method to start the application
69static Main m_main = nullptr;
70static void *m_mainLibraryHnd = nullptr;
71static QList<QByteArray> m_applicationParams;
73
74
76
79static double m_scaledDensity = 0;
80static double m_density = 1.0;
81
84
86
87static const char m_qtTag[] = "Qt";
88static const char m_classErrorMsg[] = "Can't find class \"%s\"";
89static const char m_methodErrorMsg[] = "Can't find method \"%s%s\"";
90
92
93Q_DECLARE_JNI_CLASS(QtWindowInterface, "org/qtproject/qt/android/QtWindowInterface")
94Q_DECLARE_JNI_CLASS(QtAccessibilityInterface, "org/qtproject/qt/android/QtAccessibilityInterface");
95
96namespace QtAndroid
97{
102
119
124
125 QWindow *topLevelWindowAt(const QPoint &globalPos)
126 {
128 ? m_androidPlatformIntegration->screen()->topLevelAt(globalPos)
129 : 0;
130 }
131
132 QWindow *windowFromId(int windowId)
133 {
134 if (!qGuiApp)
135 return nullptr;
136
137 for (QWindow *w : qGuiApp->allWindows()) {
138 if (!w->handle())
139 continue;
140 QAndroidPlatformWindow *window = static_cast<QAndroidPlatformWindow *>(w->handle());
141 if (window->nativeViewId() == windowId)
142 return w;
143 }
144 return nullptr;
145 }
146
148 {
150 }
151
153 {
155 }
156
158 {
159 return m_scaledDensity;
160 }
161
163 {
164 return m_density;
165 }
166
167 JavaVM *javaVM()
168 {
169 return m_javaVM;
170 }
171
172 AAssetManager *assetManager()
173 {
174 return m_assetManager;
175 }
176
178 {
179 return m_applicationClass;
180 }
181
182 // TODO move calls from here to where they logically belong
184 {
186 reg->callInterface<QtJniTypes::QtWindowInterface, void>("setSystemUiVisibility",
187 jint(uiVisibility));
188 }
189
191 {
192 // Returns true if the app is a Qt app, i.e. Qt controls the whole app and
193 // the Activity/Service is created by Qt. Returns false if instead Qt is
194 // embedded into a native Android app, where the Activity/Service is created
195 // by the user, outside of Qt, and Qt content is added as a view.
196 JNIEnv *env = QJniEnvironment::getJniEnv();
197 auto activity = QtAndroidPrivate::activity();
198 if (activity.isValid())
199 return env->IsInstanceOf(activity.object(), m_qtActivityClass);
200 auto service = QtAndroidPrivate::service();
201 if (service.isValid())
202 return env->IsInstanceOf(QtAndroidPrivate::service().object(), m_qtServiceClass);
203 // return true as default as Qt application is our default use case.
204 // famous last words: we should not end up here
205 return true;
206 }
207
209 {
210 m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
211 "initializeAccessibility");
212 }
213
214 void notifyAccessibilityLocationChange(uint accessibilityObjectId)
215 {
216 m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
217 "notifyLocationChange", accessibilityObjectId);
218 }
219
220 void notifyObjectHide(uint accessibilityObjectId, uint parentObjectId)
221 {
222 m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
223 "notifyObjectHide", accessibilityObjectId, parentObjectId);
224 }
225
226 void notifyObjectShow(uint parentObjectId)
227 {
228 m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
229 "notifyObjectShow", parentObjectId);
230 }
231
232 void notifyObjectFocus(uint accessibilityObjectId)
233 {
234 m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
235 "notifyObjectFocus", accessibilityObjectId);
236 }
237
238 void notifyValueChanged(uint accessibilityObjectId, jstring value)
239 {
240 m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
241 "notifyValueChanged", accessibilityObjectId, value);
242 }
243
244 void notifyScrolledEvent(uint accessibilityObjectId)
245 {
246 m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
247 "notifyScrolledEvent", accessibilityObjectId);
248 }
249
251 {
252 QJniObject::callStaticMethod<void>(m_applicationClass,
253 "notifyNativePluginIntegrationReady",
254 ready);
255 }
256
257 jobject createBitmap(QImage img, JNIEnv *env)
258 {
259 if (!m_bitmapClass)
260 return 0;
261
262 if (img.format() != QImage::Format_RGBA8888 && img.format() != QImage::Format_RGB16)
263 img = std::move(img).convertToFormat(QImage::Format_RGBA8888);
264
265 jobject bitmap = env->CallStaticObjectMethod(m_bitmapClass,
267 img.width(),
268 img.height(),
269 img.format() == QImage::Format_RGBA8888
272 if (!bitmap)
273 return 0;
274
275 AndroidBitmapInfo info;
276 if (AndroidBitmap_getInfo(env, bitmap, &info) < 0) {
277 env->DeleteLocalRef(bitmap);
278 return 0;
279 }
280
281 void *pixels;
282 if (AndroidBitmap_lockPixels(env, bitmap, &pixels) < 0) {
283 env->DeleteLocalRef(bitmap);
284 return 0;
285 }
286
287 if (info.stride == uint(img.bytesPerLine())
288 && info.width == uint(img.width())
289 && info.height == uint(img.height())) {
290 memcpy(pixels, img.constBits(), info.stride * info.height);
291 } else {
292 uchar *bmpPtr = static_cast<uchar *>(pixels);
293 const unsigned width = qMin(info.width, (uint)img.width()); //should be the same
294 const unsigned height = qMin(info.height, (uint)img.height()); //should be the same
295 for (unsigned y = 0; y < height; y++, bmpPtr += info.stride)
296 memcpy(bmpPtr, img.constScanLine(y), width);
297 }
298 AndroidBitmap_unlockPixels(env, bitmap);
299 return bitmap;
300 }
301
302 jobject createBitmap(int width, int height, QImage::Format format, JNIEnv *env)
303 {
306 return 0;
307
308 return env->CallStaticObjectMethod(m_bitmapClass,
310 width,
311 height,
315 }
316
317 jobject createBitmapDrawable(jobject bitmap, JNIEnv *env)
318 {
320 return 0;
321
322 return env->NewObject(m_bitmapDrawableClass,
325 bitmap);
326 }
327
328 const char *classErrorMsgFmt()
329 {
330 return m_classErrorMsg;
331 }
332
333 const char *methodErrorMsgFmt()
334 {
335 return m_methodErrorMsg;
336 }
337
338 const char *qtTagText()
339 {
340 return m_qtTag;
341 }
342
344 {
345 QString manufacturer = QJniObject::getStaticObjectField("android/os/Build", "MANUFACTURER", "Ljava/lang/String;").toString();
346 QString model = QJniObject::getStaticObjectField("android/os/Build", "MODEL", "Ljava/lang/String;").toString();
347
348 return manufacturer + u' ' + model;
349 }
350
351 void setViewVisibility(jobject view, bool visible)
352 {
353 QJniObject::callStaticMethod<void>(m_applicationClass,
354 "setViewVisibility",
355 "(Landroid/view/View;Z)V",
356 view,
357 visible);
358 }
359
361 {
362 static bool block = qEnvironmentVariableIntValue("QT_BLOCK_EVENT_LOOPS_WHEN_SUSPENDED");
363 return block;
364 }
365
366 jobject assets()
367 {
368 return m_assets;
369 }
370
375
376} // namespace QtAndroid
377
378static jboolean startQtAndroidPlugin(JNIEnv *env, jobject /*object*/, jstring paramsString)
379{
380 Q_UNUSED(env)
381
385 m_mainLibraryHnd = nullptr;
387
388 const QStringList argsList = QProcess::splitCommand(QJniObject(paramsString).toString());
389
390 for (const QString &arg : argsList)
391 m_applicationParams.append(arg.toUtf8());
392
393 // Go home
395
396 //look for main()
397 if (m_applicationParams.length()) {
398 // Obtain a handle to the main library (the library that contains the main() function).
399 // This library should already be loaded, and calling dlopen() will just return a reference to it.
400 m_mainLibraryHnd = dlopen(m_applicationParams.constFirst().data(), 0);
402 qCritical() << "dlopen failed:" << dlerror();
403 return false;
404 }
405 m_main = (Main)dlsym(m_mainLibraryHnd, "main");
406 } else {
407 qWarning("No main library was specified; searching entire process (this is slow!)");
408 m_main = (Main)dlsym(RTLD_DEFAULT, "main");
409 }
410
411 if (Q_UNLIKELY(!m_main)) {
412 qCritical() << "dlsym failed:" << dlerror() << Qt::endl
413 << "Could not find main method";
414 return false;
415 }
416
417 if (sem_init(&m_exitSemaphore, 0, 0) == -1)
418 return false;
419
420 if (sem_init(&m_terminateSemaphore, 0, 0) == -1)
421 return false;
422
423 return true;
424}
425
426static void waitForServiceSetup(JNIEnv *env, jclass /*clazz*/)
427{
428 Q_UNUSED(env);
429 // The service must wait until the QCoreApplication starts otherwise onBind will be
430 // called too early
433}
434
435static void startQtApplication(JNIEnv */*env*/, jclass /*clazz*/)
436{
437 {
438 JNIEnv* env = nullptr;
439 JavaVMAttachArgs args;
440 args.version = JNI_VERSION_1_6;
441 args.name = "QtMainThread";
442 args.group = NULL;
443 JavaVM *vm = QJniEnvironment::javaVM();
444 if (vm)
445 vm->AttachCurrentThread(&env, &args);
446 }
447
448 // Register type for invokeMethod() calls.
449 qRegisterMetaType<Qt::ScreenOrientation>("Qt::ScreenOrientation");
450
451 // Register resources if they are available
452 if (QFile{QStringLiteral("assets:/android_rcc_bundle.rcc")}.exists())
453 QResource::registerResource(QStringLiteral("assets:/android_rcc_bundle.rcc"));
454
455 const int argc = m_applicationParams.size();
456 QVarLengthArray<char *> argv(argc + 1);
457 for (int i = 0; i < argc; i++)
458 argv[i] = m_applicationParams[i].data();
459 argv[argc] = nullptr;
460
461 startQtAndroidPluginCalled.fetchAndAddRelease(1);
462 const int ret = m_main(argc, argv.data());
463 qInfo() << "main() returned" << ret;
464
465 if (m_mainLibraryHnd) {
466 int res = dlclose(m_mainLibraryHnd);
467 if (res < 0)
468 qWarning() << "dlclose failed:" << dlerror();
469 }
470
472 QJniObject::callStaticMethod<void>(m_applicationClass, "quitApp", "()V");
473
474 sem_post(&m_terminateSemaphore);
475 sem_wait(&m_exitSemaphore);
476 sem_destroy(&m_exitSemaphore);
477
478 // We must call exit() to ensure that all global objects will be destructed
479 if (!qEnvironmentVariableIsSet("QT_ANDROID_NO_EXIT_CALL"))
480 exit(ret);
481}
482
483static void quitQtCoreApplication(JNIEnv *env, jclass /*clazz*/)
484{
485 Q_UNUSED(env);
487}
488
489static void quitQtAndroidPlugin(JNIEnv *env, jclass /*clazz*/)
490{
491 Q_UNUSED(env);
497}
498
499static void terminateQt(JNIEnv *env, jclass /*clazz*/)
500{
501 // QAndroidEventDispatcherStopper is stopped when the user uses the task manager to kill the application
505 QAndroidEventDispatcherStopper::instance()->goingToStop(false);
506 }
507
508 if (startQtAndroidPluginCalled.loadAcquire())
509 sem_wait(&m_terminateSemaphore);
510
511 sem_destroy(&m_terminateSemaphore);
512
513 env->DeleteGlobalRef(m_applicationClass);
514 env->DeleteGlobalRef(m_classLoaderObject);
515 if (m_resourcesObj)
516 env->DeleteGlobalRef(m_resourcesObj);
517 if (m_bitmapClass)
518 env->DeleteGlobalRef(m_bitmapClass);
520 env->DeleteGlobalRef(m_ARGB_8888_BitmapConfigValue);
522 env->DeleteGlobalRef(m_RGB_565_BitmapConfigValue);
524 env->DeleteGlobalRef(m_bitmapDrawableClass);
525 if (m_assets)
526 env->DeleteGlobalRef(m_assets);
528 env->DeleteGlobalRef(m_qtActivityClass);
530 env->DeleteGlobalRef(m_qtServiceClass);
534 delete m_backendRegister;
535 m_backendRegister = nullptr;
536 sem_post(&m_exitSemaphore);
537}
538
539static void setDisplayMetrics(JNIEnv * /*env*/, jclass /*clazz*/, jint screenWidthPixels,
540 jint screenHeightPixels, jint availableLeftPixels,
541 jint availableTopPixels, jint availableWidthPixels,
542 jint availableHeightPixels, jdouble xdpi, jdouble ydpi,
543 jdouble scaledDensity, jdouble density, jfloat refreshRate)
544{
545 Q_UNUSED(availableLeftPixels)
546 Q_UNUSED(availableTopPixels)
547
548 m_availableWidthPixels = availableWidthPixels;
549 m_availableHeightPixels = availableHeightPixels;
550 m_scaledDensity = scaledDensity;
551 m_density = density;
552
553 const QSize screenSize(screenWidthPixels, screenHeightPixels);
554 // available geometry always starts from top left
555 const QRect availableGeometry(0, 0, availableWidthPixels, availableHeightPixels);
556 const QSize physicalSize(qRound(double(screenWidthPixels) / xdpi * 25.4),
557 qRound(double(screenHeightPixels) / ydpi * 25.4));
558
562 availableGeometry.left(), availableGeometry.top(), availableGeometry.width(),
563 availableGeometry.height(), physicalSize.width(), physicalSize.height(),
564 screenSize.width(), screenSize.height());
565 } else {
566 m_androidPlatformIntegration->setScreenSizeParameters(physicalSize, screenSize,
567 availableGeometry);
568 m_androidPlatformIntegration->setRefreshRate(refreshRate);
569 }
570}
571Q_DECLARE_JNI_NATIVE_METHOD(setDisplayMetrics)
572
573static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/)
574{
576 return;
577
578 if (QGuiApplication::instance() != nullptr) {
579 const auto tlw = QGuiApplication::topLevelWindows();
580 for (QWindow *w : tlw) {
581
582 // Skip non-platform windows, e.g., offscreen windows.
583 if (!w->handle())
584 continue;
585
586 QRect availableGeometry = w->screen()->availableGeometry();
587 if (w->geometry().width() > 0 && w->geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0)
589 }
590 }
591}
592
593static void updateApplicationState(JNIEnv */*env*/, jobject /*thiz*/, jint state)
594{
598 return;
599 }
600
601 // We're about to call user code from the Android thread, since we don't know
602 //the side effects we'll unlock first!
603 lock.unlock();
606 else if (state == Qt::ApplicationInactive)
608 lock.relock();
610 return;
611
613 // NOTE: sometimes we will receive two consecutive suspended notifications,
614 // In the second suspended notification, QWindowSystemInterface::flushWindowSystemEvents()
615 // will deadlock since the dispatcher has been stopped in the first suspended notification.
616 // To avoid the deadlock we simply return if we found the event dispatcher has been stopped.
618 return;
619
620 // Don't send timers and sockets events anymore if we are going to hide all windows
621 QAndroidEventDispatcherStopper::instance()->goingToStop(true);
625 } else {
628 QAndroidEventDispatcherStopper::instance()->goingToStop(false);
629 }
630}
631
632static void handleOrientationChanged(JNIEnv */*env*/, jobject /*thiz*/, jint newRotation, jint nativeOrientation)
633{
634 // Array of orientations rotated in 90 degree increments, counterclockwise
635 // (same direction as Android measures angles)
636 static const Qt::ScreenOrientation orientations[] = {
641 };
642
643 // The Android API defines the following constants:
644 // ROTATION_0 : 0
645 // ROTATION_90 : 1
646 // ROTATION_180 : 2
647 // ROTATION_270 : 3
648 // ORIENTATION_PORTRAIT : 1
649 // ORIENTATION_LANDSCAPE : 2
650
651 // and newRotation is how much the current orientation is rotated relative to nativeOrientation
652
653 // which means that we can be really clever here :)
654 Qt::ScreenOrientation screenOrientation = orientations[(nativeOrientation - 1 + newRotation) % 4];
655 Qt::ScreenOrientation native = orientations[nativeOrientation - 1];
656
657 QAndroidPlatformIntegration::setScreenOrientation(screenOrientation, native);
661 // Use invokeMethod to keep the certain order of the "geometry change"
662 // and "orientation change" event handling.
663 if (screen) {
665 Q_ARG(Qt::ScreenOrientation, screenOrientation));
666 }
667 }
668}
669Q_DECLARE_JNI_NATIVE_METHOD(handleOrientationChanged)
670
671static void handleRefreshRateChanged(JNIEnv */*env*/, jclass /*cls*/, jfloat refreshRate)
672{
674 m_androidPlatformIntegration->setRefreshRate(refreshRate);
675}
676Q_DECLARE_JNI_NATIVE_METHOD(handleRefreshRateChanged)
677
678static void handleScreenAdded(JNIEnv */*env*/, jclass /*cls*/, jint displayId)
679{
681 m_androidPlatformIntegration->handleScreenAdded(displayId);
682}
683Q_DECLARE_JNI_NATIVE_METHOD(handleScreenAdded)
684
685static void handleScreenChanged(JNIEnv */*env*/, jclass /*cls*/, jint displayId)
686{
688 m_androidPlatformIntegration->handleScreenChanged(displayId);
689}
690Q_DECLARE_JNI_NATIVE_METHOD(handleScreenChanged)
691
692static void handleScreenRemoved(JNIEnv */*env*/, jclass /*cls*/, jint displayId)
693{
695 m_androidPlatformIntegration->handleScreenRemoved(displayId);
696}
697Q_DECLARE_JNI_NATIVE_METHOD(handleScreenRemoved)
698
699static void handleUiDarkModeChanged(JNIEnv */*env*/, jobject /*thiz*/, jint newUiMode)
700{
702 (newUiMode == 1 ) ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light);
703}
704Q_DECLARE_JNI_NATIVE_METHOD(handleUiDarkModeChanged)
705
706static void onActivityResult(JNIEnv */*env*/, jclass /*cls*/,
707 jint requestCode,
708 jint resultCode,
709 jobject data)
710{
711 QtAndroidPrivate::handleActivityResult(requestCode, resultCode, data);
712}
713
714static void onNewIntent(JNIEnv *env, jclass /*cls*/, jobject data)
715{
717}
718
719static jobject onBind(JNIEnv */*env*/, jclass /*cls*/, jobject intent)
720{
722}
723
724static JNINativeMethod methods[] = {
725 { "startQtAndroidPlugin", "(Ljava/lang/String;)Z", (void *)startQtAndroidPlugin },
726 { "startQtApplication", "()V", (void *)startQtApplication },
727 { "quitQtAndroidPlugin", "()V", (void *)quitQtAndroidPlugin },
728 { "quitQtCoreApplication", "()V", (void *)quitQtCoreApplication },
729 { "terminateQt", "()V", (void *)terminateQt },
730 { "waitForServiceSetup", "()V", (void *)waitForServiceSetup },
731 { "updateWindow", "()V", (void *)updateWindow },
732 { "updateApplicationState", "(I)V", (void *)updateApplicationState },
733 { "onActivityResult", "(IILandroid/content/Intent;)V", (void *)onActivityResult },
734 { "onNewIntent", "(Landroid/content/Intent;)V", (void *)onNewIntent },
735 { "onBind", "(Landroid/content/Intent;)Landroid/os/IBinder;", (void *)onBind }
736};
737
738#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
739clazz = env->FindClass(CLASS_NAME); \
740if (!clazz) { \
741 __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_classErrorMsg, CLASS_NAME); \
742 return false; \
743}
744
745#define GET_AND_CHECK_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
746VAR = env->GetMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
747if (!VAR) { \
748 __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \
749 return false; \
750}
751
752#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
753VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
754if (!VAR) { \
755 __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \
756 return false; \
757}
758
759#define GET_AND_CHECK_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \
760VAR = env->GetFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \
761if (!VAR) { \
762 __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, FIELD_NAME, FIELD_SIGNATURE); \
763 return false; \
764}
765
766#define GET_AND_CHECK_STATIC_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \
767VAR = env->GetStaticFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \
768if (!VAR) { \
769 __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, FIELD_NAME, FIELD_SIGNATURE); \
770 return false; \
771}
772
773Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtDisplayManager")
774
776{
777 jclass clazz;
778 FIND_AND_CHECK_CLASS("org/qtproject/qt/android/QtNative");
779 m_applicationClass = static_cast<jclass>(env->NewGlobalRef(clazz));
780
781 if (!env.registerNativeMethods(m_applicationClass,
782 methods, sizeof(methods) / sizeof(methods[0]))) {
783 __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
784 return false;
785 }
786
787 bool success = env.registerNativeMethods(
788 QtJniTypes::Traits<QtJniTypes::QtDisplayManager>::className(),
789 {
790 Q_JNI_NATIVE_METHOD(setDisplayMetrics),
791 Q_JNI_NATIVE_METHOD(handleOrientationChanged),
792 Q_JNI_NATIVE_METHOD(handleRefreshRateChanged),
793 Q_JNI_NATIVE_METHOD(handleScreenAdded),
794 Q_JNI_NATIVE_METHOD(handleScreenChanged),
795 Q_JNI_NATIVE_METHOD(handleScreenRemoved),
796 Q_JNI_NATIVE_METHOD(handleUiDarkModeChanged)
797 });
798
799 if (!success) {
800 qCritical() << "QtDisplayManager: registerNativeMethods() failed";
801 return JNI_FALSE;
802 }
803
804 jmethodID methodID;
805 GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "activity", "()Landroid/app/Activity;");
806 jobject contextObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
807 if (!contextObject) {
808 GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "service", "()Landroid/app/Service;");
809 contextObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
810 }
811
812 if (!contextObject) {
813 __android_log_print(ANDROID_LOG_FATAL,"Qt", "Failed to get Activity or Service object");
814 return false;
815 }
816 const auto releaseContextObject = qScopeGuard([&env, contextObject]{
817 env->DeleteLocalRef(contextObject);
818 });
819
820 GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "classLoader", "()Ljava/lang/ClassLoader;");
821 m_classLoaderObject = env->NewGlobalRef(env->CallStaticObjectMethod(m_applicationClass, methodID));
822 clazz = env->GetObjectClass(m_classLoaderObject);
823 GET_AND_CHECK_METHOD(m_loadClassMethodID, clazz, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
824
825 FIND_AND_CHECK_CLASS("android/content/ContextWrapper");
826 GET_AND_CHECK_METHOD(methodID, clazz, "getAssets", "()Landroid/content/res/AssetManager;");
827 m_assets = env->NewGlobalRef(env->CallObjectMethod(contextObject, methodID));
828 m_assetManager = AAssetManager_fromJava(env.jniEnv(), m_assets);
829
830 GET_AND_CHECK_METHOD(methodID, clazz, "getResources", "()Landroid/content/res/Resources;");
831 m_resourcesObj = env->NewGlobalRef(env->CallObjectMethod(contextObject, methodID));
832
833 FIND_AND_CHECK_CLASS("android/graphics/Bitmap");
834 m_bitmapClass = static_cast<jclass>(env->NewGlobalRef(clazz));
836 "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
837 FIND_AND_CHECK_CLASS("android/graphics/Bitmap$Config");
838 jfieldID fieldId;
839 GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "ARGB_8888", "Landroid/graphics/Bitmap$Config;");
840 m_ARGB_8888_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId));
841 GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "RGB_565", "Landroid/graphics/Bitmap$Config;");
842 m_RGB_565_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId));
843
844 FIND_AND_CHECK_CLASS("android/graphics/drawable/BitmapDrawable");
845 m_bitmapDrawableClass = static_cast<jclass>(env->NewGlobalRef(clazz));
848 "<init>", "(Landroid/content/res/Resources;Landroid/graphics/Bitmap;)V");
849
850 FIND_AND_CHECK_CLASS("org/qtproject/qt/android/QtActivityBase");
851 m_qtActivityClass = static_cast<jclass>(env->NewGlobalRef(clazz));
852 FIND_AND_CHECK_CLASS("org/qtproject/qt/android/QtServiceBase");
853 m_qtServiceClass = static_cast<jclass>(env->NewGlobalRef(clazz));
854
855 return true;
856}
857
859
860Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/)
861{
862 static bool initialized = false;
863 if (initialized)
864 return JNI_VERSION_1_6;
865 initialized = true;
866
868 m_javaVM = vm;
869 QJniEnvironment env;
870 if (!env.isValid()) {
871 m_javaVM = nullptr;
872 __android_log_print(ANDROID_LOG_FATAL, "Qt", "Failed to initialize the JNI Environment");
873 return -1;
874 }
875
876 if (!registerNatives(env)
885 __android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed");
886 return -1;
887 }
889
890 // attach qt main thread data to this thread
891 QThread::currentThread()->setObjectName("QtMainLoopThread");
892 __android_log_print(ANDROID_LOG_INFO, "Qt", "qt started");
893 return JNI_VERSION_1_6;
894}
static int m_pendingApplicationState
static jclass m_qtServiceClass
static jobject m_ARGB_8888_BitmapConfigValue
#define GET_AND_CHECK_STATIC_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE)
static jmethodID m_bitmapDrawableConstructorMethodID
static void setDisplayMetrics(JNIEnv *, jclass, jint screenWidthPixels, jint screenHeightPixels, jint availableLeftPixels, jint availableTopPixels, jint availableWidthPixels, jint availableHeightPixels, jdouble xdpi, jdouble ydpi, jdouble scaledDensity, jdouble density, jfloat refreshRate)
#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE)
static AndroidBackendRegister * m_backendRegister
static AndroidAssetsFileEngineHandler * m_androidAssetsFileEngineHandler
static double m_density
static Q_CONSTINIT QBasicAtomicInt startQtAndroidPluginCalled
static QBasicMutex m_platformMutex
static jmethodID m_loadClassMethodID
static void * m_mainLibraryHnd
static void waitForServiceSetup(JNIEnv *env, jclass)
static sem_t m_exitSemaphore
static jobject m_assets
static JNINativeMethod methods[]
static void handleScreenChanged(JNIEnv *, jclass, jint displayId)
static jclass m_bitmapDrawableClass
QT_END_NAMESPACE Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *)
static void onNewIntent(JNIEnv *env, jclass, jobject data)
#define FIND_AND_CHECK_CLASS(CLASS_NAME)
#define GET_AND_CHECK_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE)
static jobject m_classLoaderObject
int(* Main)(int, char **)
static jmethodID m_createBitmapMethodID
static void handleUiDarkModeChanged(JNIEnv *, jobject, jint newUiMode)
static void handleRefreshRateChanged(JNIEnv *, jclass, jfloat refreshRate)
static void startQtApplication(JNIEnv *, jclass)
static int m_availableHeightPixels
static void updateApplicationState(JNIEnv *, jobject, jint state)
static sem_t m_terminateSemaphore
static jclass m_bitmapClass
static void handleOrientationChanged(JNIEnv *, jobject, jint newRotation, jint nativeOrientation)
static jobject m_resourcesObj
static jobject m_RGB_565_BitmapConfigValue
static jclass m_applicationClass
static void terminateQt(JNIEnv *env, jclass)
static jboolean startQtAndroidPlugin(JNIEnv *env, jobject, jstring paramsString)
static const char m_classErrorMsg[]
static jclass m_qtActivityClass
static int m_availableWidthPixels
static QT_BEGIN_NAMESPACE JavaVM * m_javaVM
static void handleScreenRemoved(JNIEnv *, jclass, jint displayId)
static double m_scaledDensity
static QAndroidPlatformIntegration * m_androidPlatformIntegration
static const char m_methodErrorMsg[]
static void quitQtAndroidPlugin(JNIEnv *env, jclass)
static AndroidContentFileEngineHandler * m_androidContentFileEngineHandler
static void quitQtCoreApplication(JNIEnv *env, jclass)
static const char m_qtTag[]
static QList< QByteArray > m_applicationParams
static jobject onBind(JNIEnv *, jclass, jobject intent)
static void onActivityResult(JNIEnv *, jclass, jint requestCode, jint resultCode, jobject data)
static Main m_main
static AAssetManager * m_assetManager
static void updateWindow(JNIEnv *, jobject)
static void handleScreenAdded(JNIEnv *, jclass, jint displayId)
Q_DECLARE_JNI_CLASS(QtAccessibilityInterface, "org/qtproject/qt/android/QtAccessibilityInterface")
static QAndroidEventDispatcherStopper * instance()
static bool registerNatives(QJniEnvironment &env)
static void setDefaultDisplayMetrics(int availableLeft, int availableTop, int availableWidth, int availableHeight, int physicalWidth, int physicalHeight, int screenWidth, int screenHeight)
static void updateColorScheme(Qt::ColorScheme colorScheme)
static void setScreenOrientation(Qt::ScreenOrientation currentOrientation, Qt::ScreenOrientation nativeOrientation)
static bool registerNatives(QJniEnvironment &env)
static void quit()
\threadsafe
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
static bool setCurrent(const QString &path)
Sets the application's current working directory to path.
Definition qdir.cpp:2030
static QString homePath()
Returns the absolute path of the user's home directory.
Definition qdir.cpp:2103
\inmodule QtCore
Definition qfile.h:93
static QWindowList topLevelWindows()
Returns a list of the top-level windows in the application.
\inmodule QtGui
Definition qimage.h:37
Format
The following image formats are available in Qt.
Definition qimage.h:41
@ Format_RGBA8888
Definition qimage.h:59
@ Format_RGB16
Definition qimage.h:49
\inmodule QtCore
\inmodule QtCore
\inmodule QtCore
Definition qmutex.h:313
\inmodule QtCore
Definition qmutex.h:281
\inmodule QtCore\reentrant
Definition qpoint.h:25
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:239
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:176
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:173
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
static bool registerResource(const QString &rccFilename, const QString &resourceRoot=QString())
Registers the resource with the given rccFileName at the location in the resource tree specified by m...
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QThread * currentThread()
Definition qthread.cpp:1039
static bool handleExposeEvent(QWindow *window, const QRegion &region)
static void handleApplicationStateChanged(Qt::ApplicationState newState, bool forcePropagate=false)
\inmodule QtGui
Definition qwindow.h:63
else opt state
[0]
static bool registerNatives()
Combined button and popup list for selecting options.
bool registerNatives(QJniEnvironment &env)
bool registerNatives(QJniEnvironment &env)
bool registerNatives(QJniEnvironment &env)
bool registerNatives(QJniEnvironment &env)
Q_CORE_EXPORT jobject callOnBindListener(jobject intent)
Q_CORE_EXPORT void handleResume()
Q_CORE_EXPORT QtJniTypes::Activity activity()
Q_CORE_EXPORT void handleNewIntent(JNIEnv *env, jobject intent)
Q_CORE_EXPORT void handlePause()
Q_CORE_EXPORT QtJniTypes::Service service()
Q_CORE_EXPORT void handleActivityResult(jint requestCode, jint resultCode, jobject data)
Q_CORE_EXPORT void waitForServiceSetup()
bool registerNatives(QJniEnvironment &env)
const char * classErrorMsgFmt()
void notifyAccessibilityLocationChange(uint accessibilityObjectId)
void setViewVisibility(jobject view, bool visible)
void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration)
const char * qtTagText()
jobject assets()
QBasicMutex * platformInterfaceMutex()
jobject createBitmap(QImage img, JNIEnv *env)
void initializeAccessibility()
QWindow * topLevelWindowAt(const QPoint &globalPos)
double scaledDensity()
QAndroidPlatformIntegration * androidPlatformIntegration()
AndroidBackendRegister * backendRegister()
QString deviceName()
int availableWidthPixels()
bool blockEventLoopsWhenSuspended()
void setSystemUiVisibility(SystemUiVisibility uiVisibility)
double pixelDensity()
QWindow * windowFromId(int windowId)
jclass applicationClass()
jobject createBitmapDrawable(jobject bitmap, JNIEnv *env)
void notifyNativePluginIntegrationReady(bool ready)
int availableHeightPixels()
AAssetManager * assetManager()
bool isQtApplication()
const char * methodErrorMsgFmt()
ScreenOrientation
Definition qnamespace.h:271
@ InvertedLandscapeOrientation
Definition qnamespace.h:276
@ InvertedPortraitOrientation
Definition qnamespace.h:275
@ LandscapeOrientation
Definition qnamespace.h:274
@ PortraitOrientation
Definition qnamespace.h:273
ApplicationState
Definition qnamespace.h:262
@ ApplicationSuspended
Definition qnamespace.h:263
@ ApplicationActive
Definition qnamespace.h:266
@ ApplicationInactive
Definition qnamespace.h:265
@ AutoConnection
QTextStream & endl(QTextStream &stream)
Writes '\n' to the stream and flushes the stream.
#define Q_BASIC_ATOMIC_INITIALIZER(a)
#define Q_UNLIKELY(x)
#define Q_DECL_EXPORT
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
#define qGuiApp
bool isQtApplication()
Definition qiosglobal.mm:20
#define qCritical
Definition qlogging.h:167
#define qInfo
Definition qlogging.h:165
#define qWarning
Definition qlogging.h:166
return ret
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
#define Q_ARG(Type, data)
Definition qobjectdefs.h:63
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei width
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum const void * pixels
GLint GLsizei GLsizei GLenum format
GLint y
GLuint res
GLint void * img
Definition qopenglext.h:233
GLsizei GLfixed GLfixed GLfixed GLfixed const GLubyte * bitmap
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
Definition qscopeguard.h:60
SSL_CTX int void * arg
#define QStringLiteral(str)
QScreen * screen
[1]
Definition main.cpp:29
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define Q_UNUSED(x)
unsigned char uchar
Definition qtypes.h:32
unsigned int uint
Definition qtypes.h:34
QSqlQueryModel * model
[16]
QReadWriteLock lock
[0]
aWidget window() -> setWindowTitle("New Window Title")
[2]
QHostInfo info
[0]
QQuickView * view
[0]
char * toString(const MyType &t)
[31]
QJSValueList args
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...