summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJani Heikkinen <jani.heikkinen@qt.io>2021-06-15 12:19:59 +0000
committerJani Heikkinen <jani.heikkinen@qt.io>2021-06-16 04:25:03 +0000
commit662bb0e83b76dc7e018b3540c19ac14b8af444ce (patch)
treecdbf616d358291364812a4f3f35bd7e53ea61a9b /src
parent50e77044a8f394e3409c8c429ff305b8df5df282 (diff)
Revert "Remove old Android code that have now has alternative public APIs"
This reverts commit ff7daa1c33b79d92837c1dca2f55089d8e5dbc80. Reason for revert: Breaks dependency update round now Change-Id: Ie52e9ac189e9516b27df389d6f624b22f939affb Reviewed-by: Antti Kokko <antti.kokko@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/CMakeLists.txt1
-rw-r--r--src/corelib/kernel/qjni.cpp2384
-rw-r--r--src/corelib/kernel/qjni_p.h292
-rw-r--r--src/corelib/kernel/qjnihelpers.cpp204
-rw-r--r--src/corelib/kernel/qjnihelpers_p.h23
5 files changed, 2901 insertions, 3 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index 52679b591f..ceb99c16ee 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -996,6 +996,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 <QtCore/qthreadstorage.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qstring.h>
+#include <QtCore/QThread>
+#include <QtCore/QReadWriteLock>
+
+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<jchar *>(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<QString, jclass> 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<QString, jclass>::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<QString, jclass>::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<jclass>(env->NewGlobalRef(classObject.object()));
+
+ cachedClasses->insert(key, clazz);
+ return clazz;
+}
+
+typedef QHash<QString, jmethodID> 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<QString, jmethodID>::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<QString, jfieldID> 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<QString, jfieldID>::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<QJNIEnvironmentPrivateTLS *>, 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<QString, jclass>::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<jclass>(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, "<init>", "()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, "<init>", 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, "<init>", 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<jclass>(env->NewGlobalRef(clazz));
+ if (d->m_jclass) {
+ // get default constructor
+ jmethodID constructorId = getMethodID(env, d->m_jclass, "<init>", "()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<jclass>(env->NewGlobalRef(clazz));
+ if (d->m_jclass) {
+ jmethodID constructorId = getMethodID(env, d->m_jclass, "<init>", 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<jclass>(env->NewGlobalRef(clazz));
+ if (d->m_jclass) {
+ jmethodID constructorId = getMethodID(env, d->m_jclass, "<init>", 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<jclass>(env->NewGlobalRef(cls));
+ env->DeleteLocalRef(cls);
+}
+template <>
+Q_CORE_EXPORT void QJNIObjectPrivate::callMethodV<void>(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<void>(const char *methodName, const char *sig, ...) const
+{
+ va_list args;
+ va_start(args, sig);
+ callMethodV<void>(methodName, sig, args);
+ va_end(args);
+}
+
+template <>
+Q_CORE_EXPORT jboolean QJNIObjectPrivate::callMethodV<jboolean>(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<jboolean>(const char *methodName, const char *sig, ...) const
+{
+ va_list args;
+ va_start(args, sig);
+ jboolean res = callMethodV<jboolean>(methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jbyte QJNIObjectPrivate::callMethodV<jbyte>(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<jbyte>(const char *methodName, const char *sig, ...) const
+{
+ va_list args;
+ va_start(args, sig);
+ jbyte res = callMethodV<jbyte>(methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jchar QJNIObjectPrivate::callMethodV<jchar>(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<jchar>(const char *methodName, const char *sig, ...) const
+{
+ va_list args;
+ va_start(args, sig);
+ jchar res = callMethodV<jchar>(methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jshort QJNIObjectPrivate::callMethodV<jshort>(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<jshort>(const char *methodName, const char *sig, ...) const
+{
+ va_list args;
+ va_start(args, sig);
+ jshort res = callMethodV<jshort>(methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jint QJNIObjectPrivate::callMethodV<jint>(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<jint>(const char *methodName, const char *sig, ...) const
+{
+ va_list args;
+ va_start(args, sig);
+ jint res = callMethodV<jint>(methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jlong QJNIObjectPrivate::callMethodV<jlong>(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<jlong>(const char *methodName, const char *sig, ...) const
+{
+ va_list args;
+ va_start(args, sig);
+ jlong res = callMethodV<jlong>(methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jfloat QJNIObjectPrivate::callMethodV<jfloat>(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<jfloat>(const char *methodName, const char *sig, ...) const
+{
+ va_list args;
+ va_start(args, sig);
+ jfloat res = callMethodV<jfloat>(methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jdouble QJNIObjectPrivate::callMethodV<jdouble>(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<jdouble>(const char *methodName, const char *sig, ...) const
+{
+ va_list args;
+ va_start(args, sig);
+ jdouble res = callMethodV<jdouble>(methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT void QJNIObjectPrivate::callMethod<void>(const char *methodName) const
+{
+ callMethod<void>(methodName, "()V");
+}
+
+template <>
+Q_CORE_EXPORT jboolean QJNIObjectPrivate::callMethod<jboolean>(const char *methodName) const
+{
+ return callMethod<jboolean>(methodName, "()Z");
+}
+
+template <>
+Q_CORE_EXPORT jbyte QJNIObjectPrivate::callMethod<jbyte>(const char *methodName) const
+{
+ return callMethod<jbyte>(methodName, "()B");
+}
+
+template <>
+Q_CORE_EXPORT jchar QJNIObjectPrivate::callMethod<jchar>(const char *methodName) const
+{
+ return callMethod<jchar>(methodName, "()C");
+}
+
+template <>
+Q_CORE_EXPORT jshort QJNIObjectPrivate::callMethod<jshort>(const char *methodName) const
+{
+ return callMethod<jshort>(methodName, "()S");
+}
+
+template <>
+Q_CORE_EXPORT jint QJNIObjectPrivate::callMethod<jint>(const char *methodName) const
+{
+ return callMethod<jint>(methodName, "()I");
+}
+
+template <>
+Q_CORE_EXPORT jlong QJNIObjectPrivate::callMethod<jlong>(const char *methodName) const
+{
+ return callMethod<jlong>(methodName, "()J");
+}
+
+template <>
+Q_CORE_EXPORT jfloat QJNIObjectPrivate::callMethod<jfloat>(const char *methodName) const
+{
+ return callMethod<jfloat>(methodName, "()F");
+}
+
+template <>
+Q_CORE_EXPORT jdouble QJNIObjectPrivate::callMethod<jdouble>(const char *methodName) const
+{
+ return callMethod<jdouble>(methodName, "()D");
+}
+
+template <>
+Q_CORE_EXPORT void QJNIObjectPrivate::callStaticMethodV<void>(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<void>(const char *className,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ va_list args;
+ va_start(args, sig);
+ callStaticMethodV<void>(className, methodName, sig, args);
+ va_end(args);
+}
+
+template <>
+Q_CORE_EXPORT void QJNIObjectPrivate::callStaticMethodV<void>(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<void>(jclass clazz,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ va_list args;
+ va_start(args, sig);
+ callStaticMethodV<void>(clazz, methodName, sig, args);
+ va_end(args);
+}
+
+template <>
+Q_CORE_EXPORT jboolean QJNIObjectPrivate::callStaticMethodV<jboolean>(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<jboolean>(const char *className,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ va_list args;
+ va_start(args, sig);
+ jboolean res = callStaticMethodV<jboolean>(className, methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jboolean QJNIObjectPrivate::callStaticMethodV<jboolean>(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<jboolean>(jclass clazz,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ va_list args;
+ va_start(args, sig);
+ jboolean res = callStaticMethodV<jboolean>(clazz, methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jbyte QJNIObjectPrivate::callStaticMethodV<jbyte>(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<jbyte>(const char *className,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ va_list args;
+ va_start(args, sig);
+ jbyte res = callStaticMethodV<jbyte>(className, methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jbyte QJNIObjectPrivate::callStaticMethodV<jbyte>(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<jbyte>(jclass clazz,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ va_list args;
+ va_start(args, sig);
+ jbyte res = callStaticMethodV<jbyte>(clazz, methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jchar QJNIObjectPrivate::callStaticMethodV<jchar>(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<jchar>(const char *className,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ va_list args;
+ va_start(args, sig);
+ jchar res = callStaticMethodV<jchar>(className, methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jchar QJNIObjectPrivate::callStaticMethodV<jchar>(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<jchar>(jclass clazz,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ va_list args;
+ va_start(args, sig);
+ jchar res = callStaticMethodV<jchar>(clazz, methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jshort QJNIObjectPrivate::callStaticMethodV<jshort>(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<jshort>(const char *className,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ va_list args;
+ va_start(args, sig);
+ jshort res = callStaticMethodV<jshort>(className, methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jshort QJNIObjectPrivate::callStaticMethodV<jshort>(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<jshort>(jclass clazz,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ va_list args;
+ va_start(args, sig);
+ jshort res = callStaticMethodV<jshort>(clazz, methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jint QJNIObjectPrivate::callStaticMethodV<jint>(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<jint>(const char *className,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ va_list args;
+ va_start(args, sig);
+ jint res = callStaticMethodV<jint>(className, methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jint QJNIObjectPrivate::callStaticMethodV<jint>(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<jint>(jclass clazz,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ va_list args;
+ va_start(args, sig);
+ jint res = callStaticMethodV<jint>(clazz, methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jlong QJNIObjectPrivate::callStaticMethodV<jlong>(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<jlong>(const char *className,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ va_list args;
+ va_start(args, sig);
+ jlong res = callStaticMethodV<jlong>(className, methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jlong QJNIObjectPrivate::callStaticMethodV<jlong>(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<jlong>(jclass clazz,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ va_list args;
+ va_start(args, sig);
+ jlong res = callStaticMethodV<jlong>(clazz, methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jfloat QJNIObjectPrivate::callStaticMethodV<jfloat>(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<jfloat>(const char *className,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ va_list args;
+ va_start(args, sig);
+ jfloat res = callStaticMethodV<jfloat>(className, methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jfloat QJNIObjectPrivate::callStaticMethodV<jfloat>(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<jfloat>(jclass clazz,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ va_list args;
+ va_start(args, sig);
+ jfloat res = callStaticMethodV<jfloat>(clazz, methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jdouble QJNIObjectPrivate::callStaticMethodV<jdouble>(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<jdouble>(const char *className,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ va_list args;
+ va_start(args, sig);
+ jdouble res = callStaticMethodV<jdouble>(className, methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT jdouble QJNIObjectPrivate::callStaticMethodV<jdouble>(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<jdouble>(jclass clazz,
+ const char *methodName,
+ const char *sig,
+ ...)
+{
+ va_list args;
+ va_start(args, sig);
+ jdouble res = callStaticMethodV<jdouble>(clazz, methodName, sig, args);
+ va_end(args);
+ return res;
+}
+
+template <>
+Q_CORE_EXPORT void QJNIObjectPrivate::callStaticMethod<void>(const char *className, const char *methodName)
+{
+ callStaticMethod<void>(className, methodName, "()V");
+}
+
+template <>
+Q_CORE_EXPORT void QJNIObjectPrivate::callStaticMethod<void>(jclass clazz, const char *methodName)
+{
+ callStaticMethod<void>(clazz, methodName, "()V");
+}
+
+template <>
+Q_CORE_EXPORT jboolean QJNIObjectPrivate::callStaticMethod<jboolean>(const char *className, const char *methodName)
+{
+ return callStaticMethod<jboolean>(className, methodName, "()Z");
+}
+
+template <>
+Q_CORE_EXPORT jboolean QJNIObjectPrivate::callStaticMethod<jboolean>(jclass clazz, const char *methodName)
+{
+ return callStaticMethod<jboolean>(clazz, methodName, "()Z");
+}
+
+template <>
+Q_CORE_EXPORT jbyte QJNIObjectPrivate::callStaticMethod<jbyte>(const char *className, const char *methodName)
+{
+ return callStaticMethod<jbyte>(className, methodName, "()B");
+}
+
+template <>
+Q_CORE_EXPORT jbyte QJNIObjectPrivate::callStaticMethod<jbyte>(jclass clazz, const char *methodName)
+{
+ return callStaticMethod<jbyte>(clazz, methodName, "()B");
+}
+
+template <>
+Q_CORE_EXPORT jchar QJNIObjectPrivate::callStaticMethod<jchar>(const char *className, const char *methodName)
+{
+ return callStaticMethod<jchar>(className, methodName, "()C");
+}
+
+template <>
+Q_CORE_EXPORT jchar QJNIObjectPrivate::callStaticMethod<jchar>(jclass clazz, const char *methodName)
+{
+ return callStaticMethod<jchar>(clazz, methodName, "()C");
+}
+
+template <>
+Q_CORE_EXPORT jshort QJNIObjectPrivate::callStaticMethod<jshort>(const char *className, const char *methodName)
+{
+ return callStaticMethod<jshort>(className, methodName, "()S");
+}
+
+template <>
+Q_CORE_EXPORT jshort QJNIObjectPrivate::callStaticMethod<jshort>(jclass clazz, const char *methodName)
+{
+ return callStaticMethod<jshort>(clazz, methodName, "()S");
+}
+
+template <>
+Q_CORE_EXPORT jint QJNIObjectPrivate::callStaticMethod<jint>(const char *className, const char *methodName)
+{
+ return callStaticMethod<jint>(className, methodName, "()I");
+}
+
+template <>
+Q_CORE_EXPORT jint QJNIObjectPrivate::callStaticMethod<jint>(jclass clazz, const char *methodName)
+{
+ return callStaticMethod<jint>(clazz, methodName, "()I");
+}
+
+template <>
+Q_CORE_EXPORT jlong QJNIObjectPrivate::callStaticMethod<jlong>(const char *className, const char *methodName)
+{
+ return callStaticMethod<jlong>(className, methodName, "()J");
+}
+
+template <>
+Q_CORE_EXPORT jlong QJNIObjectPrivate::callStaticMethod<jlong>(jclass clazz, const char *methodName)
+{
+ return callStaticMethod<jlong>(clazz, methodName, "()J");
+}
+
+template <>
+Q_CORE_EXPORT jfloat QJNIObjectPrivate::callStaticMethod<jfloat>(const char *className, const char *methodName)
+{
+ return callStaticMethod<jfloat>(className, methodName, "()F");
+}
+
+template <>
+Q_CORE_EXPORT jfloat QJNIObjectPrivate::callStaticMethod<jfloat>(jclass clazz, const char *methodName)
+{
+ return callStaticMethod<jfloat>(clazz, methodName, "()F");
+}
+
+template <>
+Q_CORE_EXPORT jdouble QJNIObjectPrivate::callStaticMethod<jdouble>(const char *className, const char *methodName)
+{
+ return callStaticMethod<jdouble>(className, methodName, "()D");
+}
+
+template <>
+Q_CORE_EXPORT jdouble QJNIObjectPrivate::callStaticMethod<jdouble>(jclass clazz, const char *methodName)
+{
+ return callStaticMethod<jdouble>(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<jstring>(const char *methodName) const
+{
+ return callObjectMethod(methodName, "()Ljava/lang/String;");
+}
+
+template <>
+Q_CORE_EXPORT QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod<jbooleanArray>(const char *methodName) const
+{
+ return callObjectMethod(methodName, "()[Z");
+}
+
+template <>
+Q_CORE_EXPORT QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod<jbyteArray>(const char *methodName) const
+{
+ return callObjectMethod(methodName, "()[B");
+}
+
+template <>
+Q_CORE_EXPORT QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod<jshortArray>(const char *methodName) const
+{
+ return callObjectMethod(methodName, "()[S");
+}
+
+template <>
+Q_CORE_EXPORT QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod<jintArray>(const char *methodName) const
+{
+ return callObjectMethod(methodName, "()[I");
+}
+
+template <>
+Q_CORE_EXPORT QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod<jlongArray>(const char *methodName) const
+{
+ return callObjectMethod(methodName, "()[J");
+}
+
+template <>
+Q_CORE_EXPORT QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod<jfloatArray>(const char *methodName) const
+{
+ return callObjectMethod(methodName, "()[F");
+}
+
+template <>
+Q_CORE_EXPORT QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod<jdoubleArray>(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<jboolean>(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<jbyte>(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<jchar>(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<jshort>(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<jint>(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<jlong>(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<jfloat>(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<jdouble>(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<jboolean>(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<jboolean>(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<jbyte>(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<jbyte>(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<jchar>(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<jchar>(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<jshort>(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<jshort>(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<jint>(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<jint>(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<jlong>(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<jlong>(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<jfloat>(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<jfloat>(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<jdouble>(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<jdouble>(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<jboolean>(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<jbyte>(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<jchar>(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<jshort>(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<jint>(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<jlong>(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<jfloat>(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<jdouble>(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<jbooleanArray>(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<jbyteArray>(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<jcharArray>(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<jshortArray>(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<jintArray>(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<jlongArray>(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<jfloatArray>(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<jdoubleArray>(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<jstring>(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<jobject>(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<jobjectArray>(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<jboolean>(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<jboolean>(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<jbyte>(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<jbyte>(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<jchar>(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<jchar>(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<jshort>(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<jshort>(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<jint>(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<jint>(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<jlong>(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<jlong>(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<jfloat>(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<jfloat>(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<jdouble>(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<jdouble>(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<jobject>(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<jobject>(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<const jchar*>(string.constData()),
+ string.length());
+ QJNIObjectPrivate obj(res);
+ env->DeleteLocalRef(res);
+ return obj;
+}
+
+QString QJNIObjectPrivate::toString() const
+{
+ if (!isValid())
+ return QString();
+
+ QJNIObjectPrivate string = callObjectMethod<jstring>("toString");
+ return qt_convertJString(static_cast<jstring>(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 <jni.h>
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/qsharedpointer.h>
+
+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 <typename T>
+ T callMethod(const char *methodName,
+ const char *sig,
+ ...) const;
+ template <typename T>
+ T callMethod(const char *methodName) const;
+ template <typename T>
+ QJNIObjectPrivate callObjectMethod(const char *methodName) const;
+ QJNIObjectPrivate callObjectMethod(const char *methodName,
+ const char *sig,
+ ...) const;
+ template <typename T>
+ static T callStaticMethod(const char *className,
+ const char *methodName,
+ const char *sig, ...);
+ template <typename T>
+ static T callStaticMethod(const char *className,
+ const char *methodName);
+ template <typename T>
+ static T callStaticMethod(jclass clazz,
+ const char *methodName,
+ const char *sig, ...);
+ template <typename T>
+ 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 <typename T>
+ T getField(const char *fieldName) const;
+ template <typename T>
+ static T getStaticField(const char *className, const char *fieldName);
+ template <typename T>
+ 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 <typename T>
+ void setField(const char *fieldName, T value);
+ template <typename T>
+ void setField(const char *fieldName, const char *sig, T value);
+ template <typename T>
+ static void setStaticField(const char *className,
+ const char *fieldName,
+ T value);
+ template <typename T>
+ static void setStaticField(const char *className,
+ const char *fieldName,
+ const char *sig,
+ T value);
+ template <typename T>
+ static void setStaticField(jclass clazz,
+ const char *fieldName,
+ const char *sig,
+ T value);
+
+ template <typename T>
+ 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 <typename T>
+ inline QJNIObjectPrivate &operator=(T o)
+ {
+ jobject jobj = static_cast<jobject>(o);
+ if (!isSameObject(jobj)) {
+ d = QSharedPointer<QJNIObjectData>::create();
+ if (jobj) {
+ QJNIEnvironmentPrivate env;
+ d->m_jobject = env->NewGlobalRef(jobj);
+ jclass objectClass = env->GetObjectClass(jobj);
+ d->m_jclass = static_cast<jclass>(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 <typename T>
+ 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 <typename T>
+ static T callStaticMethodV(const char *className,
+ const char *methodName,
+ const char *sig,
+ va_list args);
+ template <typename T>
+ 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 <typename T> friend bool operator!=(const QJNIObjectPrivate&, T);
+ template <typename T> friend bool operator==(const QJNIObjectPrivate&, T);
+ template <typename T> friend bool operator!=(T, const QJNIObjectPrivate&);
+ template <typename T> friend bool operator==(T, const QJNIObjectPrivate&);
+
+ QSharedPointer<QJNIObjectData> 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 <typename T>
+inline bool operator==(const QJNIObjectPrivate &obj1, T obj2)
+{
+ return obj1.isSameObject(static_cast<jobject>(obj2));
+}
+
+template <typename T>
+inline bool operator==(T obj1, const QJNIObjectPrivate &obj2)
+{
+ return obj2.isSameObject(static_cast<jobject>(obj1));
+}
+
+template <typename T>
+inline bool operator!=(const QJNIObjectPrivate &obj1, T obj2)
+{
+ return !obj1.isSameObject(obj2);
+}
+
+template <typename T>
+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 <QtCore/private/qcoreapplication_p.h>
+#include <QtCore/qrunnable.h>
#include <android/log.h>
#include <deque>
@@ -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<QtAndroidPrivate::Runnable>, 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<int, PermissionsResultClass*> 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<QtAndroidPrivate::GenericMotionEventListener *> 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<jint[]> 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<void *>(runPendingCppRunnables)},
{"dispatchGenericMotionEvent", "(Landroid/view/MotionEvent;)Z", reinterpret_cast<void *>(dispatchGenericMotionEvent)},
{"dispatchKeyEvent", "(Landroid/view/KeyEvent;)Z", reinterpret_cast<void *>(dispatchKeyEvent)},
+ {"sendRequestPermissionsResult", "(I[Ljava/lang/String;[I)V", reinterpret_cast<void *>(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<jclass>(env->NewGlobalRef(jQtNative));
+ env->DeleteLocalRef(jQtNative);
+
+ qRegisterMetaType<QtAndroidPrivate::PermissionsHash>();
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<QSemaphore> 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<QSemaphore> 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<QString, QtAndroidPrivate::PermissionsResult> 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<void>("requestPermissions", "([Ljava/lang/String;I)V", array, requestCode);
+ env->DeleteLocalRef(array);
+ }, env);
+}
+
+QtAndroidPrivate::PermissionsHash QtAndroidPrivate::requestPermissionsSync(JNIEnv *env, const QStringList &permissions, int timeoutMs)
+{
+ QSharedPointer<QHash<QString, QtAndroidPrivate::PermissionsResult>> res(new QHash<QString, QtAndroidPrivate::PermissionsResult>());
+ QSharedPointer<QSemaphore> sem(new QSemaphore);
+ requestPermissions(env, permissions, [sem, res](const QHash<QString, PermissionsResult> &result){
+ *res = result;
+ sem->release();
+ }, true);
+ if (waitForSemaphore(timeoutMs, sem))
+ return std::move(*res);
+ else // mustn't touch *res
+ return QHash<QString, QtAndroidPrivate::PermissionsResult>();
+}
+
+QtAndroidPrivate::PermissionsResult QtAndroidPrivate::checkPermission(const QString &permission)
+{
+ const auto res = QJniObject::callStaticMethod<jint>("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<jboolean>("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<void>("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 <jni.h>
#include <functional>
#include <QtCore/private/qglobal_p.h>
+#include <QHash>
+#include <QMetaType>
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<QString, QtAndroidPrivate::PermissionsResult> PermissionsHash;
+ typedef std::function<void()> Runnable;
+ typedef std::function<void(const PermissionsHash &)> 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