13#include <QtCore/private/qcoreapplication_p.h>
14#include <QtCore/private/qlocking_p.h>
16#if QT_CONFIG(regularexpression)
17#include <QtCore/qregularexpression.h>
20#include <android/log.h>
27Q_DECLARE_JNI_CLASS(QtInputDelegate,
"org/qtproject/qt/android/QtInputDelegate");
31using namespace Qt::StringLiterals;
49Q_CONSTINIT
static QBasicMutex g_onBindListenerMutex;
51Q_CONSTINIT
static QBasicAtomicInt g_serviceSetupLockers = Q_BASIC_ATOMIC_INITIALIZER(0);
58 jclass jQtNative = env->FindClass(
"org/qtproject/qt/android/QtNative");
59 if (QJniEnvironment::checkAndClearExceptions(env))
62 jmethodID activityMethodID =
63 env->GetStaticMethodID(jQtNative,
"activity",
"()Landroid/app/Activity;");
64 if (QJniEnvironment::checkAndClearExceptions(env))
67 jobject activity = env->CallStaticObjectMethod(jQtNative, activityMethodID);
68 if (QJniEnvironment::checkAndClearExceptions(env))
71 QWriteLocker locker(g_updateMutex());
74 env->DeleteGlobalRef(g_jActivity);
80 env->DeleteLocalRef(activity);
83 env->DeleteLocalRef(jQtNative);
84 if (QJniEnvironment::checkAndClearExceptions(env))
91 class ActivityResultListeners
95 QList<QtAndroidPrivate::ActivityResultListener *> listeners;
99Q_GLOBAL_STATIC(ActivityResultListeners, g_activityResultListeners)
103 QMutexLocker locker(&g_activityResultListeners()->mutex);
104 g_activityResultListeners()->listeners.append(listener);
109 QMutexLocker locker(&g_activityResultListeners()->mutex);
110 g_activityResultListeners()->listeners.removeAll(listener);
115 QMutexLocker locker(&g_activityResultListeners()->mutex);
116 const QList<QtAndroidPrivate::ActivityResultListener *> &listeners = g_activityResultListeners()->listeners;
117 for (
int i=0; i<listeners.size(); ++i) {
118 if (listeners.at(i)->handleActivityResult(requestCode, resultCode, data))
124 class NewIntentListeners
128 QList<QtAndroidPrivate::NewIntentListener *> listeners;
132Q_GLOBAL_STATIC(NewIntentListeners, g_newIntentListeners)
136 QMutexLocker locker(&g_newIntentListeners()->mutex);
137 g_newIntentListeners()->listeners.append(listener);
142 QMutexLocker locker(&g_newIntentListeners()->mutex);
143 g_newIntentListeners()->listeners.removeAll(listener);
149 const QList<QtAndroidPrivate::NewIntentListener *> &listeners = g_newIntentListeners()->listeners;
150 for (
int i=0; i<listeners.size(); ++i) {
151 if (listeners.at(i)->handleNewIntent(env, intent))
156QtAndroidPrivate::GenericMotionEventListener::~GenericMotionEventListener() {}
158struct GenericMotionEventListeners {
160 QList<QtAndroidPrivate::GenericMotionEventListener *> listeners;
163Q_GLOBAL_STATIC(GenericMotionEventListeners, g_genericMotionEventListeners)
167 jboolean ret = JNI_FALSE;
168 QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
169 for (
auto *listener : std::as_const(g_genericMotionEventListeners()->listeners))
170 ret |= listener->handleGenericMotionEvent(event.object());
175QtAndroidPrivate::KeyEventListener::~KeyEventListener() {}
177struct KeyEventListeners {
179 QList<QtAndroidPrivate::KeyEventListener *> listeners;
182Q_GLOBAL_STATIC(KeyEventListeners, g_keyEventListeners)
186 jboolean ret = JNI_FALSE;
188 for (
auto *listener : std::as_const(g_keyEventListeners()->listeners))
189 ret |= listener->handleKeyEvent(event.object());
196 QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
197 g_genericMotionEventListeners()->listeners.push_back(listener);
202 QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
203 g_genericMotionEventListeners()->listeners.removeOne(listener);
208 QMutexLocker locker(&g_keyEventListeners()->mutex);
209 g_keyEventListeners()->listeners.push_back(listener);
214 QMutexLocker locker(&g_keyEventListeners()->mutex);
215 g_keyEventListeners()->listeners.removeOne(listener);
219 class ResumePauseListeners
223 QList<QtAndroidPrivate::ResumePauseListener *> listeners;
227Q_GLOBAL_STATIC(ResumePauseListeners, g_resumePauseListeners)
231 QMutexLocker locker(&g_resumePauseListeners()->mutex);
232 g_resumePauseListeners()->listeners.append(listener);
237 QMutexLocker locker(&g_resumePauseListeners()->mutex);
238 g_resumePauseListeners()->listeners.removeAll(listener);
244 const QList<QtAndroidPrivate::ResumePauseListener *> &listeners = g_resumePauseListeners()->listeners;
245 for (
int i=0; i<listeners.size(); ++i)
246 listeners.at(i)->handlePause();
252 const QList<QtAndroidPrivate::ResumePauseListener *> &listeners = g_resumePauseListeners()->listeners;
253 for (
int i=0; i<listeners.size(); ++i)
254 listeners.at(i)->handleResume();
259 const static bool isUncompressed = QtJniTypes::QtLoader::callStaticMethod<
bool>(
260 "isUncompressedNativeLibs");
261 return isUncompressed;
266#if QT_CONFIG(regularexpression)
267 const static QRegularExpression inApkRegex(
"(.+\\.apk)!\\/.+"_L1);
268 auto match = inApkRegex.matchView(fileName);
269 if (match.hasMatch())
270 return match.captured(1);
272 if (
int index = fileName.lastIndexOf(u".apk!/"); index > 0)
273 return fileName.mid(0, index + 4);
283 jclass jQtNative = env->FindClass(
"org/qtproject/qt/android/QtNative");
285 if (QJniEnvironment::checkAndClearExceptions(env))
288 jmethodID activityMethodID = env->GetStaticMethodID(jQtNative,
290 "()Landroid/app/Activity;");
292 if (QJniEnvironment::checkAndClearExceptions(env))
295 jobject activity = env->CallStaticObjectMethod(jQtNative, activityMethodID);
297 if (QJniEnvironment::checkAndClearExceptions(env))
300 jmethodID serviceMethodID = env->GetStaticMethodID(jQtNative,
302 "()Landroid/app/Service;");
304 if (QJniEnvironment::checkAndClearExceptions(env))
307 jobject service = env->CallStaticObjectMethod(jQtNative, serviceMethodID);
309 if (QJniEnvironment::checkAndClearExceptions(env))
312 jmethodID classLoaderMethodID = env->GetStaticMethodID(jQtNative,
314 "()Ljava/lang/ClassLoader;");
316 if (QJniEnvironment::checkAndClearExceptions(env))
319 jobject classLoader = env->CallStaticObjectMethod(jQtNative, classLoaderMethodID);
320 if (QJniEnvironment::checkAndClearExceptions(env))
323 g_jClassLoader = env->NewGlobalRef(classLoader);
324 env->DeleteLocalRef(classLoader);
326 g_jActivity = env->NewGlobalRef(activity);
327 env->DeleteLocalRef(activity);
330 g_jService = env->NewGlobalRef(service);
331 env->DeleteLocalRef(service);
334 static const JNINativeMethod methods[] = {
335 {
"updateNativeActivity",
"()Z",
reinterpret_cast<
void *>(updateNativeActivity) },
338 const bool regOk = (env->RegisterNatives(jQtNative, methods,
sizeof(methods) /
sizeof(methods[0])) == JNI_OK);
339 env->DeleteLocalRef(jQtNative);
340 if (!regOk && QJniEnvironment::checkAndClearExceptions(env))
343 QJniEnvironment qJniEnv;
344 using namespace QtJniTypes;
345 if (!QtInputDelegate::registerNativeMethods(
346 { Q_JNI_NATIVE_METHOD(dispatchGenericMotionEvent),
347 Q_JNI_NATIVE_METHOD(dispatchKeyEvent) })) {
348 qCritical() <<
"Failed to register natives methods for"
349 << Traits<QtInputDelegate>::className();
353#if QT_CONFIG(permissions)
354 if (!registerPermissionNatives(qJniEnv))
358 if (!registerNativeInterfaceNatives(qJniEnv))
361 if (!registerExtrasNatives(qJniEnv))
367Q_CORE_EXPORT jobject qt_androidActivity()
369 QReadLocker locker(g_updateMutex());
376 QReadLocker locker(g_updateMutex());
380Q_CORE_EXPORT jobject qt_androidService()
392 QReadLocker locker(g_updateMutex());
408 return g_jClassLoader;
413 static jint sdkVersion = 0;
415 sdkVersion = QJniObject::getStaticField<jint>(
"android/os/Build$VERSION",
"SDK_INT");
421 g_waitForServiceSetupSemaphore->acquire();
426 g_serviceSetupLockers.ref();
432 const auto lock = qt_scoped_lock(g_onBindListenerMutex);
433 g_onBindListener = listener;
434 if (!g_serviceSetupLockers.deref())
435 g_waitForServiceSetupSemaphore->release();
440 const auto lock = qt_scoped_lock(g_onBindListenerMutex);
441 if (g_onBindListener)
442 return g_onBindListener->onBind(intent);
446Q_CONSTINIT
static QBasicAtomicInt g_androidDeadlockProtector = Q_BASIC_ATOMIC_INITIALIZER(0);
450 return g_androidDeadlockProtector.testAndSetAcquire(0, 1);
455 g_androidDeadlockProtector.storeRelease(0);
458QtAndroidPrivate::AndroidDeadlockProtector::AndroidDeadlockProtector(
const QString &lockedBy)
459 : m_lockedBy(lockedBy)
462QtAndroidPrivate::AndroidDeadlockProtector::~AndroidDeadlockProtector() {
464 QtAndroidPrivate::releaseAndroidDeadlockProtector();
465 s_lockers.removeOne(m_lockedBy);
469bool QtAndroidPrivate::AndroidDeadlockProtector::acquire() {
470 m_acquired = QtAndroidPrivate::acquireAndroidDeadlockProtector();
472 s_lockers.append(m_lockedBy);
474 qWarning(
"Failed to acquire deadlock protector for '%s' while already locked by '%s'.",
475 qPrintable(m_lockedBy), qPrintable(s_lockers.join(u',')));
482extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm,
void *reserved)
486 static const char logTag[] =
"QtCore";
487 static bool initialized =
false;
489 return JNI_VERSION_1_6;
497 __android_log_print(ANDROID_LOG_INFO, logTag,
"Start");
502 if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_6) != JNI_OK) {
503 __android_log_print(ANDROID_LOG_FATAL, logTag,
"GetEnv failed");
507 JNIEnv *env = uenv.nenv;
508 const jint ret = QT_PREPEND_NAMESPACE(QtAndroidPrivate::initJNI(vm, env));
510 __android_log_print(ANDROID_LOG_FATAL, logTag,
"initJNI failed");
514 return JNI_VERSION_1_6;
\preliminary \inmodule QtCorePrivate
Q_CORE_EXPORT void unregisterNewIntentListener(NewIntentListener *listener)
Q_CORE_EXPORT int acuqireServiceSetup(int flags)
Q_CORE_EXPORT void registerNewIntentListener(NewIntentListener *listener)
Q_CORE_EXPORT void unregisterResumePauseListener(ResumePauseListener *listener)
Q_CORE_EXPORT void unregisterGenericMotionEventListener(GenericMotionEventListener *listener)
Q_CORE_EXPORT bool acquireAndroidDeadlockProtector()
Q_CORE_EXPORT void unregisterKeyEventListener(KeyEventListener *listener)
Q_CORE_EXPORT void handleResume()
Q_CORE_EXPORT void registerResumePauseListener(ResumePauseListener *listener)
Q_CORE_EXPORT void releaseAndroidDeadlockProtector()
Q_CORE_EXPORT void handleNewIntent(JNIEnv *env, jobject intent)
Q_CORE_EXPORT void setOnBindListener(OnBindListener *listener)
Q_CORE_EXPORT void registerKeyEventListener(KeyEventListener *listener)
Q_CORE_EXPORT void handlePause()
Q_CORE_EXPORT bool isUncompressedNativeLibs()
Q_CORE_EXPORT void unregisterActivityResultListener(ActivityResultListener *listener)
Q_CORE_EXPORT void registerGenericMotionEventListener(GenericMotionEventListener *listener)
Q_CORE_EXPORT void handleActivityResult(jint requestCode, jint resultCode, jobject data)
Q_CORE_EXPORT void waitForServiceSetup()
Q_CORE_EXPORT void registerActivityResultListener(ActivityResultListener *listener)
Q_GLOBAL_STATIC(DefaultRoleNames, qDefaultRoleNames, { { Qt::DisplayRole, "display" }, { Qt::DecorationRole, "decoration" }, { Qt::EditRole, "edit" }, { Qt::ToolTipRole, "toolTip" }, { Qt::StatusTipRole, "statusTip" }, { Qt::WhatsThisRole, "whatsThis" }, }) const QHash< int
Q_DECLARE_JNI_NATIVE_METHOD(dispatchKeyEvent)
Q_DECLARE_JNI_NATIVE_METHOD(dispatchGenericMotionEvent)
static jobject g_jClassLoader
static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, QtJniTypes::MotionEvent event)
Q_GLOBAL_STATIC(QReadWriteLock, g_updateMutex)
static jobject g_jActivity
Q_DECLARE_JNI_CLASS(MotionEvent, "android/view/MotionEvent")
static jboolean updateNativeActivity(JNIEnv *env, jclass=nullptr)
static jboolean dispatchKeyEvent(JNIEnv *, jclass, QtJniTypes::KeyEvent event)
static jobject g_jService