diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index 46df0fd3b2..6fcd0e995e 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -994,6 +994,7 @@ qt_internal_extend_target(Core CONDITION ANDROID AND NOT ANDROID_EMBEDDED io/qstandardpaths_android.cpp kernel/qcoreapplication_android.cpp io/qstorageinfo_unix.cpp + kernel/qjni.cpp kernel/qjni_p.h kernel/qjnienvironment.cpp kernel/qjnienvironment.h kernel/qjniobject.cpp kernel/qjniobject.h kernel/qjnihelpers.cpp kernel/qjnihelpers_p.h diff --git a/src/corelib/kernel/qjni.cpp b/src/corelib/kernel/qjni.cpp new file mode 100644 index 0000000000..3750fdb9bc --- /dev/null +++ b/src/corelib/kernel/qjni.cpp @@ -0,0 +1,2384 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qjni_p.h" +#include "qjnihelpers_p.h" +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static inline QLatin1String keyBase() +{ + return QLatin1String("%1%2:%3"); +} + +static QString qt_convertJString(jstring string) +{ + QJNIEnvironmentPrivate env; + int strLength = env->GetStringLength(string); + QString res(strLength, Qt::Uninitialized); + env->GetStringRegion(string, 0, strLength, reinterpret_cast(res.data())); + return res; +} + +static inline bool exceptionCheckAndClear(JNIEnv *env) +{ + if (Q_UNLIKELY(env->ExceptionCheck())) { + env->ExceptionDescribe(); + env->ExceptionClear(); + return true; + } + + return false; +} + +typedef QHash JClassHash; +Q_GLOBAL_STATIC(JClassHash, cachedClasses) +Q_GLOBAL_STATIC(QReadWriteLock, cachedClassesLock) + +static QByteArray toBinaryEncClassName(const QByteArray &className) +{ + return QByteArray(className).replace('/', '.'); +} + +static jclass getCachedClass(const QByteArray &classBinEnc, bool *isCached = nullptr) +{ + QReadLocker locker(cachedClassesLock); + const QHash::const_iterator &it = cachedClasses->constFind(QString::fromLatin1(classBinEnc)); + const bool found = (it != cachedClasses->constEnd()); + + if (isCached != 0) + *isCached = found; + + return found ? it.value() : 0; +} + +inline static jclass loadClass(const QByteArray &className, JNIEnv *env, bool binEncoded = false) +{ + const QByteArray &binEncClassName = binEncoded ? className : toBinaryEncClassName(className); + + bool isCached = false; + jclass clazz = getCachedClass(binEncClassName, &isCached); + if (clazz != 0 || isCached) + return clazz; + + QJNIObjectPrivate classLoader(QtAndroidPrivate::classLoader()); + if (!classLoader.isValid()) + return 0; + + QWriteLocker locker(cachedClassesLock); + // did we lose the race? + const QLatin1String key(binEncClassName); + const QHash::const_iterator &it = cachedClasses->constFind(key); + if (it != cachedClasses->constEnd()) + return it.value(); + + QJNIObjectPrivate stringName = QJNIObjectPrivate::fromString(key); + QJNIObjectPrivate classObject = classLoader.callObjectMethod("loadClass", + "(Ljava/lang/String;)Ljava/lang/Class;", + stringName.object()); + + if (!exceptionCheckAndClear(env) && classObject.isValid()) + clazz = static_cast(env->NewGlobalRef(classObject.object())); + + cachedClasses->insert(key, clazz); + return clazz; +} + +typedef QHash JMethodIDHash; +Q_GLOBAL_STATIC(JMethodIDHash, cachedMethodID) +Q_GLOBAL_STATIC(QReadWriteLock, cachedMethodIDLock) + +static inline jmethodID getMethodID(JNIEnv *env, + jclass clazz, + const char *name, + const char *sig, + bool isStatic = false) +{ + jmethodID id = isStatic ? env->GetStaticMethodID(clazz, name, sig) + : env->GetMethodID(clazz, name, sig); + + if (exceptionCheckAndClear(env)) + return 0; + + return id; +} + +static jmethodID getCachedMethodID(JNIEnv *env, + jclass clazz, + const QByteArray &className, + const char *name, + const char *sig, + bool isStatic = false) +{ + if (className.isEmpty()) + return getMethodID(env, clazz, name, sig, isStatic); + + const QString key = keyBase().arg(QLatin1String(className), QLatin1String(name), QLatin1String(sig)); + QHash::const_iterator it; + + { + QReadLocker locker(cachedMethodIDLock); + it = cachedMethodID->constFind(key); + if (it != cachedMethodID->constEnd()) + return it.value(); + } + + { + QWriteLocker locker(cachedMethodIDLock); + it = cachedMethodID->constFind(key); + if (it != cachedMethodID->constEnd()) + return it.value(); + + jmethodID id = getMethodID(env, clazz, name, sig, isStatic); + + cachedMethodID->insert(key, id); + return id; + } +} + +typedef QHash JFieldIDHash; +Q_GLOBAL_STATIC(JFieldIDHash, cachedFieldID) +Q_GLOBAL_STATIC(QReadWriteLock, cachedFieldIDLock) + +static inline jfieldID getFieldID(JNIEnv *env, + jclass clazz, + const char *name, + const char *sig, + bool isStatic = false) +{ + jfieldID id = isStatic ? env->GetStaticFieldID(clazz, name, sig) + : env->GetFieldID(clazz, name, sig); + + if (exceptionCheckAndClear(env)) + return 0; + + return id; +} + +static jfieldID getCachedFieldID(JNIEnv *env, + jclass clazz, + const QByteArray &className, + const char *name, + const char *sig, + bool isStatic = false) +{ + if (className.isNull()) + return getFieldID(env, clazz, name, sig, isStatic); + + const QString key = keyBase().arg(QLatin1String(className), QLatin1String(name), QLatin1String(sig)); + QHash::const_iterator it; + + { + QReadLocker locker(cachedFieldIDLock); + it = cachedFieldID->constFind(key); + if (it != cachedFieldID->constEnd()) + return it.value(); + } + + { + QWriteLocker locker(cachedFieldIDLock); + it = cachedFieldID->constFind(key); + if (it != cachedFieldID->constEnd()) + return it.value(); + + jfieldID id = getFieldID(env, clazz, name, sig, isStatic); + + cachedFieldID->insert(key, id); + return id; + } +} + +void QJNILocalRefDeleter::cleanup(jobject obj) +{ + if (obj == 0) + return; + + QJNIEnvironmentPrivate env; + env->DeleteLocalRef(obj); +} + +class QJNIEnvironmentPrivateTLS +{ +public: + inline ~QJNIEnvironmentPrivateTLS() + { + QtAndroidPrivate::javaVM()->DetachCurrentThread(); + } +}; + +Q_GLOBAL_STATIC(QThreadStorage, jniEnvTLS) + +static const char qJniThreadName[] = "QtThread"; + +QJNIEnvironmentPrivate::QJNIEnvironmentPrivate() + : jniEnv(0) +{ + JavaVM *vm = QtAndroidPrivate::javaVM(); + const jint ret = vm->GetEnv((void**)&jniEnv, JNI_VERSION_1_6); + if (ret == JNI_OK) // Already attached + return; + + if (ret == JNI_EDETACHED) { // We need to (re-)attach + JavaVMAttachArgs args = { JNI_VERSION_1_6, qJniThreadName, nullptr }; + if (vm->AttachCurrentThread(&jniEnv, &args) != JNI_OK) + return; + + if (!jniEnvTLS->hasLocalData()) // If we attached the thread we own it. + jniEnvTLS->setLocalData(new QJNIEnvironmentPrivateTLS); + } +} + +JNIEnv *QJNIEnvironmentPrivate::operator->() +{ + return jniEnv; +} + +jclass QJNIEnvironmentPrivate::findClass(const char *className, JNIEnv *env) +{ + const QByteArray &classDotEnc = toBinaryEncClassName(className); + bool isCached = false; + jclass clazz = getCachedClass(classDotEnc, &isCached); + + if (clazz || isCached) + return clazz; + + const QLatin1String key(classDotEnc); + if (env != 0) { // We got an env. pointer (We expect this to be the right env. and call FindClass()) + QWriteLocker locker(cachedClassesLock); + const QHash::const_iterator &it = cachedClasses->constFind(key); + // Did we lose the race? + if (it != cachedClasses->constEnd()) + return it.value(); + + jclass fclazz = env->FindClass(className); + if (!exceptionCheckAndClear(env)) { + clazz = static_cast(env->NewGlobalRef(fclazz)); + env->DeleteLocalRef(fclazz); + } + + if (clazz != 0) + cachedClasses->insert(key, clazz); + } + + if (clazz == 0) // We didn't get an env. pointer or we got one with the WRONG class loader... + clazz = loadClass(classDotEnc, QJNIEnvironmentPrivate(), true); + + return clazz; +} + +QJNIEnvironmentPrivate::operator JNIEnv* () const +{ + return jniEnv; +} + +QJNIEnvironmentPrivate::~QJNIEnvironmentPrivate() +{ +} + +QJNIObjectData::QJNIObjectData() + : m_jobject(0), + m_jclass(0), + m_own_jclass(true) +{ + +} + +QJNIObjectData::~QJNIObjectData() +{ + QJNIEnvironmentPrivate env; + if (m_jobject) + env->DeleteGlobalRef(m_jobject); + if (m_jclass && m_own_jclass) + env->DeleteGlobalRef(m_jclass); +} + +QJNIObjectPrivate::QJNIObjectPrivate() + : d(new QJNIObjectData()) +{ + +} + +QJNIObjectPrivate::QJNIObjectPrivate(const char *className) + : d(new QJNIObjectData()) +{ + QJNIEnvironmentPrivate env; + d->m_className = toBinaryEncClassName(className); + d->m_jclass = loadClass(d->m_className, env, true); + d->m_own_jclass = false; + if (d->m_jclass) { + // get default constructor + jmethodID constructorId = getCachedMethodID(env, d->m_jclass, d->m_className, "", "()V"); + if (constructorId) { + jobject obj = env->NewObject(d->m_jclass, constructorId); + if (obj) { + d->m_jobject = env->NewGlobalRef(obj); + env->DeleteLocalRef(obj); + } + } + } +} + +QJNIObjectPrivate::QJNIObjectPrivate(const char *className, const char *sig, ...) + : d(new QJNIObjectData()) +{ + QJNIEnvironmentPrivate env; + d->m_className = toBinaryEncClassName(className); + d->m_jclass = loadClass(d->m_className, env, true); + d->m_own_jclass = false; + if (d->m_jclass) { + jmethodID constructorId = getCachedMethodID(env, d->m_jclass, d->m_className, "", sig); + if (constructorId) { + va_list args; + va_start(args, sig); + jobject obj = env->NewObjectV(d->m_jclass, constructorId, args); + va_end(args); + if (obj) { + d->m_jobject = env->NewGlobalRef(obj); + env->DeleteLocalRef(obj); + } + } + } +} + +QJNIObjectPrivate::QJNIObjectPrivate(const char *className, const char *sig, const QVaListPrivate &args) + : d(new QJNIObjectData()) +{ + QJNIEnvironmentPrivate env; + d->m_className = toBinaryEncClassName(className); + d->m_jclass = loadClass(d->m_className, env, true); + d->m_own_jclass = false; + if (d->m_jclass) { + jmethodID constructorId = getCachedMethodID(env, d->m_jclass, d->m_className, "", sig); + if (constructorId) { + jobject obj = env->NewObjectV(d->m_jclass, constructorId, args); + if (obj) { + d->m_jobject = env->NewGlobalRef(obj); + env->DeleteLocalRef(obj); + } + } + } +} + +QJNIObjectPrivate::QJNIObjectPrivate(jclass clazz) + : d(new QJNIObjectData()) +{ + QJNIEnvironmentPrivate env; + d->m_jclass = static_cast(env->NewGlobalRef(clazz)); + if (d->m_jclass) { + // get default constructor + jmethodID constructorId = getMethodID(env, d->m_jclass, "", "()V"); + if (constructorId) { + jobject obj = env->NewObject(d->m_jclass, constructorId); + if (obj) { + d->m_jobject = env->NewGlobalRef(obj); + env->DeleteLocalRef(obj); + } + } + } +} + +QJNIObjectPrivate::QJNIObjectPrivate(jclass clazz, const char *sig, ...) + : d(new QJNIObjectData()) +{ + QJNIEnvironmentPrivate env; + if (clazz) { + d->m_jclass = static_cast(env->NewGlobalRef(clazz)); + if (d->m_jclass) { + jmethodID constructorId = getMethodID(env, d->m_jclass, "", sig); + if (constructorId) { + va_list args; + va_start(args, sig); + jobject obj = env->NewObjectV(d->m_jclass, constructorId, args); + va_end(args); + if (obj) { + d->m_jobject = env->NewGlobalRef(obj); + env->DeleteLocalRef(obj); + } + } + } + } +} + +QJNIObjectPrivate::QJNIObjectPrivate(jclass clazz, const char *sig, const QVaListPrivate &args) + : d(new QJNIObjectData()) +{ + QJNIEnvironmentPrivate env; + if (clazz) { + d->m_jclass = static_cast(env->NewGlobalRef(clazz)); + if (d->m_jclass) { + jmethodID constructorId = getMethodID(env, d->m_jclass, "", sig); + if (constructorId) { + jobject obj = env->NewObjectV(d->m_jclass, constructorId, args); + if (obj) { + d->m_jobject = env->NewGlobalRef(obj); + env->DeleteLocalRef(obj); + } + } + } + } +} + +QJNIObjectPrivate::QJNIObjectPrivate(jobject obj) + : d(new QJNIObjectData()) +{ + if (!obj) + return; + + QJNIEnvironmentPrivate env; + d->m_jobject = env->NewGlobalRef(obj); + jclass cls = env->GetObjectClass(obj); + d->m_jclass = static_cast(env->NewGlobalRef(cls)); + env->DeleteLocalRef(cls); +} +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const +{ + QJNIEnvironmentPrivate env; + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); + if (id) { + env->CallVoidMethodV(d->m_jobject, id, args); + } +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::callMethod(const char *methodName, const char *sig, ...) const +{ + va_list args; + va_start(args, sig); + callMethodV(methodName, sig, args); + va_end(args); +} + +template <> +Q_CORE_EXPORT jboolean QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const +{ + QJNIEnvironmentPrivate env; + jboolean res = 0; + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); + if (id) { + res = env->CallBooleanMethodV(d->m_jobject, id, args); + } + return res; +} + +template <> +Q_CORE_EXPORT jboolean QJNIObjectPrivate::callMethod(const char *methodName, const char *sig, ...) const +{ + va_list args; + va_start(args, sig); + jboolean res = callMethodV(methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jbyte QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const +{ + QJNIEnvironmentPrivate env; + jbyte res = 0; + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); + if (id) { + res = env->CallByteMethodV(d->m_jobject, id, args); + } + return res; +} + +template <> +Q_CORE_EXPORT jbyte QJNIObjectPrivate::callMethod(const char *methodName, const char *sig, ...) const +{ + va_list args; + va_start(args, sig); + jbyte res = callMethodV(methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jchar QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const +{ + QJNIEnvironmentPrivate env; + jchar res = 0; + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); + if (id) { + res = env->CallCharMethodV(d->m_jobject, id, args); + } + return res; +} + +template <> +Q_CORE_EXPORT jchar QJNIObjectPrivate::callMethod(const char *methodName, const char *sig, ...) const +{ + va_list args; + va_start(args, sig); + jchar res = callMethodV(methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jshort QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const +{ + QJNIEnvironmentPrivate env; + jshort res = 0; + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); + if (id) { + res = env->CallShortMethodV(d->m_jobject, id, args); + } + return res; +} + +template <> +Q_CORE_EXPORT jshort QJNIObjectPrivate::callMethod(const char *methodName, const char *sig, ...) const +{ + va_list args; + va_start(args, sig); + jshort res = callMethodV(methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jint QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const +{ + QJNIEnvironmentPrivate env; + jint res = 0; + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); + if (id) { + res = env->CallIntMethodV(d->m_jobject, id, args); + } + return res; +} + +template <> +Q_CORE_EXPORT jint QJNIObjectPrivate::callMethod(const char *methodName, const char *sig, ...) const +{ + va_list args; + va_start(args, sig); + jint res = callMethodV(methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jlong QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const +{ + QJNIEnvironmentPrivate env; + jlong res = 0; + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); + if (id) { + res = env->CallLongMethodV(d->m_jobject, id, args); + } + return res; +} + +template <> +Q_CORE_EXPORT jlong QJNIObjectPrivate::callMethod(const char *methodName, const char *sig, ...) const +{ + va_list args; + va_start(args, sig); + jlong res = callMethodV(methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jfloat QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const +{ + QJNIEnvironmentPrivate env; + jfloat res = 0.f; + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); + if (id) { + res = env->CallFloatMethodV(d->m_jobject, id, args); + } + return res; +} + +template <> +Q_CORE_EXPORT jfloat QJNIObjectPrivate::callMethod(const char *methodName, const char *sig, ...) const +{ + va_list args; + va_start(args, sig); + jfloat res = callMethodV(methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jdouble QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const +{ + QJNIEnvironmentPrivate env; + jdouble res = 0.; + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); + if (id) { + res = env->CallDoubleMethodV(d->m_jobject, id, args); + } + return res; +} + +template <> +Q_CORE_EXPORT jdouble QJNIObjectPrivate::callMethod(const char *methodName, const char *sig, ...) const +{ + va_list args; + va_start(args, sig); + jdouble res = callMethodV(methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::callMethod(const char *methodName) const +{ + callMethod(methodName, "()V"); +} + +template <> +Q_CORE_EXPORT jboolean QJNIObjectPrivate::callMethod(const char *methodName) const +{ + return callMethod(methodName, "()Z"); +} + +template <> +Q_CORE_EXPORT jbyte QJNIObjectPrivate::callMethod(const char *methodName) const +{ + return callMethod(methodName, "()B"); +} + +template <> +Q_CORE_EXPORT jchar QJNIObjectPrivate::callMethod(const char *methodName) const +{ + return callMethod(methodName, "()C"); +} + +template <> +Q_CORE_EXPORT jshort QJNIObjectPrivate::callMethod(const char *methodName) const +{ + return callMethod(methodName, "()S"); +} + +template <> +Q_CORE_EXPORT jint QJNIObjectPrivate::callMethod(const char *methodName) const +{ + return callMethod(methodName, "()I"); +} + +template <> +Q_CORE_EXPORT jlong QJNIObjectPrivate::callMethod(const char *methodName) const +{ + return callMethod(methodName, "()J"); +} + +template <> +Q_CORE_EXPORT jfloat QJNIObjectPrivate::callMethod(const char *methodName) const +{ + return callMethod(methodName, "()F"); +} + +template <> +Q_CORE_EXPORT jdouble QJNIObjectPrivate::callMethod(const char *methodName) const +{ + return callMethod(methodName, "()D"); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz) { + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); + if (id) { + env->CallStaticVoidMethodV(clazz, id, args); + } + } +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::callStaticMethod(const char *className, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + callStaticMethodV(className, methodName, sig, args); + va_end(args); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jmethodID id = getMethodID(env, clazz, methodName, sig, true); + if (id) { + env->CallStaticVoidMethodV(clazz, id, args); + } +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::callStaticMethod(jclass clazz, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + callStaticMethodV(clazz, methodName, sig, args); + va_end(args); +} + +template <> +Q_CORE_EXPORT jboolean QJNIObjectPrivate::callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jboolean res = 0; + jclass clazz = loadClass(className, env); + if (clazz) { + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); + if (id) { + res = env->CallStaticBooleanMethodV(clazz, id, args); + } + } + + return res; +} + +template <> +Q_CORE_EXPORT jboolean QJNIObjectPrivate::callStaticMethod(const char *className, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + jboolean res = callStaticMethodV(className, methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jboolean QJNIObjectPrivate::callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jboolean res = 0; + jmethodID id = getMethodID(env, clazz, methodName, sig, true); + if (id) { + res = env->CallStaticBooleanMethodV(clazz, id, args); + } + + return res; +} + +template <> +Q_CORE_EXPORT jboolean QJNIObjectPrivate::callStaticMethod(jclass clazz, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + jboolean res = callStaticMethodV(clazz, methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jbyte QJNIObjectPrivate::callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jbyte res = 0; + jclass clazz = loadClass(className, env); + if (clazz) { + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); + if (id) { + res = env->CallStaticByteMethodV(clazz, id, args); + } + } + + return res; +} + +template <> +Q_CORE_EXPORT jbyte QJNIObjectPrivate::callStaticMethod(const char *className, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + jbyte res = callStaticMethodV(className, methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jbyte QJNIObjectPrivate::callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jbyte res = 0; + jmethodID id = getMethodID(env, clazz, methodName, sig, true); + if (id) { + res = env->CallStaticByteMethodV(clazz, id, args); + } + + return res; +} + +template <> +Q_CORE_EXPORT jbyte QJNIObjectPrivate::callStaticMethod(jclass clazz, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + jbyte res = callStaticMethodV(clazz, methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jchar QJNIObjectPrivate::callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jchar res = 0; + jclass clazz = loadClass(className, env); + if (clazz) { + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); + if (id) { + res = env->CallStaticCharMethodV(clazz, id, args); + } + } + + return res; +} + +template <> +Q_CORE_EXPORT jchar QJNIObjectPrivate::callStaticMethod(const char *className, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + jchar res = callStaticMethodV(className, methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jchar QJNIObjectPrivate::callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jchar res = 0; + jmethodID id = getMethodID(env, clazz, methodName, sig, true); + if (id) { + res = env->CallStaticCharMethodV(clazz, id, args); + } + + return res; +} + +template <> +Q_CORE_EXPORT jchar QJNIObjectPrivate::callStaticMethod(jclass clazz, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + jchar res = callStaticMethodV(clazz, methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jshort QJNIObjectPrivate::callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jshort res = 0; + jclass clazz = loadClass(className, env); + if (clazz) { + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); + if (id) { + res = env->CallStaticShortMethodV(clazz, id, args); + } + } + + return res; +} + +template <> +Q_CORE_EXPORT jshort QJNIObjectPrivate::callStaticMethod(const char *className, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + jshort res = callStaticMethodV(className, methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jshort QJNIObjectPrivate::callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jshort res = 0; + jmethodID id = getMethodID(env, clazz, methodName, sig, true); + if (id) { + res = env->CallStaticShortMethodV(clazz, id, args); + } + + return res; +} + +template <> +Q_CORE_EXPORT jshort QJNIObjectPrivate::callStaticMethod(jclass clazz, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + jshort res = callStaticMethodV(clazz, methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jint QJNIObjectPrivate::callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jint res = 0; + jclass clazz = loadClass(className, env); + if (clazz) { + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); + if (id) { + res = env->CallStaticIntMethodV(clazz, id, args); + } + } + + return res; +} + +template <> +Q_CORE_EXPORT jint QJNIObjectPrivate::callStaticMethod(const char *className, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + jint res = callStaticMethodV(className, methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jint QJNIObjectPrivate::callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jint res = 0; + jmethodID id = getMethodID(env, clazz, methodName, sig, true); + if (id) { + res = env->CallStaticIntMethodV(clazz, id, args); + } + + return res; +} + +template <> +Q_CORE_EXPORT jint QJNIObjectPrivate::callStaticMethod(jclass clazz, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + jint res = callStaticMethodV(clazz, methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jlong QJNIObjectPrivate::callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jlong res = 0; + jclass clazz = loadClass(className, env); + if (clazz) { + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); + if (id) { + res = env->CallStaticLongMethodV(clazz, id, args); + } + } + + return res; +} + +template <> +Q_CORE_EXPORT jlong QJNIObjectPrivate::callStaticMethod(const char *className, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + jlong res = callStaticMethodV(className, methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jlong QJNIObjectPrivate::callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jlong res = 0; + jmethodID id = getMethodID(env, clazz, methodName, sig, true); + if (id) { + res = env->CallStaticLongMethodV(clazz, id, args); + } + + return res; +} + +template <> +Q_CORE_EXPORT jlong QJNIObjectPrivate::callStaticMethod(jclass clazz, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + jlong res = callStaticMethodV(clazz, methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jfloat QJNIObjectPrivate::callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jfloat res = 0.f; + jclass clazz = loadClass(className, env); + if (clazz) { + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); + if (id) { + res = env->CallStaticFloatMethodV(clazz, id, args); + } + } + + return res; +} + +template <> +Q_CORE_EXPORT jfloat QJNIObjectPrivate::callStaticMethod(const char *className, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + jfloat res = callStaticMethodV(className, methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jfloat QJNIObjectPrivate::callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jfloat res = 0.f; + jmethodID id = getMethodID(env, clazz, methodName, sig, true); + if (id) { + res = env->CallStaticFloatMethodV(clazz, id, args); + } + + return res; +} + +template <> +Q_CORE_EXPORT jfloat QJNIObjectPrivate::callStaticMethod(jclass clazz, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + jfloat res = callStaticMethodV(clazz, methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jdouble QJNIObjectPrivate::callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jdouble res = 0.; + jclass clazz = loadClass(className, env); + if (clazz) { + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); + if (id) { + res = env->CallStaticDoubleMethodV(clazz, id, args); + } + } + + return res; +} + +template <> +Q_CORE_EXPORT jdouble QJNIObjectPrivate::callStaticMethod(const char *className, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + jdouble res = callStaticMethodV(className, methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jdouble QJNIObjectPrivate::callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jdouble res = 0.; + jmethodID id = getMethodID(env, clazz, methodName, sig, true); + if (id) { + res = env->CallStaticDoubleMethodV(clazz, id, args); + } + + return res; +} + +template <> +Q_CORE_EXPORT jdouble QJNIObjectPrivate::callStaticMethod(jclass clazz, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + jdouble res = callStaticMethodV(clazz, methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::callStaticMethod(const char *className, const char *methodName) +{ + callStaticMethod(className, methodName, "()V"); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::callStaticMethod(jclass clazz, const char *methodName) +{ + callStaticMethod(clazz, methodName, "()V"); +} + +template <> +Q_CORE_EXPORT jboolean QJNIObjectPrivate::callStaticMethod(const char *className, const char *methodName) +{ + return callStaticMethod(className, methodName, "()Z"); +} + +template <> +Q_CORE_EXPORT jboolean QJNIObjectPrivate::callStaticMethod(jclass clazz, const char *methodName) +{ + return callStaticMethod(clazz, methodName, "()Z"); +} + +template <> +Q_CORE_EXPORT jbyte QJNIObjectPrivate::callStaticMethod(const char *className, const char *methodName) +{ + return callStaticMethod(className, methodName, "()B"); +} + +template <> +Q_CORE_EXPORT jbyte QJNIObjectPrivate::callStaticMethod(jclass clazz, const char *methodName) +{ + return callStaticMethod(clazz, methodName, "()B"); +} + +template <> +Q_CORE_EXPORT jchar QJNIObjectPrivate::callStaticMethod(const char *className, const char *methodName) +{ + return callStaticMethod(className, methodName, "()C"); +} + +template <> +Q_CORE_EXPORT jchar QJNIObjectPrivate::callStaticMethod(jclass clazz, const char *methodName) +{ + return callStaticMethod(clazz, methodName, "()C"); +} + +template <> +Q_CORE_EXPORT jshort QJNIObjectPrivate::callStaticMethod(const char *className, const char *methodName) +{ + return callStaticMethod(className, methodName, "()S"); +} + +template <> +Q_CORE_EXPORT jshort QJNIObjectPrivate::callStaticMethod(jclass clazz, const char *methodName) +{ + return callStaticMethod(clazz, methodName, "()S"); +} + +template <> +Q_CORE_EXPORT jint QJNIObjectPrivate::callStaticMethod(const char *className, const char *methodName) +{ + return callStaticMethod(className, methodName, "()I"); +} + +template <> +Q_CORE_EXPORT jint QJNIObjectPrivate::callStaticMethod(jclass clazz, const char *methodName) +{ + return callStaticMethod(clazz, methodName, "()I"); +} + +template <> +Q_CORE_EXPORT jlong QJNIObjectPrivate::callStaticMethod(const char *className, const char *methodName) +{ + return callStaticMethod(className, methodName, "()J"); +} + +template <> +Q_CORE_EXPORT jlong QJNIObjectPrivate::callStaticMethod(jclass clazz, const char *methodName) +{ + return callStaticMethod(clazz, methodName, "()J"); +} + +template <> +Q_CORE_EXPORT jfloat QJNIObjectPrivate::callStaticMethod(const char *className, const char *methodName) +{ + return callStaticMethod(className, methodName, "()F"); +} + +template <> +Q_CORE_EXPORT jfloat QJNIObjectPrivate::callStaticMethod(jclass clazz, const char *methodName) +{ + return callStaticMethod(clazz, methodName, "()F"); +} + +template <> +Q_CORE_EXPORT jdouble QJNIObjectPrivate::callStaticMethod(const char *className, const char *methodName) +{ + return callStaticMethod(className, methodName, "()D"); +} + +template <> +Q_CORE_EXPORT jdouble QJNIObjectPrivate::callStaticMethod(jclass clazz, const char *methodName) +{ + return callStaticMethod(clazz, methodName, "()D"); +} + +QJNIObjectPrivate QJNIObjectPrivate::callObjectMethodV(const char *methodName, + const char *sig, + va_list args) const +{ + QJNIEnvironmentPrivate env; + jobject res = 0; + jmethodID id = getCachedMethodID(env, d->m_jclass, d->m_className, methodName, sig); + if (id) { + res = env->CallObjectMethodV(d->m_jobject, id, args); + if (res && env->ExceptionCheck()) + res = 0; + } + + QJNIObjectPrivate obj(res); + env->DeleteLocalRef(res); + return obj; +} + +QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod(const char *methodName, + const char *sig, + ...) const +{ + va_list args; + va_start(args, sig); + QJNIObjectPrivate res = callObjectMethodV(methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod(const char *methodName) const +{ + return callObjectMethod(methodName, "()Ljava/lang/String;"); +} + +template <> +Q_CORE_EXPORT QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod(const char *methodName) const +{ + return callObjectMethod(methodName, "()[Z"); +} + +template <> +Q_CORE_EXPORT QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod(const char *methodName) const +{ + return callObjectMethod(methodName, "()[B"); +} + +template <> +Q_CORE_EXPORT QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod(const char *methodName) const +{ + return callObjectMethod(methodName, "()[S"); +} + +template <> +Q_CORE_EXPORT QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod(const char *methodName) const +{ + return callObjectMethod(methodName, "()[I"); +} + +template <> +Q_CORE_EXPORT QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod(const char *methodName) const +{ + return callObjectMethod(methodName, "()[J"); +} + +template <> +Q_CORE_EXPORT QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod(const char *methodName) const +{ + return callObjectMethod(methodName, "()[F"); +} + +template <> +Q_CORE_EXPORT QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod(const char *methodName) const +{ + return callObjectMethod(methodName, "()[D"); +} + +QJNIObjectPrivate QJNIObjectPrivate::callStaticObjectMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jobject res = 0; + jclass clazz = loadClass(className, env); + if (clazz) { + jmethodID id = getCachedMethodID(env, clazz, toBinaryEncClassName(className), methodName, sig, true); + if (id) { + res = env->CallStaticObjectMethodV(clazz, id, args); + if (res && env->ExceptionCheck()) + res = 0; + } + } + + QJNIObjectPrivate obj(res); + env->DeleteLocalRef(res); + return obj; +} + +QJNIObjectPrivate QJNIObjectPrivate::callStaticObjectMethod(const char *className, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + QJNIObjectPrivate res = callStaticObjectMethodV(className, methodName, sig, args); + va_end(args); + return res; +} + +QJNIObjectPrivate QJNIObjectPrivate::callStaticObjectMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) +{ + QJNIEnvironmentPrivate env; + jobject res = 0; + jmethodID id = getMethodID(env, clazz, methodName, sig, true); + if (id) { + res = env->CallStaticObjectMethodV(clazz, id, args); + if (res && env->ExceptionCheck()) + res = 0; + } + + QJNIObjectPrivate obj(res); + env->DeleteLocalRef(res); + return obj; +} + +QJNIObjectPrivate QJNIObjectPrivate::callStaticObjectMethod(jclass clazz, + const char *methodName, + const char *sig, + ...) +{ + va_list args; + va_start(args, sig); + QJNIObjectPrivate res = callStaticObjectMethodV(clazz, methodName, sig, args); + va_end(args); + return res; +} + +template <> +Q_CORE_EXPORT jboolean QJNIObjectPrivate::getField(const char *fieldName) const +{ + QJNIEnvironmentPrivate env; + jboolean res = 0; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "Z"); + if (id) + res = env->GetBooleanField(d->m_jobject, id); + + return res; +} + +template <> +Q_CORE_EXPORT jbyte QJNIObjectPrivate::getField(const char *fieldName) const +{ + QJNIEnvironmentPrivate env; + jbyte res = 0; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "B"); + if (id) + res = env->GetByteField(d->m_jobject, id); + + return res; +} + +template <> +Q_CORE_EXPORT jchar QJNIObjectPrivate::getField(const char *fieldName) const +{ + QJNIEnvironmentPrivate env; + jchar res = 0; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "C"); + if (id) + res = env->GetCharField(d->m_jobject, id); + + return res; +} + +template <> +Q_CORE_EXPORT jshort QJNIObjectPrivate::getField(const char *fieldName) const +{ + QJNIEnvironmentPrivate env; + jshort res = 0; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "S"); + if (id) + res = env->GetShortField(d->m_jobject, id); + + return res; +} + +template <> +Q_CORE_EXPORT jint QJNIObjectPrivate::getField(const char *fieldName) const +{ + QJNIEnvironmentPrivate env; + jint res = 0; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "I"); + if (id) + res = env->GetIntField(d->m_jobject, id); + + return res; +} + +template <> +Q_CORE_EXPORT jlong QJNIObjectPrivate::getField(const char *fieldName) const +{ + QJNIEnvironmentPrivate env; + jlong res = 0; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "J"); + if (id) + res = env->GetLongField(d->m_jobject, id); + + return res; +} + +template <> +Q_CORE_EXPORT jfloat QJNIObjectPrivate::getField(const char *fieldName) const +{ + QJNIEnvironmentPrivate env; + jfloat res = 0.f; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "F"); + if (id) + res = env->GetFloatField(d->m_jobject, id); + + return res; +} + +template <> +Q_CORE_EXPORT jdouble QJNIObjectPrivate::getField(const char *fieldName) const +{ + QJNIEnvironmentPrivate env; + jdouble res = 0.; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "D"); + if (id) + res = env->GetDoubleField(d->m_jobject, id); + + return res; +} + +template <> +Q_CORE_EXPORT jboolean QJNIObjectPrivate::getStaticField(jclass clazz, const char *fieldName) +{ + QJNIEnvironmentPrivate env; + jboolean res = 0; + jfieldID id = getFieldID(env, clazz, fieldName, "Z", true); + if (id) + res = env->GetStaticBooleanField(clazz, id); + + return res; +} + +template <> +Q_CORE_EXPORT jboolean QJNIObjectPrivate::getStaticField(const char *className, const char *fieldName) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz == 0) + return 0; + + jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, "Z", true); + if (id == 0) + return 0; + + return env->GetStaticBooleanField(clazz, id); +} + +template <> +Q_CORE_EXPORT jbyte QJNIObjectPrivate::getStaticField(jclass clazz, const char *fieldName) +{ + QJNIEnvironmentPrivate env; + jbyte res = 0; + jfieldID id = getFieldID(env, clazz, fieldName, "B", true); + if (id) + res = env->GetStaticByteField(clazz, id); + + return res; +} + +template <> +Q_CORE_EXPORT jbyte QJNIObjectPrivate::getStaticField(const char *className, const char *fieldName) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz == 0) + return 0; + + jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, "B", true); + if (id == 0) + return 0; + + return env->GetStaticByteField(clazz, id); +} + +template <> +Q_CORE_EXPORT jchar QJNIObjectPrivate::getStaticField(jclass clazz, const char *fieldName) +{ + QJNIEnvironmentPrivate env; + jchar res = 0; + jfieldID id = getFieldID(env, clazz, fieldName, "C", true); + if (id) + res = env->GetStaticCharField(clazz, id); + + return res; +} + +template <> +Q_CORE_EXPORT jchar QJNIObjectPrivate::getStaticField(const char *className, const char *fieldName) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz == 0) + return 0; + + jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, "C", true); + if (id == 0) + return 0; + + return env->GetStaticCharField(clazz, id); +} + +template <> +Q_CORE_EXPORT jshort QJNIObjectPrivate::getStaticField(jclass clazz, const char *fieldName) +{ + QJNIEnvironmentPrivate env; + jshort res = 0; + jfieldID id = getFieldID(env, clazz, fieldName, "S", true); + if (id) + res = env->GetStaticShortField(clazz, id); + + return res; +} + +template <> +Q_CORE_EXPORT jshort QJNIObjectPrivate::getStaticField(const char *className, const char *fieldName) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz == 0) + return 0; + + jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, "S", true); + if (id == 0) + return 0; + + return env->GetStaticShortField(clazz, id); +} + +template <> +Q_CORE_EXPORT jint QJNIObjectPrivate::getStaticField(jclass clazz, const char *fieldName) +{ + QJNIEnvironmentPrivate env; + jint res = 0; + jfieldID id = getFieldID(env, clazz, fieldName, "I", true); + if (id) + res = env->GetStaticIntField(clazz, id); + + return res; +} + +template <> +Q_CORE_EXPORT jint QJNIObjectPrivate::getStaticField(const char *className, const char *fieldName) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz == 0) + return 0; + + jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, "I", true); + if (id == 0) + return 0; + + return env->GetStaticIntField(clazz, id); +} + +template <> +Q_CORE_EXPORT jlong QJNIObjectPrivate::getStaticField(jclass clazz, const char *fieldName) +{ + QJNIEnvironmentPrivate env; + jlong res = 0; + jfieldID id = getFieldID(env, clazz, fieldName, "J", true); + if (id) + res = env->GetStaticLongField(clazz, id); + + return res; +} + +template <> +Q_CORE_EXPORT jlong QJNIObjectPrivate::getStaticField(const char *className, const char *fieldName) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz == 0) + return 0; + + jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, "J", true); + if (id == 0) + return 0; + + return env->GetStaticLongField(clazz, id); +} + +template <> +Q_CORE_EXPORT jfloat QJNIObjectPrivate::getStaticField(jclass clazz, const char *fieldName) +{ + QJNIEnvironmentPrivate env; + jfloat res = 0.f; + jfieldID id = getFieldID(env, clazz, fieldName, "F", true); + if (id) + res = env->GetStaticFloatField(clazz, id); + + return res; +} + +template <> +Q_CORE_EXPORT jfloat QJNIObjectPrivate::getStaticField(const char *className, const char *fieldName) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz == 0) + return 0.f; + + jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, "F", true); + if (id == 0) + return 0.f; + + return env->GetStaticFloatField(clazz, id); +} + +template <> +Q_CORE_EXPORT jdouble QJNIObjectPrivate::getStaticField(jclass clazz, const char *fieldName) +{ + QJNIEnvironmentPrivate env; + jdouble res = 0.; + jfieldID id = getFieldID(env, clazz, fieldName, "D", true); + if (id) + res = env->GetStaticDoubleField(clazz, id); + + return res; +} + +template <> +Q_CORE_EXPORT jdouble QJNIObjectPrivate::getStaticField(const char *className, const char *fieldName) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz == 0) + return 0.; + + jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, "D", true); + if (id == 0) + return 0.; + + return env->GetStaticDoubleField(clazz, id); +} + +QJNIObjectPrivate QJNIObjectPrivate::getObjectField(const char *fieldName, + const char *sig) const +{ + QJNIEnvironmentPrivate env; + jobject res = 0; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, sig); + if (id) { + res = env->GetObjectField(d->m_jobject, id); + if (res && env->ExceptionCheck()) + res = 0; + } + + QJNIObjectPrivate obj(res); + env->DeleteLocalRef(res); + return obj; +} + +QJNIObjectPrivate QJNIObjectPrivate::getStaticObjectField(const char *className, + const char *fieldName, + const char *sig) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz == 0) + return QJNIObjectPrivate(); + + jfieldID id = getCachedFieldID(env, clazz, toBinaryEncClassName(className), fieldName, sig, true); + if (id == 0) + return QJNIObjectPrivate(); + + jobject res = env->GetStaticObjectField(clazz, id); + if (res && env->ExceptionCheck()) + res = 0; + + QJNIObjectPrivate obj(res); + env->DeleteLocalRef(res); + return obj; +} + +QJNIObjectPrivate QJNIObjectPrivate::getStaticObjectField(jclass clazz, + const char *fieldName, + const char *sig) +{ + QJNIEnvironmentPrivate env; + jobject res = 0; + jfieldID id = getFieldID(env, clazz, fieldName, sig, true); + if (id) { + res = env->GetStaticObjectField(clazz, id); + if (res && env->ExceptionCheck()) + res = 0; + } + + QJNIObjectPrivate obj(res); + env->DeleteLocalRef(res); + return obj; +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, jboolean value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "Z"); + if (id) + env->SetBooleanField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, jbyte value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "B"); + if (id) + env->SetByteField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, jchar value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "C"); + if (id) + env->SetCharField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, jshort value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "S"); + if (id) + env->SetShortField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, jint value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "I"); + if (id) + env->SetIntField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, jlong value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "J"); + if (id) + env->SetLongField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, jfloat value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "F"); + if (id) + env->SetFloatField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, jdouble value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "D"); + if (id) + env->SetDoubleField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, jbooleanArray value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "[Z"); + if (id) + env->SetObjectField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, jbyteArray value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "[B"); + if (id) + env->SetObjectField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, jcharArray value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "[C"); + if (id) + env->SetObjectField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, jshortArray value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "[S"); + if (id) + env->SetObjectField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, jintArray value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "[I"); + if (id) + env->SetObjectField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, jlongArray value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "[J"); + if (id) + env->SetObjectField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, jfloatArray value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "[F"); + if (id) + env->SetObjectField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, jdoubleArray value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "[D"); + if (id) + env->SetObjectField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, jstring value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, "Ljava/lang/String;"); + if (id) + env->SetObjectField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, + const char *sig, + jobject value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, sig); + if (id) + env->SetObjectField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setField(const char *fieldName, + const char *sig, + jobjectArray value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getCachedFieldID(env, d->m_jclass, d->m_className, fieldName, sig); + if (id) + env->SetObjectField(d->m_jobject, id, value); + +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setStaticField(jclass clazz, + const char *fieldName, + jboolean value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getFieldID(env, clazz, fieldName, "Z", true); + if (id) + env->SetStaticBooleanField(clazz, id, value); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setStaticField(const char *className, + const char *fieldName, + jboolean value) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz == 0) + return; + + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, "Z", true); + if (id == 0) + return; + + env->SetStaticBooleanField(clazz, id, value); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setStaticField(jclass clazz, + const char *fieldName, + jbyte value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getFieldID(env, clazz, fieldName, "B", true); + if (id) + env->SetStaticByteField(clazz, id, value); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setStaticField(const char *className, + const char *fieldName, + jbyte value) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz == 0) + return; + + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, "B", true); + if (id == 0) + return; + + env->SetStaticByteField(clazz, id, value); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setStaticField(jclass clazz, + const char *fieldName, + jchar value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getFieldID(env, clazz, fieldName, "C", true); + if (id) + env->SetStaticCharField(clazz, id, value); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setStaticField(const char *className, + const char *fieldName, + jchar value) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz == 0) + return; + + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, "C", true); + if (id == 0) + return; + + env->SetStaticCharField(clazz, id, value); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setStaticField(jclass clazz, + const char *fieldName, + jshort value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getFieldID(env, clazz, fieldName, "S", true); + if (id) + env->SetStaticShortField(clazz, id, value); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setStaticField(const char *className, + const char *fieldName, + jshort value) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz == 0) + return; + + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, "S", true); + if (id == 0) + return; + + env->SetStaticShortField(clazz, id, value); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setStaticField(jclass clazz, + const char *fieldName, + jint value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getFieldID(env, clazz, fieldName, "I", true); + if (id) + env->SetStaticIntField(clazz, id, value); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setStaticField(const char *className, + const char *fieldName, + jint value) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz == 0) + return; + + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, "I", true); + if (id == 0) + return; + + env->SetStaticIntField(clazz, id, value); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setStaticField(jclass clazz, + const char *fieldName, + jlong value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getFieldID(env, clazz, fieldName, "J", true); + if (id) + env->SetStaticLongField(clazz, id, value); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setStaticField(const char *className, + const char *fieldName, + jlong value) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz == 0) + return; + + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, "J", true); + if (id == 0) + return; + + env->SetStaticLongField(clazz, id, value); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setStaticField(jclass clazz, + const char *fieldName, + jfloat value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getFieldID(env, clazz, fieldName, "F", true); + if (id) + env->SetStaticFloatField(clazz, id, value); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setStaticField(const char *className, + const char *fieldName, + jfloat value) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz == 0) + return; + + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, "F", true); + if (id == 0) + return; + + env->SetStaticFloatField(clazz, id, value); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setStaticField(jclass clazz, + const char *fieldName, + jdouble value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getFieldID(env, clazz, fieldName, "D", true); + if (id) + env->SetStaticDoubleField(clazz, id, value); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setStaticField(const char *className, + const char *fieldName, + jdouble value) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz == 0) + return; + + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, "D", true); + if (id == 0) + return; + + env->SetStaticDoubleField(clazz, id, value); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setStaticField(jclass clazz, + const char *fieldName, + const char *sig, + jobject value) +{ + QJNIEnvironmentPrivate env; + jfieldID id = getFieldID(env, clazz, fieldName, sig, true); + if (id) + env->SetStaticObjectField(clazz, id, value); +} + +template <> +Q_CORE_EXPORT void QJNIObjectPrivate::setStaticField(const char *className, + const char *fieldName, + const char *sig, + jobject value) +{ + QJNIEnvironmentPrivate env; + jclass clazz = loadClass(className, env); + if (clazz == 0) + return; + + jfieldID id = getCachedFieldID(env, clazz, className, fieldName, sig, true); + if (id == 0) + return; + + env->SetStaticObjectField(clazz, id, value); +} + +QJNIObjectPrivate QJNIObjectPrivate::fromString(const QString &string) +{ + QJNIEnvironmentPrivate env; + jstring res = env->NewString(reinterpret_cast(string.constData()), + string.length()); + QJNIObjectPrivate obj(res); + env->DeleteLocalRef(res); + return obj; +} + +QString QJNIObjectPrivate::toString() const +{ + if (!isValid()) + return QString(); + + QJNIObjectPrivate string = callObjectMethod("toString"); + return qt_convertJString(static_cast(string.object())); +} + +bool QJNIObjectPrivate::isClassAvailable(const char *className) +{ + QJNIEnvironmentPrivate env; + + if (!env) + return false; + + jclass clazz = loadClass(className, env); + return (clazz != 0); +} + +bool QJNIObjectPrivate::isValid() const +{ + return d->m_jobject; +} + +QJNIObjectPrivate QJNIObjectPrivate::fromLocalRef(jobject lref) +{ + QJNIObjectPrivate o(lref); + QJNIEnvironmentPrivate()->DeleteLocalRef(lref); + return o; +} + +bool QJNIObjectPrivate::isSameObject(jobject obj) const +{ + QJNIEnvironmentPrivate env; + return env->IsSameObject(d->m_jobject, obj); +} + +bool QJNIObjectPrivate::isSameObject(const QJNIObjectPrivate &other) const +{ + return isSameObject(other.d->m_jobject); +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qjni_p.h b/src/corelib/kernel/qjni_p.h new file mode 100644 index 0000000000..57ec8a39b5 --- /dev/null +++ b/src/corelib/kernel/qjni_p.h @@ -0,0 +1,292 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// +// FIXME: Remove this once the JNI API is used by other modules. + +#ifndef QJNI_P_H +#define QJNI_P_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +struct Q_CORE_EXPORT QJNILocalRefDeleter +{ + static void cleanup(jobject obj); +}; + +// To simplify this we only define it for jobjects. +typedef QScopedPointer<_jobject, QJNILocalRefDeleter> QJNIScopedLocalRef; + +class Q_CORE_EXPORT QJNIEnvironmentPrivate +{ +public: + QJNIEnvironmentPrivate(); + ~QJNIEnvironmentPrivate(); + JNIEnv *operator->(); + operator JNIEnv *() const; + static jclass findClass(const char *className, JNIEnv *env = nullptr); + +private: + friend class QAndroidJniEnvironment; + Q_DISABLE_COPY_MOVE(QJNIEnvironmentPrivate) + JNIEnv *jniEnv; +}; + +class Q_CORE_EXPORT QJNIObjectData +{ +public: + QJNIObjectData(); + ~QJNIObjectData(); + jobject m_jobject; + jclass m_jclass; + bool m_own_jclass; + QByteArray m_className; +}; + +class Q_CORE_EXPORT QJNIObjectPrivate +{ +public: + QJNIObjectPrivate(); + explicit QJNIObjectPrivate(const char *className); + QJNIObjectPrivate(const char *className, const char *sig, ...); + explicit QJNIObjectPrivate(jclass clazz); + QJNIObjectPrivate(jclass clazz, const char *sig, ...); + // In most cases you should never call this function with a local ref. unless you intend + // to manage the local ref. yourself. + // NOTE: see fromLocalRef() for converting a local ref. to QJNIObjectPrivate. + explicit QJNIObjectPrivate(jobject globalRef); + + template + T callMethod(const char *methodName, + const char *sig, + ...) const; + template + T callMethod(const char *methodName) const; + template + QJNIObjectPrivate callObjectMethod(const char *methodName) const; + QJNIObjectPrivate callObjectMethod(const char *methodName, + const char *sig, + ...) const; + template + static T callStaticMethod(const char *className, + const char *methodName, + const char *sig, ...); + template + static T callStaticMethod(const char *className, + const char *methodName); + template + static T callStaticMethod(jclass clazz, + const char *methodName, + const char *sig, ...); + template + static T callStaticMethod(jclass clazz, + const char *methodName); + static QJNIObjectPrivate callStaticObjectMethod(const char *className, + const char *methodName, + const char *sig, ...); + + static QJNIObjectPrivate callStaticObjectMethod(jclass clazz, + const char *methodName, + const char *sig, ...); + + template + T getField(const char *fieldName) const; + template + static T getStaticField(const char *className, const char *fieldName); + template + static T getStaticField(jclass clazz, const char *fieldName); + + QJNIObjectPrivate getObjectField(const char *fieldName, const char *sig) const; + static QJNIObjectPrivate getStaticObjectField(const char *className, + const char *fieldName, + const char *sig); + static QJNIObjectPrivate getStaticObjectField(jclass clazz, + const char *fieldName, + const char *sig); + + template + void setField(const char *fieldName, T value); + template + void setField(const char *fieldName, const char *sig, T value); + template + static void setStaticField(const char *className, + const char *fieldName, + T value); + template + static void setStaticField(const char *className, + const char *fieldName, + const char *sig, + T value); + template + static void setStaticField(jclass clazz, + const char *fieldName, + const char *sig, + T value); + + template + static void setStaticField(jclass clazz, + const char *fieldName, + T value); + + static QJNIObjectPrivate fromString(const QString &string); + QString toString() const; + + static bool isClassAvailable(const char *className); + bool isValid() const; + jobject object() const { return d->m_jobject; } + + template + inline QJNIObjectPrivate &operator=(T o) + { + jobject jobj = static_cast(o); + if (!isSameObject(jobj)) { + d = QSharedPointer::create(); + if (jobj) { + QJNIEnvironmentPrivate env; + d->m_jobject = env->NewGlobalRef(jobj); + jclass objectClass = env->GetObjectClass(jobj); + d->m_jclass = static_cast(env->NewGlobalRef(objectClass)); + env->DeleteLocalRef(objectClass); + } + } + + return *this; + } + + // This function takes ownership of the jobject and releases the local ref. before returning. + static QJNIObjectPrivate fromLocalRef(jobject lref); + +private: + friend class QAndroidJniObject; + + struct QVaListPrivate { operator va_list &() const { return m_args; } va_list &m_args; }; + + QJNIObjectPrivate(const char *className, const char *sig, const QVaListPrivate &args); + QJNIObjectPrivate(jclass clazz, const char *sig, const QVaListPrivate &args); + + template + T callMethodV(const char *methodName, + const char *sig, + va_list args) const; + QJNIObjectPrivate callObjectMethodV(const char *methodName, + const char *sig, + va_list args) const; + template + static T callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args); + template + static T callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args); + static QJNIObjectPrivate callStaticObjectMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args); + + static QJNIObjectPrivate callStaticObjectMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args); + + bool isSameObject(jobject obj) const; + bool isSameObject(const QJNIObjectPrivate &other) const; + + friend bool operator==(const QJNIObjectPrivate &, const QJNIObjectPrivate &); + friend bool operator!=(const QJNIObjectPrivate&, const QJNIObjectPrivate&); + template friend bool operator!=(const QJNIObjectPrivate&, T); + template friend bool operator==(const QJNIObjectPrivate&, T); + template friend bool operator!=(T, const QJNIObjectPrivate&); + template friend bool operator==(T, const QJNIObjectPrivate&); + + QSharedPointer d; +}; + +inline bool operator==(const QJNIObjectPrivate &obj1, const QJNIObjectPrivate &obj2) +{ + return obj1.isSameObject(obj2); +} + +inline bool operator!=(const QJNIObjectPrivate &obj1, const QJNIObjectPrivate &obj2) +{ + return !obj1.isSameObject(obj2); +} + +template +inline bool operator==(const QJNIObjectPrivate &obj1, T obj2) +{ + return obj1.isSameObject(static_cast(obj2)); +} + +template +inline bool operator==(T obj1, const QJNIObjectPrivate &obj2) +{ + return obj2.isSameObject(static_cast(obj1)); +} + +template +inline bool operator!=(const QJNIObjectPrivate &obj1, T obj2) +{ + return !obj1.isSameObject(obj2); +} + +template +inline bool operator!=(T obj1, const QJNIObjectPrivate &obj2) +{ + return !obj2.isSameObject(obj1); +} + +QT_END_NAMESPACE + +#endif // QJNI_P_H diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp index b2a5dc7441..46143d4c2c 100644 --- a/src/corelib/kernel/qjnihelpers.cpp +++ b/src/corelib/kernel/qjnihelpers.cpp @@ -37,14 +37,18 @@ ** ****************************************************************************/ -#include "qjnihelpers_p.h" - +#include "qcoreapplication.h" #include "qjnienvironment.h" +#include "qjnihelpers_p.h" #include "qjniobject.h" #include "qlist.h" #include "qmutex.h" #include "qsemaphore.h" +#include "qsharedpointer.h" +#include "qthread.h" + #include +#include #include #include @@ -68,20 +72,91 @@ static JavaVM *g_javaVM = nullptr; static jobject g_jActivity = nullptr; static jobject g_jService = nullptr; static jobject g_jClassLoader = nullptr; +static jclass g_jNativeClass = nullptr; +static jmethodID g_runPendingCppRunnablesMethodID = nullptr; +Q_GLOBAL_STATIC(std::deque, g_pendingRunnables); +static QBasicMutex g_pendingRunnablesMutex; Q_GLOBAL_STATIC_WITH_ARGS(QtAndroidPrivate::OnBindListener*, g_onBindListener, (nullptr)); Q_GLOBAL_STATIC(QMutex, g_onBindListenerMutex); Q_GLOBAL_STATIC(QSemaphore, g_waitForServiceSetupSemaphore); Q_GLOBAL_STATIC(QAtomicInt, g_serviceSetupLockers); +class PermissionsResultClass : public QObject +{ + Q_OBJECT +public: + PermissionsResultClass(const QtAndroidPrivate::PermissionsResultFunc &func) : m_func(func) {} + Q_INVOKABLE void sendResult(const QtAndroidPrivate::PermissionsHash &result) { m_func(result); delete this;} + +private: + QtAndroidPrivate::PermissionsResultFunc m_func; +}; + +typedef QHash PendingPermissionRequestsHash; +Q_GLOBAL_STATIC(PendingPermissionRequestsHash, g_pendingPermissionRequests); +static QBasicMutex g_pendingPermissionRequestsMutex; +static int nextRequestCode() +{ + static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(0); + return counter.fetchAndAddRelaxed(1); +} + +// function called from Java from Android UI thread +static void runPendingCppRunnables(JNIEnv */*env*/, jobject /*obj*/) +{ + for (;;) { // run all posted runnables + QMutexLocker locker(&g_pendingRunnablesMutex); + if (g_pendingRunnables->empty()) { + break; + } + QtAndroidPrivate::Runnable runnable(std::move(g_pendingRunnables->front())); + g_pendingRunnables->pop_front(); + locker.unlock(); + runnable(); // run it outside the sync block! + } +} + namespace { struct GenericMotionEventListeners { QMutex mutex; QList listeners; }; + + enum { + PERMISSION_GRANTED = 0 + }; } Q_GLOBAL_STATIC(GenericMotionEventListeners, g_genericMotionEventListeners) +static void sendRequestPermissionsResult(JNIEnv *env, jobject /*obj*/, jint requestCode, + jobjectArray permissions, jintArray grantResults) +{ + QMutexLocker locker(&g_pendingPermissionRequestsMutex); + auto it = g_pendingPermissionRequests->find(requestCode); + if (it == g_pendingPermissionRequests->end()) { + // show an error or something ? + return; + } + auto request = *it; + g_pendingPermissionRequests->erase(it); + locker.unlock(); + + Qt::ConnectionType connection = QThread::currentThread() == request->thread() ? Qt::DirectConnection : Qt::QueuedConnection; + QtAndroidPrivate::PermissionsHash hash; + const int size = env->GetArrayLength(permissions); + std::unique_ptr results(new jint[size]); + env->GetIntArrayRegion(grantResults, 0, size, results.get()); + for (int i = 0 ; i < size; ++i) { + const auto &permission = QJniObject(env->GetObjectArrayElement(permissions, i)).toString(); + auto value = results[i] == PERMISSION_GRANTED ? + QtAndroidPrivate::PermissionsResult::Granted : + QtAndroidPrivate::PermissionsResult::Denied; + hash[permission] = value; + } + QMetaObject::invokeMethod(request, "sendResult", connection, Q_ARG(QtAndroidPrivate::PermissionsHash, hash)); +} + static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event) { jboolean ret = JNI_FALSE; @@ -269,12 +344,14 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env) } static const JNINativeMethod methods[] = { + {"runPendingCppRunnables", "()V", reinterpret_cast(runPendingCppRunnables)}, {"dispatchGenericMotionEvent", "(Landroid/view/MotionEvent;)Z", reinterpret_cast(dispatchGenericMotionEvent)}, {"dispatchKeyEvent", "(Landroid/view/KeyEvent;)Z", reinterpret_cast(dispatchKeyEvent)}, + {"sendRequestPermissionsResult", "(I[Ljava/lang/String;[I)V", reinterpret_cast(sendRequestPermissionsResult)}, }; const bool regOk = (env->RegisterNatives(jQtNative, methods, sizeof(methods) / sizeof(methods[0])) == JNI_OK); - env->DeleteLocalRef(jQtNative); + if (!regOk && QJniEnvironment::checkAndClearExceptions(env)) return JNI_ERR; @@ -284,9 +361,17 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env) if (!registerNativeInterfaceNatives()) return JNI_ERR; + g_runPendingCppRunnablesMethodID = env->GetStaticMethodID(jQtNative, + "runPendingCppRunnablesOnAndroidThread", + "()V"); + g_jNativeClass = static_cast(env->NewGlobalRef(jQtNative)); + env->DeleteLocalRef(jQtNative); + + qRegisterMetaType(); return JNI_OK; } + jobject QtAndroidPrivate::activity() { return g_jActivity; @@ -325,6 +410,110 @@ jint QtAndroidPrivate::androidSdkVersion() return sdkVersion; } +void QtAndroidPrivate::runOnAndroidThread(const QtAndroidPrivate::Runnable &runnable, JNIEnv *env) +{ + QMutexLocker locker(&g_pendingRunnablesMutex); + const bool triggerRun = g_pendingRunnables->empty(); + g_pendingRunnables->push_back(runnable); + locker.unlock(); + if (triggerRun) + env->CallStaticVoidMethod(g_jNativeClass, g_runPendingCppRunnablesMethodID); +} + +static bool waitForSemaphore(int timeoutMs, QSharedPointer sem) +{ + while (timeoutMs > 0) { + if (sem->tryAcquire(1, 10)) + return true; + timeoutMs -= 10; + QCoreApplication::processEvents(); + } + return false; +} + +void QtAndroidPrivate::runOnAndroidThreadSync(const QtAndroidPrivate::Runnable &runnable, JNIEnv *env, int timeoutMs) +{ + QSharedPointer sem(new QSemaphore); + runOnAndroidThread([&runnable, sem]{ + runnable(); + sem->release(); + }, env); + waitForSemaphore(timeoutMs, sem); +} + +void QtAndroidPrivate::requestPermissions(JNIEnv *env, + const QStringList &permissions, + const QtAndroidPrivate::PermissionsResultFunc &callbackFunc, + bool directCall) +{ + if (androidSdkVersion() < 23 || !activity()) { + QHash res; + for (const auto &perm : permissions) + res[perm] = checkPermission(perm); + callbackFunc(res); + return; + } + // Check API 23+ permissions + const int requestCode = nextRequestCode(); + if (!directCall) { + QMutexLocker locker(&g_pendingPermissionRequestsMutex); + (*g_pendingPermissionRequests)[requestCode] = new PermissionsResultClass(callbackFunc); + } + + runOnAndroidThread([permissions, callbackFunc, requestCode, directCall] { + if (directCall) { + QMutexLocker locker(&g_pendingPermissionRequestsMutex); + (*g_pendingPermissionRequests)[requestCode] = new PermissionsResultClass(callbackFunc); + } + + QJniEnvironment env; + jclass clazz = env->FindClass("java/lang/String"); + + if (env.checkAndClearExceptions()) + return; + + auto array = env->NewObjectArray(permissions.size(), clazz, nullptr); + int index = 0; + for (const auto &perm : permissions) + env->SetObjectArrayElement(array, index++, QJniObject::fromString(perm).object()); + QJniObject(activity()).callMethod("requestPermissions", "([Ljava/lang/String;I)V", array, requestCode); + env->DeleteLocalRef(array); + }, env); +} + +QtAndroidPrivate::PermissionsHash QtAndroidPrivate::requestPermissionsSync(JNIEnv *env, const QStringList &permissions, int timeoutMs) +{ + QSharedPointer> res(new QHash()); + QSharedPointer sem(new QSemaphore); + requestPermissions(env, permissions, [sem, res](const QHash &result){ + *res = result; + sem->release(); + }, true); + if (waitForSemaphore(timeoutMs, sem)) + return std::move(*res); + else // mustn't touch *res + return QHash(); +} + +QtAndroidPrivate::PermissionsResult QtAndroidPrivate::checkPermission(const QString &permission) +{ + const auto res = QJniObject::callStaticMethod("org/qtproject/qt/android/QtNative", + "checkSelfPermission", + "(Ljava/lang/String;)I", + QJniObject::fromString(permission).object()); + return res == PERMISSION_GRANTED ? PermissionsResult::Granted : PermissionsResult::Denied; +} + +bool QtAndroidPrivate::shouldShowRequestPermissionRationale(const QString &permission) +{ + if (androidSdkVersion() < 23 || !activity()) + return false; + + return QJniObject(activity()).callMethod("shouldShowRequestPermissionRationale", + "(Ljava/lang/String;)Z", + QJniObject::fromString(permission).object()); +} + void QtAndroidPrivate::registerGenericMotionEventListener(QtAndroidPrivate::GenericMotionEventListener *listener) { QMutexLocker locker(&g_genericMotionEventListeners()->mutex); @@ -349,6 +538,13 @@ void QtAndroidPrivate::unregisterKeyEventListener(QtAndroidPrivate::KeyEventList g_keyEventListeners()->listeners.removeOne(listener); } +void QtAndroidPrivate::hideSplashScreen(JNIEnv *env, int duration) +{ + Q_UNUSED(env) + QJniObject::callStaticMethod("org/qtproject/qt/android/QtNative", + "hideSplashScreen", "(I)V", duration); +} + void QtAndroidPrivate::waitForServiceSetup() { g_waitForServiceSetupSemaphore->acquire(); @@ -412,3 +608,5 @@ Q_CORE_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) return JNI_VERSION_1_6; } + +#include "qjnihelpers.moc" diff --git a/src/corelib/kernel/qjnihelpers_p.h b/src/corelib/kernel/qjnihelpers_p.h index 2860cef4c3..f858240602 100644 --- a/src/corelib/kernel/qjnihelpers_p.h +++ b/src/corelib/kernel/qjnihelpers_p.h @@ -54,9 +54,13 @@ #include #include #include +#include +#include QT_BEGIN_NAMESPACE +class QRunnable; + namespace QtAndroidPrivate { class Q_CORE_EXPORT ActivityResultListener @@ -102,6 +106,14 @@ namespace QtAndroidPrivate virtual jobject onBind(jobject intent) = 0; }; + enum class PermissionsResult { + Granted, + Denied + }; + typedef QHash PermissionsHash; + typedef std::function Runnable; + typedef std::function PermissionsResultFunc; + Q_CORE_EXPORT jobject activity(); Q_CORE_EXPORT jobject service(); Q_CORE_EXPORT jobject context(); @@ -110,6 +122,12 @@ namespace QtAndroidPrivate Q_CORE_EXPORT jclass findClass(const char *className, JNIEnv *env); jobject classLoader(); Q_CORE_EXPORT jint androidSdkVersion(); + Q_CORE_EXPORT void runOnAndroidThread(const Runnable &runnable, JNIEnv *env); + Q_CORE_EXPORT void runOnAndroidThreadSync(const Runnable &runnable, JNIEnv *env, int timeoutMs = INT_MAX); + Q_CORE_EXPORT void requestPermissions(JNIEnv *env, const QStringList &permissions, const PermissionsResultFunc &callbackFunc, bool directCall = false); + Q_CORE_EXPORT PermissionsHash requestPermissionsSync(JNIEnv *env, const QStringList &permissions, int timeoutMs = INT_MAX); + Q_CORE_EXPORT PermissionsResult checkPermission(const QString &permission); + Q_CORE_EXPORT bool shouldShowRequestPermissionRationale(const QString &permission); bool registerPermissionNatives(); bool registerNativeInterfaceNatives(); @@ -133,6 +151,9 @@ namespace QtAndroidPrivate Q_CORE_EXPORT void registerKeyEventListener(KeyEventListener *listener); Q_CORE_EXPORT void unregisterKeyEventListener(KeyEventListener *listener); + // TODO: Remove once other modules refectoring is done and androidextras is not needed. + Q_CORE_EXPORT void hideSplashScreen(JNIEnv *env, int duration = 0); + Q_CORE_EXPORT void waitForServiceSetup(); Q_CORE_EXPORT int acuqireServiceSetup(int flags); Q_CORE_EXPORT void setOnBindListener(OnBindListener *listener); @@ -180,4 +201,6 @@ namespace QtAndroidPrivate QT_END_NAMESPACE +Q_DECLARE_METATYPE(QtAndroidPrivate::PermissionsHash) + #endif // QJNIHELPERS_H