Qt 6.x
The Qt SDK
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 "androidjniclipboard.h"
14#include "androidjniinput.h"
15#include "androidjnimain.h"
16#include "androidjnimenu.h"
21
22#include <android/api-level.h>
23#include <android/asset_manager_jni.h>
24#include <android/bitmap.h>
25
26#include <QtCore/private/qjnihelpers_p.h>
27#include <QtCore/qbasicatomic.h>
28#include <QtCore/qjnienvironment.h>
29#include <QtCore/qjniobject.h>
30#include <QtCore/qprocess.h>
31#include <QtCore/qresource.h>
32#include <QtCore/qthread.h>
33#include <QtGui/private/qguiapplication_p.h>
34#include <QtGui/private/qhighdpiscaling_p.h>
35
36#include <qpa/qwindowsysteminterface.h>
37
39
40static JavaVM *m_javaVM = nullptr;
41static jclass m_applicationClass = nullptr;
42static jobject m_classLoaderObject = nullptr;
43static jmethodID m_loadClassMethodID = nullptr;
44static AAssetManager *m_assetManager = nullptr;
45static jobject m_assets = nullptr;
46static jobject m_resourcesObj = nullptr;
47static QtJniTypes::Activity m_activityObject = nullptr;
48static jmethodID m_createSurfaceMethodID = nullptr;
49static QtJniTypes::Service m_serviceObject = nullptr;
50static jmethodID m_setSurfaceGeometryMethodID = nullptr;
51static jmethodID m_destroySurfaceMethodID = nullptr;
52
55
56static jclass m_bitmapClass = nullptr;
57static jmethodID m_createBitmapMethodID = nullptr;
58static jobject m_ARGB_8888_BitmapConfigValue = nullptr;
59static jobject m_RGB_565_BitmapConfigValue = nullptr;
60
61static jclass m_bitmapDrawableClass = nullptr;
62static jmethodID m_bitmapDrawableConstructorMethodID = nullptr;
63
64extern "C" typedef int (*Main)(int, char **); //use the standard main method to start the application
65static Main m_main = nullptr;
66static void *m_mainLibraryHnd = nullptr;
69
71
72Q_CONSTINIT static QBasicMutex m_surfacesMutex;
73
74
76
79static double m_scaledDensity = 0;
80static double m_density = 1.0;
81
84
85
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
93namespace QtAndroid
94{
96 {
97 return &m_platformMutex;
98 }
99
101 {
103
104 // flush the pending state if necessary.
111 }
112
114 }
115
117 {
119 }
120
121 QWindow *topLevelWindowAt(const QPoint &globalPos)
122 {
125 : 0;
126 }
127
129 {
131 }
132
134 {
136 }
137
139 {
140 return m_scaledDensity;
141 }
142
144 {
145 return m_density;
146 }
147
148 JavaVM *javaVM()
149 {
150 return m_javaVM;
151 }
152
153 AAssetManager *assetManager()
154 {
155 return m_assetManager;
156 }
157
159 {
160 return m_applicationClass;
161 }
162
163 QtJniTypes::Activity activity()
164 {
165 return m_activityObject;
166 }
167
168 QtJniTypes::Service service()
169 {
170 return m_serviceObject;
171 }
172
174 {
175 QJniObject::callStaticMethod<void>(m_applicationClass, "setSystemUiVisibility", "(I)V", jint(uiVisibility));
176 }
177
178 void notifyAccessibilityLocationChange(uint accessibilityObjectId)
179 {
180 QJniObject::callStaticMethod<void>(m_applicationClass, "notifyAccessibilityLocationChange",
181 "(I)V", accessibilityObjectId);
182 }
183
184 void notifyObjectHide(uint accessibilityObjectId, uint parentObjectId)
185 {
186 QJniObject::callStaticMethod<void>(m_applicationClass, "notifyObjectHide", "(II)V",
187 accessibilityObjectId, parentObjectId);
188 }
189
190 void notifyObjectFocus(uint accessibilityObjectId)
191 {
192 QJniObject::callStaticMethod<void>(m_applicationClass, "notifyObjectFocus","(I)V", accessibilityObjectId);
193 }
194
195 void notifyValueChanged(uint accessibilityObjectId, jstring value)
196 {
197 QJniObject::callStaticMethod<void>(m_applicationClass, "notifyValueChanged",
198 "(ILjava/lang/String;)V", accessibilityObjectId, value);
199 }
200
201 void notifyScrolledEvent(uint accessibilityObjectId)
202 {
203 QJniObject::callStaticMethod<void>(m_applicationClass, "notifyScrolledEvent", "(I)V",
204 accessibilityObjectId);
205 }
206
208 {
209 QJniObject::callStaticMethod<void>(m_applicationClass, "notifyQtAndroidPluginRunning","(Z)V", running);
210 }
211
212 jobject createBitmap(QImage img, JNIEnv *env)
213 {
214 if (!m_bitmapClass)
215 return 0;
216
217 if (img.format() != QImage::Format_RGBA8888 && img.format() != QImage::Format_RGB16)
218 img = img.convertToFormat(QImage::Format_RGBA8888);
219
220 jobject bitmap = env->CallStaticObjectMethod(m_bitmapClass,
222 img.width(),
223 img.height(),
224 img.format() == QImage::Format_RGBA8888
227 if (!bitmap)
228 return 0;
229
230 AndroidBitmapInfo info;
231 if (AndroidBitmap_getInfo(env, bitmap, &info) < 0) {
232 env->DeleteLocalRef(bitmap);
233 return 0;
234 }
235
236 void *pixels;
237 if (AndroidBitmap_lockPixels(env, bitmap, &pixels) < 0) {
238 env->DeleteLocalRef(bitmap);
239 return 0;
240 }
241
242 if (info.stride == uint(img.bytesPerLine())
243 && info.width == uint(img.width())
244 && info.height == uint(img.height())) {
245 memcpy(pixels, img.constBits(), info.stride * info.height);
246 } else {
247 uchar *bmpPtr = static_cast<uchar *>(pixels);
248 const unsigned width = qMin(info.width, (uint)img.width()); //should be the same
249 const unsigned height = qMin(info.height, (uint)img.height()); //should be the same
250 for (unsigned y = 0; y < height; y++, bmpPtr += info.stride)
251 memcpy(bmpPtr, img.constScanLine(y), width);
252 }
253 AndroidBitmap_unlockPixels(env, bitmap);
254 return bitmap;
255 }
256
257 jobject createBitmap(int width, int height, QImage::Format format, JNIEnv *env)
258 {
261 return 0;
262
263 return env->CallStaticObjectMethod(m_bitmapClass,
265 width,
266 height,
270 }
271
272 jobject createBitmapDrawable(jobject bitmap, JNIEnv *env)
273 {
275 return 0;
276
277 return env->NewObject(m_bitmapDrawableClass,
280 bitmap);
281 }
282
283 const char *classErrorMsgFmt()
284 {
285 return m_classErrorMsg;
286 }
287
288 const char *methodErrorMsgFmt()
289 {
290 return m_methodErrorMsg;
291 }
292
293 const char *qtTagText()
294 {
295 return m_qtTag;
296 }
297
299 {
300 QString manufacturer = QJniObject::getStaticObjectField("android/os/Build", "MANUFACTURER", "Ljava/lang/String;").toString();
301 QString model = QJniObject::getStaticObjectField("android/os/Build", "MODEL", "Ljava/lang/String;").toString();
302
303 return manufacturer + u' ' + model;
304 }
305
307 {
308 return QJniObject::callStaticMethod<jint>("android/view/View", "generateViewId", "()I");
309 }
310
311 int createSurface(AndroidSurfaceClient *client, const QRect &geometry, bool onTop, int imageDepth)
312 {
313 QJniEnvironment env;
314 if (!env.jniEnv())
315 return -1;
316
318 jint surfaceId = generateViewId();
319 m_surfaces[surfaceId] = client;
321
322 jint x = 0, y = 0, w = -1, h = -1;
323 if (!geometry.isNull()) {
324 x = geometry.x();
325 y = geometry.y();
326 w = std::max(geometry.width(), 1);
327 h = std::max(geometry.height(), 1);
328 }
329 env->CallStaticVoidMethod(m_applicationClass,
331 surfaceId,
332 jboolean(onTop),
333 x, y, w, h,
334 imageDepth);
335 return surfaceId;
336 }
337
338 int insertNativeView(jobject view, const QRect &geometry)
339 {
341 jint surfaceId = generateViewId();
342 m_surfaces[surfaceId] = nullptr; // dummy
344
345 jint x = 0, y = 0, w = -1, h = -1;
346 if (!geometry.isNull())
347 geometry.getRect(&x, &y, &w, &h);
348
349 QJniObject::callStaticMethod<void>(m_applicationClass,
350 "insertNativeView",
351 "(ILandroid/view/View;IIII)V",
352 surfaceId,
353 view,
354 x,
355 y,
356 qMax(w, 1),
357 qMax(h, 1));
358
359 return surfaceId;
360 }
361
362 void setViewVisibility(jobject view, bool visible)
363 {
364 QJniObject::callStaticMethod<void>(m_applicationClass,
365 "setViewVisibility",
366 "(Landroid/view/View;Z)V",
367 view,
368 visible);
369 }
370
371 void setSurfaceGeometry(int surfaceId, const QRect &geometry)
372 {
373 if (surfaceId == -1)
374 return;
375
376 QJniEnvironment env;
377 if (!env.jniEnv())
378 return;
379 jint x = 0, y = 0, w = -1, h = -1;
380 if (!geometry.isNull()) {
381 x = geometry.x();
382 y = geometry.y();
383 w = geometry.width();
384 h = geometry.height();
385 }
386 env->CallStaticVoidMethod(m_applicationClass,
388 surfaceId,
389 x, y, w, h);
390 }
391
392
393 void destroySurface(int surfaceId)
394 {
395 if (surfaceId == -1)
396 return;
397
398 {
400 const auto &it = m_surfaces.find(surfaceId);
401 if (it != m_surfaces.end())
402 m_surfaces.erase(it);
403 }
404
405 QJniEnvironment env;
406 if (env.jniEnv())
407 env->CallStaticVoidMethod(m_applicationClass,
409 surfaceId);
410 }
411
412 void bringChildToFront(int surfaceId)
413 {
414 if (surfaceId == -1)
415 return;
416
417 QJniObject::callStaticMethod<void>(m_applicationClass,
418 "bringChildToFront",
419 "(I)V",
420 surfaceId);
421 }
422
423 void bringChildToBack(int surfaceId)
424 {
425 if (surfaceId == -1)
426 return;
427
428 QJniObject::callStaticMethod<void>(m_applicationClass,
429 "bringChildToBack",
430 "(I)V",
431 surfaceId);
432 }
433
435 {
436 static bool block = qEnvironmentVariableIntValue("QT_BLOCK_EVENT_LOOPS_WHEN_SUSPENDED");
437 return block;
438 }
439
440 jobject assets()
441 {
442 return m_assets;
443 }
444
445} // namespace QtAndroid
446
447static jboolean startQtAndroidPlugin(JNIEnv *env, jobject /*object*/, jstring paramsString)
448{
452 m_mainLibraryHnd = nullptr;
453
454 const char *nativeString = env->GetStringUTFChars(paramsString, 0);
455 const QStringList argsList = QProcess::splitCommand(QString::fromUtf8(nativeString));
456 env->ReleaseStringUTFChars(paramsString, nativeString);
457
458 for (const QString &arg : argsList)
460
461 // Go home
463
464 //look for main()
466 // Obtain a handle to the main library (the library that contains the main() function).
467 // This library should already be loaded, and calling dlopen() will just return a reference to it.
470 qCritical() << "dlopen failed:" << dlerror();
471 return false;
472 }
473 m_main = (Main)dlsym(m_mainLibraryHnd, "main");
474 } else {
475 qWarning("No main library was specified; searching entire process (this is slow!)");
476 m_main = (Main)dlsym(RTLD_DEFAULT, "main");
477 }
478
479 if (Q_UNLIKELY(!m_main)) {
480 qCritical() << "dlsym failed:" << dlerror() << Qt::endl
481 << "Could not find main method";
482 return false;
483 }
484
485 if (sem_init(&m_exitSemaphore, 0, 0) == -1)
486 return false;
487
488 if (sem_init(&m_terminateSemaphore, 0, 0) == -1)
489 return false;
490
491 return true;
492}
493
494static void waitForServiceSetup(JNIEnv *env, jclass /*clazz*/)
495{
496 Q_UNUSED(env);
497 // The service must wait until the QCoreApplication starts otherwise onBind will be
498 // called too early
499 if (m_serviceObject)
501}
502
503static void startQtApplication(JNIEnv */*env*/, jclass /*clazz*/)
504{
505 {
506 JNIEnv* env = nullptr;
507 JavaVMAttachArgs args;
508 args.version = JNI_VERSION_1_6;
509 args.name = "QtMainThread";
510 args.group = NULL;
511 JavaVM *vm = QJniEnvironment::javaVM();
512 if (vm)
513 vm->AttachCurrentThread(&env, &args);
514 }
515
516 // Register type for invokeMethod() calls.
517 qRegisterMetaType<Qt::ScreenOrientation>("Qt::ScreenOrientation");
518
519 // Register resources if they are available
520 if (QFile{QStringLiteral("assets:/android_rcc_bundle.rcc")}.exists())
521 QResource::registerResource(QStringLiteral("assets:/android_rcc_bundle.rcc"));
522
523 const int argc = m_applicationParams.size();
524 QVarLengthArray<char *> argv(argc + 1);
525 for (int i = 0; i < argc; i++)
526 argv[i] = m_applicationParams[i].data();
527 argv[argc] = nullptr;
528
530 int ret = m_main(argc, argv.data());
531
532 if (m_mainLibraryHnd) {
533 int res = dlclose(m_mainLibraryHnd);
534 if (res < 0)
535 qWarning() << "dlclose failed:" << dlerror();
536 }
537
538 if (m_applicationClass) {
539 qWarning("exit app 0");
540 QJniObject::callStaticMethod<void>(m_applicationClass, "quitApp", "()V");
541 }
542
543 sem_post(&m_terminateSemaphore);
544 sem_wait(&m_exitSemaphore);
545 sem_destroy(&m_exitSemaphore);
546
547 // We must call exit() to ensure that all global objects will be destructed
548 if (!qEnvironmentVariableIsSet("QT_ANDROID_NO_EXIT_CALL"))
549 exit(ret);
550}
551
552static void quitQtCoreApplication(JNIEnv *env, jclass /*clazz*/)
553{
554 Q_UNUSED(env);
556}
557
558static void quitQtAndroidPlugin(JNIEnv *env, jclass /*clazz*/)
559{
560 Q_UNUSED(env);
566}
567
568static void terminateQt(JNIEnv *env, jclass /*clazz*/)
569{
570 // QAndroidEventDispatcherStopper is stopped when the user uses the task manager to kill the application
575 }
576
578 sem_wait(&m_terminateSemaphore);
579
580 sem_destroy(&m_terminateSemaphore);
581
582 env->DeleteGlobalRef(m_applicationClass);
583 env->DeleteGlobalRef(m_classLoaderObject);
584 if (m_resourcesObj)
585 env->DeleteGlobalRef(m_resourcesObj);
587 env->DeleteGlobalRef(m_activityObject);
588 if (m_serviceObject)
589 env->DeleteGlobalRef(m_serviceObject);
590 if (m_bitmapClass)
591 env->DeleteGlobalRef(m_bitmapClass);
593 env->DeleteGlobalRef(m_ARGB_8888_BitmapConfigValue);
595 env->DeleteGlobalRef(m_RGB_565_BitmapConfigValue);
597 env->DeleteGlobalRef(m_bitmapDrawableClass);
598 if (m_assets)
599 env->DeleteGlobalRef(m_assets);
603 sem_post(&m_exitSemaphore);
604}
605
606static void setSurface(JNIEnv *env, jobject /*thiz*/, jint id, jobject jSurface, jint w, jint h)
607{
609 const auto &it = m_surfaces.find(id);
610 if (it == m_surfaces.end())
611 return;
612
613 auto surfaceClient = it.value();
614 if (surfaceClient)
615 surfaceClient->surfaceChanged(env, jSurface, w, h);
616}
617
618static void setDisplayMetrics(JNIEnv * /*env*/, jclass /*clazz*/, jint screenWidthPixels,
619 jint screenHeightPixels, jint availableLeftPixels,
620 jint availableTopPixels, jint availableWidthPixels,
621 jint availableHeightPixels, jdouble xdpi, jdouble ydpi,
622 jdouble scaledDensity, jdouble density, jfloat refreshRate)
623{
624 Q_UNUSED(availableLeftPixels)
625 Q_UNUSED(availableTopPixels)
626
627 m_availableWidthPixels = availableWidthPixels;
628 m_availableHeightPixels = availableHeightPixels;
629 m_scaledDensity = scaledDensity;
630 m_density = density;
631
632 const QSize screenSize(screenWidthPixels, screenHeightPixels);
633 // available geometry always starts from top left
634 const QRect availableGeometry(0, 0, availableWidthPixels, availableHeightPixels);
635 const QSize physicalSize(qRound(double(screenWidthPixels) / xdpi * 25.4),
636 qRound(double(screenHeightPixels) / ydpi * 25.4));
637
641 availableGeometry.left(), availableGeometry.top(), availableGeometry.width(),
642 availableGeometry.height(), physicalSize.width(), physicalSize.height(),
643 screenSize.width(), screenSize.height());
644 } else {
646 availableGeometry);
648 }
649}
650
651static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/)
652{
654 return;
655
656 if (QGuiApplication::instance() != nullptr) {
657 const auto tlw = QGuiApplication::topLevelWindows();
658 for (QWindow *w : tlw) {
659
660 // Skip non-platform windows, e.g., offscreen windows.
661 if (!w->handle())
662 continue;
663
664 QRect availableGeometry = w->screen()->availableGeometry();
665 if (w->geometry().width() > 0 && w->geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0)
667 }
668 }
669
671 if (screen->rasterSurfaces())
673}
674
675static void updateApplicationState(JNIEnv */*env*/, jobject /*thiz*/, jint state)
676{
680 return;
681 }
682
683 // We're about to call user code from the Android thread, since we don't know
684 //the side effects we'll unlock first!
685 lock.unlock();
688 else if (state == Qt::ApplicationInactive)
690 lock.relock();
692 return;
693
695 // NOTE: sometimes we will receive two consecutive suspended notifications,
696 // In the second suspended notification, QWindowSystemInterface::flushWindowSystemEvents()
697 // will deadlock since the dispatcher has been stopped in the first suspended notification.
698 // To avoid the deadlock we simply return if we found the event dispatcher has been stopped.
700 return;
701
702 // Don't send timers and sockets events anymore if we are going to hide all windows
707 } else {
711 }
712}
713
714static void handleOrientationChanged(JNIEnv */*env*/, jobject /*thiz*/, jint newRotation, jint nativeOrientation)
715{
716 // Array of orientations rotated in 90 degree increments, counterclockwise
717 // (same direction as Android measures angles)
718 static const Qt::ScreenOrientation orientations[] = {
723 };
724
725 // The Android API defines the following constants:
726 // ROTATION_0 : 0
727 // ROTATION_90 : 1
728 // ROTATION_180 : 2
729 // ROTATION_270 : 3
730 // ORIENTATION_PORTRAIT : 1
731 // ORIENTATION_LANDSCAPE : 2
732
733 // and newRotation is how much the current orientation is rotated relative to nativeOrientation
734
735 // which means that we can be really clever here :)
736 Qt::ScreenOrientation screenOrientation = orientations[(nativeOrientation - 1 + newRotation) % 4];
737 Qt::ScreenOrientation native = orientations[nativeOrientation - 1];
738
739 QAndroidPlatformIntegration::setScreenOrientation(screenOrientation, native);
743 // Use invokeMethod to keep the certain order of the "geometry change"
744 // and "orientation change" event handling.
745 if (screen) {
747 Q_ARG(Qt::ScreenOrientation, screenOrientation));
748 }
749 }
750}
751
752static void handleRefreshRateChanged(JNIEnv */*env*/, jclass /*cls*/, jfloat refreshRate)
753{
756}
757
758static void handleScreenAdded(JNIEnv */*env*/, jclass /*cls*/, jint displayId)
759{
762}
763
764static void handleScreenChanged(JNIEnv */*env*/, jclass /*cls*/, jint displayId)
765{
768}
769
770static void handleScreenRemoved(JNIEnv */*env*/, jclass /*cls*/, jint displayId)
771{
774}
775
776static void handleUiDarkModeChanged(JNIEnv */*env*/, jobject /*thiz*/, jint newUiMode)
777{
779 (newUiMode == 1 ) ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light);
780}
781
782static void onActivityResult(JNIEnv */*env*/, jclass /*cls*/,
783 jint requestCode,
784 jint resultCode,
785 jobject data)
786{
787 QtAndroidPrivate::handleActivityResult(requestCode, resultCode, data);
788}
789
790static void onNewIntent(JNIEnv *env, jclass /*cls*/, jobject data)
791{
793}
794
795static jobject onBind(JNIEnv */*env*/, jclass /*cls*/, jobject intent)
796{
798}
799
800static JNINativeMethod methods[] = {
801 { "startQtAndroidPlugin", "(Ljava/lang/String;)Z", (void *)startQtAndroidPlugin },
802 { "startQtApplication", "()V", (void *)startQtApplication },
803 { "quitQtAndroidPlugin", "()V", (void *)quitQtAndroidPlugin },
804 { "quitQtCoreApplication", "()V", (void *)quitQtCoreApplication },
805 { "terminateQt", "()V", (void *)terminateQt },
806 { "waitForServiceSetup", "()V", (void *)waitForServiceSetup },
807 { "setDisplayMetrics", "(IIIIIIDDDDF)V", (void *)setDisplayMetrics },
808 { "setSurface", "(ILjava/lang/Object;II)V", (void *)setSurface },
809 { "updateWindow", "()V", (void *)updateWindow },
810 { "updateApplicationState", "(I)V", (void *)updateApplicationState },
811 { "handleUiDarkModeChanged", "(I)V", (void *)handleUiDarkModeChanged },
812 { "handleOrientationChanged", "(II)V", (void *)handleOrientationChanged },
813 { "onActivityResult", "(IILandroid/content/Intent;)V", (void *)onActivityResult },
814 { "onNewIntent", "(Landroid/content/Intent;)V", (void *)onNewIntent },
815 { "onBind", "(Landroid/content/Intent;)Landroid/os/IBinder;", (void *)onBind },
816 { "handleRefreshRateChanged", "(F)V", (void *)handleRefreshRateChanged },
817 { "handleScreenAdded", "(I)V", (void *)handleScreenAdded },
818 { "handleScreenChanged", "(I)V", (void *)handleScreenChanged },
819 { "handleScreenRemoved", "(I)V", (void *)handleScreenRemoved }
820};
821
822#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
823clazz = env->FindClass(CLASS_NAME); \
824if (!clazz) { \
825 __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_classErrorMsg, CLASS_NAME); \
826 return JNI_FALSE; \
827}
828
829#define GET_AND_CHECK_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
830VAR = env->GetMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
831if (!VAR) { \
832 __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \
833 return JNI_FALSE; \
834}
835
836#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
837VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
838if (!VAR) { \
839 __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \
840 return JNI_FALSE; \
841}
842
843#define GET_AND_CHECK_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \
844VAR = env->GetFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \
845if (!VAR) { \
846 __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, FIELD_NAME, FIELD_SIGNATURE); \
847 return JNI_FALSE; \
848}
849
850#define GET_AND_CHECK_STATIC_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \
851VAR = env->GetStaticFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \
852if (!VAR) { \
853 __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, FIELD_NAME, FIELD_SIGNATURE); \
854 return JNI_FALSE; \
855}
856
857static int registerNatives(JNIEnv *env)
858{
859 jclass clazz;
860 FIND_AND_CHECK_CLASS("org/qtproject/qt/android/QtNative");
861 m_applicationClass = static_cast<jclass>(env->NewGlobalRef(clazz));
862
863 if (env->RegisterNatives(m_applicationClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
864 __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
865 return JNI_FALSE;
866 }
867
871
872 jmethodID methodID;
873 GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "activity", "()Landroid/app/Activity;");
874 jobject activityObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
875 GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "service", "()Landroid/app/Service;");
876 jobject serviceObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
877 GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "classLoader", "()Ljava/lang/ClassLoader;");
878 m_classLoaderObject = env->NewGlobalRef(env->CallStaticObjectMethod(m_applicationClass, methodID));
879 clazz = env->GetObjectClass(m_classLoaderObject);
880 GET_AND_CHECK_METHOD(m_loadClassMethodID, clazz, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
881 if (serviceObject)
882 m_serviceObject = env->NewGlobalRef(serviceObject);
883
884 if (activityObject)
885 m_activityObject = env->NewGlobalRef(activityObject);
886
887 jobject object = activityObject ? activityObject : serviceObject;
888 if (object) {
889 FIND_AND_CHECK_CLASS("android/content/ContextWrapper");
890 GET_AND_CHECK_METHOD(methodID, clazz, "getAssets", "()Landroid/content/res/AssetManager;");
891 m_assets = env->NewGlobalRef(env->CallObjectMethod(object, methodID));
892 m_assetManager = AAssetManager_fromJava(env, m_assets);
893
894 GET_AND_CHECK_METHOD(methodID, clazz, "getResources", "()Landroid/content/res/Resources;");
895 m_resourcesObj = env->NewGlobalRef(env->CallObjectMethod(object, methodID));
896
897 FIND_AND_CHECK_CLASS("android/graphics/Bitmap");
898 m_bitmapClass = static_cast<jclass>(env->NewGlobalRef(clazz));
900 , "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
901 FIND_AND_CHECK_CLASS("android/graphics/Bitmap$Config");
902 jfieldID fieldId;
903 GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "ARGB_8888", "Landroid/graphics/Bitmap$Config;");
904 m_ARGB_8888_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId));
905 GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "RGB_565", "Landroid/graphics/Bitmap$Config;");
906 m_RGB_565_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId));
907
908 FIND_AND_CHECK_CLASS("android/graphics/drawable/BitmapDrawable");
909 m_bitmapDrawableClass = static_cast<jclass>(env->NewGlobalRef(clazz));
912 "<init>",
913 "(Landroid/content/res/Resources;Landroid/graphics/Bitmap;)V");
914 }
915
916 return JNI_TRUE;
917}
918
920
921Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/)
922{
923 static bool initialized = false;
924 if (initialized)
925 return JNI_VERSION_1_6;
926 initialized = true;
927
929 typedef union {
930 JNIEnv *nativeEnvironment;
931 void *venv;
932 } UnionJNIEnvToVoid;
933
934 UnionJNIEnvToVoid uenv;
935 uenv.venv = nullptr;
936 m_javaVM = nullptr;
937
938 if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_6) != JNI_OK) {
939 __android_log_print(ANDROID_LOG_FATAL, "Qt", "GetEnv failed");
940 return -1;
941 }
942
943 JNIEnv *env = uenv.nativeEnvironment;
944 if (!registerNatives(env)
949 __android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed");
950 return -1;
951 }
953
954 m_javaVM = vm;
955 // attach qt main thread data to this thread
956 QObject threadSetter;
957 if (threadSetter.thread())
958 threadSetter.thread()->setObjectName("QtMainLoopThread");
959 __android_log_print(ANDROID_LOG_INFO, "Qt", "qt started");
960 return JNI_VERSION_1_6;
961}
static const char m_classErrorMsg[]
static const char m_qtTag[]
static int m_pendingApplicationState
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 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 jmethodID m_createSurfaceMethodID
static void onNewIntent(JNIEnv *env, jclass, jobject data)
#define FIND_AND_CHECK_CLASS(CLASS_NAME)
static QtJniTypes::Activity m_activityObject
#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)
QHash< int, AndroidSurfaceClient * > m_surfaces
static void handleRefreshRateChanged(JNIEnv *, jclass, jfloat refreshRate)
static void startQtApplication(JNIEnv *, jclass)
static Q_CONSTINIT QBasicMutex m_surfacesMutex
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 QtJniTypes::Service m_serviceObject
static jboolean startQtAndroidPlugin(JNIEnv *env, jobject, jstring paramsString)
static const char m_classErrorMsg[]
static int m_availableWidthPixels
static QT_BEGIN_NAMESPACE JavaVM * m_javaVM
static jmethodID m_destroySurfaceMethodID
static void handleScreenRemoved(JNIEnv *, jclass, jint displayId)
static double m_scaledDensity
static QAndroidPlatformIntegration * m_androidPlatformIntegration
static const char m_methodErrorMsg[]
static void setSurface(JNIEnv *env, jobject, jint id, jobject jSurface, jint w, jint h)
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 jmethodID m_setSurfaceGeometryMethodID
static Main m_main
static AAssetManager * m_assetManager
static void updateWindow(JNIEnv *, jobject)
static void handleScreenAdded(JNIEnv *, jclass, jint displayId)
static QAndroidEventDispatcherStopper * instance()
static void setDefaultDisplayMetrics(int availableLeft, int availableTop, int availableWidth, int availableHeight, int physicalWidth, int physicalHeight, int screenWidth, int screenHeight)
void setScreenSizeParameters(const QSize &physicalSize, const QSize &screenSize, const QRect &availableGeometry)
static void setScreenOrientation(Qt::ScreenOrientation currentOrientation, Qt::ScreenOrientation nativeOrientation)
static void setColorScheme(Qt::ColorScheme colorScheme)
QWindow * topLevelAt(const QPoint &p) const override
Return the given top level window for a given position.
T loadAcquire() const noexcept
T fetchAndAddRelease(T valueToAdd) noexcept
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:534
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:2027
static QString homePath()
Returns the absolute path of the user's home directory.
Definition qdir.cpp:2100
\inmodule QtCore
Definition qfile.h:93
static QWindowList topLevelWindows()
Returns a list of the top-level windows in the application.
\inmodule QtCore
Definition qhash.h:818
\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
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
qsizetype length() const noexcept
Definition qlist.h:388
const T & constFirst() const noexcept
Definition qlist.h:630
void append(parameter_type t)
Definition qlist.h:441
\inmodule QtCore
Definition qmutex.h:317
\inmodule QtCore
Definition qmutex.h:285
void unlock() noexcept
Unlocks the mutex.
Definition qmutex.h:293
void lock() noexcept
Locks the mutex.
Definition qmutex.h:290
\inmodule QtCore
Definition qobject.h:90
QThread * thread() const
Returns the thread in which the object lives.
Definition qobject.cpp:1561
Q_WEAK_OVERLOAD void setObjectName(const QString &name)
Sets the object's name to name.
Definition qobject.h:114
\inmodule QtCore\reentrant
Definition qpoint.h:23
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr void getRect(int *x, int *y, int *w, int *h) const
Extracts the position of the rectangle's top-left corner to *x and *y, and its dimensions to *width a...
Definition qrect.h:337
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:238
constexpr bool isNull() const noexcept
Returns true if the rectangle is a null rectangle, otherwise returns false.
Definition qrect.h:163
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:175
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:172
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:184
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:235
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:187
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...
QRect geometry
the screen's geometry in pixels
Definition qscreen.h:45
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:132
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:129
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
T * data() noexcept
static bool handleExposeEvent(QWindow *window, const QRegion &region)
static void handleApplicationStateChanged(Qt::ApplicationState newState, bool forcePropagate=false)
\inmodule QtGui
Definition qwindow.h:63
QSet< QString >::iterator it
else opt state
[0]
static bool registerNatives()
Combined button and popup list for selecting options.
bool registerNatives(JNIEnv *env)
bool registerNatives(JNIEnv *env)
Q_CORE_EXPORT jobject callOnBindListener(jobject intent)
Q_CORE_EXPORT void handleResume()
Q_CORE_EXPORT void handleNewIntent(JNIEnv *env, jobject intent)
Q_CORE_EXPORT void handlePause()
Q_CORE_EXPORT void handleActivityResult(jint requestCode, jint resultCode, jobject data)
Q_CORE_EXPORT void waitForServiceSetup()
const char * classErrorMsgFmt()
void notifyAccessibilityLocationChange(uint accessibilityObjectId)
int insertNativeView(jobject view, const QRect &geometry)
void setViewVisibility(jobject view, bool visible)
void destroySurface(int surfaceId)
void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration)
const char * qtTagText()
jobject assets()
QBasicMutex * platformInterfaceMutex()
void notifyScrolledEvent(uint accessibilityObjectId)
void setSurfaceGeometry(int surfaceId, const QRect &geometry)
jobject createBitmap(QImage img, JNIEnv *env)
QWindow * topLevelWindowAt(const QPoint &globalPos)
double scaledDensity()
QAndroidPlatformIntegration * androidPlatformIntegration()
void notifyObjectFocus(uint accessibilityObjectId)
QString deviceName()
JavaVM * javaVM()
void notifyValueChanged(uint accessibilityObjectId, jstring value)
void notifyQtAndroidPluginRunning(bool running)
int availableWidthPixels()
bool blockEventLoopsWhenSuspended()
void bringChildToFront(int surfaceId)
void setSystemUiVisibility(SystemUiVisibility uiVisibility)
double pixelDensity()
int createSurface(AndroidSurfaceClient *client, const QRect &geometry, bool onTop, int imageDepth)
void bringChildToBack(int surfaceId)
jclass applicationClass()
QtJniTypes::Activity activity()
jobject createBitmapDrawable(jobject bitmap, JNIEnv *env)
QtJniTypes::Service service()
void notifyObjectHide(uint accessibilityObjectId, uint parentObjectId)
int availableHeightPixels()
jint generateViewId()
AAssetManager * assetManager()
const char * methodErrorMsgFmt()
ScreenOrientation
Definition qnamespace.h:270
@ InvertedLandscapeOrientation
Definition qnamespace.h:275
@ InvertedPortraitOrientation
Definition qnamespace.h:274
@ LandscapeOrientation
Definition qnamespace.h:273
@ PortraitOrientation
Definition qnamespace.h:272
ApplicationState
Definition qnamespace.h:261
@ ApplicationSuspended
Definition qnamespace.h:262
@ ApplicationActive
Definition qnamespace.h:265
@ ApplicationInactive
Definition qnamespace.h:264
@ AutoConnection
@ QueuedConnection
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
static Q_CONSTINIT QBasicAtomicInt running
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:281
#define qCritical
Definition qlogging.h:163
#define qWarning
Definition qlogging.h:162
return ret
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
#define Q_ARG(Type, data)
Definition qobjectdefs.h:62
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLint GLsizei width
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum const void * pixels
GLint GLsizei GLsizei GLenum format
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLuint res
GLint void * img
Definition qopenglext.h:233
GLsizei GLfixed GLfixed GLfixed GLfixed const GLubyte * bitmap
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:27
unsigned int uint
Definition qtypes.h:29
QSqlQueryModel * model
[16]
QFileInfo info(fileName)
[8]
QReadWriteLock lock
[0]
QQuickView * view
[0]
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...