From afece6e49697983e7fd55647e1674504f7bc7235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Wed, 6 Aug 2014 17:24:52 +0200 Subject: [PATCH] Android: Add findClass() function to the QJNIEnvironmentPrivate class. The static QJNIEnvironmentPrivate::findClass() function exposes the cache and the class finding code in qjni. Change-Id: I42043dc993cf9cace042faf763f2a647ba79d97f Reviewed-by: Paul Olav Tvete Reviewed-by: BogDan Vatra --- src/corelib/kernel/qjni.cpp | 138 ++++++++++++------ src/corelib/kernel/qjni_p.h | 1 + .../platforms/android/androidjnimain.cpp | 8 - .../platforms/android/androidjnimain.h | 1 - .../android/qandroidinputcontext.cpp | 32 ++-- .../android/qandroidplatformdialoghelpers.cpp | 6 +- 6 files changed, 110 insertions(+), 76 deletions(-) diff --git a/src/corelib/kernel/qjni.cpp b/src/corelib/kernel/qjni.cpp index 46e7d739fb..173127b063 100644 --- a/src/corelib/kernel/qjni.cpp +++ b/src/corelib/kernel/qjni.cpp @@ -75,28 +75,58 @@ static inline bool exceptionCheckAndClear(JNIEnv *env) typedef QHash JClassHash; Q_GLOBAL_STATIC(JClassHash, cachedClasses) -static jclass getCachedClass(JNIEnv *env, const char *className) +static QString toDotEncodedClassName(const char *className) +{ + return QString::fromLatin1(className).replace(QLatin1Char('/'), QLatin1Char('.')); +} + +static jclass getCachedClass(const QString &classDotEnc) { - jclass clazz = 0; - QString classDotEnc = QString::fromLatin1(className).replace(QLatin1Char('/'), QLatin1Char('.')); QHash::iterator it = cachedClasses->find(classDotEnc); - if (it == cachedClasses->end()) { - QJNIObjectPrivate classLoader = QtAndroidPrivate::classLoader(); - if (!classLoader.isValid()) - return 0; - QJNIObjectPrivate stringName = QJNIObjectPrivate::fromString(classDotEnc); - QJNIObjectPrivate classObject = classLoader.callObjectMethod("loadClass", - "(Ljava/lang/String;)Ljava/lang/Class;", - stringName.object()); + if (it == cachedClasses->end()) + return 0; - if (!exceptionCheckAndClear(env) && classObject.isValid()) - clazz = static_cast(env->NewGlobalRef(classObject.object())); + return it.value(); +} - cachedClasses->insert(classDotEnc, clazz); - } else { - clazz = it.value(); +static jclass findClass(const char *className, JNIEnv *env) +{ + const QString &classDotEnc = toDotEncodedClassName(className); + jclass clazz = getCachedClass(classDotEnc); + if (clazz != 0) + return clazz; + + jclass fclazz = env->FindClass(className); + if (!exceptionCheckAndClear(env)) { + clazz = static_cast(env->NewGlobalRef(fclazz)); + env->DeleteLocalRef(fclazz); } + + cachedClasses->insert(classDotEnc, clazz); + return clazz; +} + +static jclass loadClass(const char *className, JNIEnv *env) +{ + const QString &classDotEnc = toDotEncodedClassName(className); + jclass clazz = getCachedClass(classDotEnc); + if (clazz != 0) + return clazz; + + QJNIObjectPrivate classLoader = QtAndroidPrivate::classLoader(); + if (!classLoader.isValid()) + return 0; + + QJNIObjectPrivate stringName = QJNIObjectPrivate::fromString(classDotEnc); + 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(classDotEnc, clazz); return clazz; } @@ -192,6 +222,18 @@ JNIEnv *QJNIEnvironmentPrivate::operator->() return jniEnv; } +jclass QJNIEnvironmentPrivate::findClass(const char *className, JNIEnv *env) +{ + jclass clazz = 0; + if (env != 0) + clazz = ::findClass(className, env); + + if (clazz == 0) + clazz = loadClass(className, QJNIEnvironmentPrivate()); + + return clazz; +} + QJNIEnvironmentPrivate::operator JNIEnv* () const { return jniEnv; @@ -228,7 +270,7 @@ QJNIObjectPrivate::QJNIObjectPrivate(const char *className) : d(new QJNIObjectData()) { QJNIEnvironmentPrivate env; - d->m_jclass = getCachedClass(env, className); + d->m_jclass = loadClass(className, env); d->m_own_jclass = false; if (d->m_jclass) { // get default constructor @@ -247,7 +289,7 @@ QJNIObjectPrivate::QJNIObjectPrivate(const char *className, const char *sig, ... : d(new QJNIObjectData()) { QJNIEnvironmentPrivate env; - d->m_jclass = getCachedClass(env, className); + d->m_jclass = loadClass(className, env); d->m_own_jclass = false; if (d->m_jclass) { jmethodID constructorId = getCachedMethodID(env, d->m_jclass, "", sig); @@ -268,7 +310,7 @@ QJNIObjectPrivate::QJNIObjectPrivate(const char *className, const char *sig, va_ : d(new QJNIObjectData()) { QJNIEnvironmentPrivate env; - d->m_jclass = getCachedClass(env, className); + d->m_jclass = loadClass(className, env); d->m_own_jclass = false; if (d->m_jclass) { jmethodID constructorId = getCachedMethodID(env, d->m_jclass, "", sig); @@ -610,7 +652,7 @@ void QJNIObjectPrivate::callStaticMethod(const char *className, va_list args) { QJNIEnvironmentPrivate env; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) { jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); if (id) { @@ -664,7 +706,7 @@ jboolean QJNIObjectPrivate::callStaticMethod(const char *className, { QJNIEnvironmentPrivate env; jboolean res = 0; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) { jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); if (id) { @@ -725,7 +767,7 @@ jbyte QJNIObjectPrivate::callStaticMethod(const char *className, { QJNIEnvironmentPrivate env; jbyte res = 0; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) { jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); if (id) { @@ -786,7 +828,7 @@ jchar QJNIObjectPrivate::callStaticMethod(const char *className, { QJNIEnvironmentPrivate env; jchar res = 0; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) { jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); if (id) { @@ -847,7 +889,7 @@ jshort QJNIObjectPrivate::callStaticMethod(const char *className, { QJNIEnvironmentPrivate env; jshort res = 0; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) { jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); if (id) { @@ -908,7 +950,7 @@ jint QJNIObjectPrivate::callStaticMethod(const char *className, { QJNIEnvironmentPrivate env; jint res = 0; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) { jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); if (id) { @@ -969,7 +1011,7 @@ jlong QJNIObjectPrivate::callStaticMethod(const char *className, { QJNIEnvironmentPrivate env; jlong res = 0; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) { jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); if (id) { @@ -1030,7 +1072,7 @@ jfloat QJNIObjectPrivate::callStaticMethod(const char *className, { QJNIEnvironmentPrivate env; jfloat res = 0.f; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) { jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); if (id) { @@ -1091,7 +1133,7 @@ jdouble QJNIObjectPrivate::callStaticMethod(const char *className, { QJNIEnvironmentPrivate env; jdouble res = 0.; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) { jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); if (id) { @@ -1336,7 +1378,7 @@ QJNIObjectPrivate QJNIObjectPrivate::callStaticObjectMethod(const char *classNam { QJNIEnvironmentPrivate env; jobject res = 0; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) { jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); if (id) { @@ -1507,7 +1549,7 @@ jboolean QJNIObjectPrivate::getStaticField(const char *className, cons { QJNIEnvironmentPrivate env; jboolean res = 0; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) res = getStaticField(clazz, fieldName); @@ -1531,7 +1573,7 @@ jbyte QJNIObjectPrivate::getStaticField(const char *className, const char { QJNIEnvironmentPrivate env; jbyte res = 0; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) res = getStaticField(clazz, fieldName); @@ -1555,7 +1597,7 @@ jchar QJNIObjectPrivate::getStaticField(const char *className, const char { QJNIEnvironmentPrivate env; jchar res = 0; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) res = getStaticField(clazz, fieldName); @@ -1579,7 +1621,7 @@ jshort QJNIObjectPrivate::getStaticField(const char *className, const ch { QJNIEnvironmentPrivate env; jshort res = 0; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) res = getStaticField(clazz, fieldName); @@ -1603,7 +1645,7 @@ jint QJNIObjectPrivate::getStaticField(const char *className, const char * { QJNIEnvironmentPrivate env; jint res = 0; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) res = getStaticField(clazz, fieldName); @@ -1627,7 +1669,7 @@ jlong QJNIObjectPrivate::getStaticField(const char *className, const char { QJNIEnvironmentPrivate env; jlong res = 0; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) res = getStaticField(clazz, fieldName); @@ -1651,7 +1693,7 @@ jfloat QJNIObjectPrivate::getStaticField(const char *className, const ch { QJNIEnvironmentPrivate env; jfloat res = 0.f; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) res = getStaticField(clazz, fieldName); @@ -1675,7 +1717,7 @@ jdouble QJNIObjectPrivate::getStaticField(const char *className, const { QJNIEnvironmentPrivate env; jdouble res = 0.; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) res = getStaticField(clazz, fieldName); @@ -1705,7 +1747,7 @@ QJNIObjectPrivate QJNIObjectPrivate::getStaticObjectField(const char *className, { QJNIEnvironmentPrivate env; QJNIObjectPrivate res; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) res = getStaticObjectField(clazz, fieldName, sig); @@ -1941,7 +1983,7 @@ void QJNIObjectPrivate::setStaticField(const char *className, jboolean value) { QJNIEnvironmentPrivate env; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) setStaticField(clazz, fieldName, value); } @@ -1963,7 +2005,7 @@ void QJNIObjectPrivate::setStaticField(const char *className, jbyte value) { QJNIEnvironmentPrivate env; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) setStaticField(clazz, fieldName, value); } @@ -1985,7 +2027,7 @@ void QJNIObjectPrivate::setStaticField(const char *className, jchar value) { QJNIEnvironmentPrivate env; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) setStaticField(clazz, fieldName, value); } @@ -2007,7 +2049,7 @@ void QJNIObjectPrivate::setStaticField(const char *className, jshort value) { QJNIEnvironmentPrivate env; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) setStaticField(clazz, fieldName, value); } @@ -2029,7 +2071,7 @@ void QJNIObjectPrivate::setStaticField(const char *className, jint value) { QJNIEnvironmentPrivate env; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) setStaticField(clazz, fieldName, value); } @@ -2051,7 +2093,7 @@ void QJNIObjectPrivate::setStaticField(const char *className, jlong value) { QJNIEnvironmentPrivate env; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) setStaticField(clazz, fieldName, value); } @@ -2073,7 +2115,7 @@ void QJNIObjectPrivate::setStaticField(const char *className, jfloat value) { QJNIEnvironmentPrivate env; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) setStaticField(clazz, fieldName, value); } @@ -2095,7 +2137,7 @@ void QJNIObjectPrivate::setStaticField(const char *className, jdouble value) { QJNIEnvironmentPrivate env; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) setStaticField(clazz, fieldName, value); } @@ -2119,7 +2161,7 @@ void QJNIObjectPrivate::setStaticField(const char *className, jobject value) { QJNIEnvironmentPrivate env; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); if (clazz) setStaticField(clazz, fieldName, sig, value); } @@ -2150,7 +2192,7 @@ bool QJNIObjectPrivate::isClassAvailable(const char *className) if (!env) return false; - jclass clazz = getCachedClass(env, className); + jclass clazz = loadClass(className, env); return (clazz != 0); } diff --git a/src/corelib/kernel/qjni_p.h b/src/corelib/kernel/qjni_p.h index 528872aa9b..19f2cf7601 100644 --- a/src/corelib/kernel/qjni_p.h +++ b/src/corelib/kernel/qjni_p.h @@ -58,6 +58,7 @@ public: ~QJNIEnvironmentPrivate(); JNIEnv *operator->(); operator JNIEnv*() const; + static jclass findClass(const char *className, JNIEnv *env = 0); private: friend class QAndroidJniEnvironment; diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 17a587b333..e068a43241 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -162,14 +162,6 @@ namespace QtAndroid return m_javaVM; } - jclass findClass(const QString &className, JNIEnv *env) - { - return static_cast(env->CallObjectMethod(m_classLoaderObject, - m_loadClassMethodID, - env->NewString(reinterpret_cast(className.constData()), - jsize(className.length())))); - } - AAssetManager *assetManager() { return m_assetManager; diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h index 3e226b13c2..7f762c8108 100644 --- a/src/plugins/platforms/android/androidjnimain.h +++ b/src/plugins/platforms/android/androidjnimain.h @@ -70,7 +70,6 @@ namespace QtAndroid int desktopHeightPixels(); double scaledDensity(); JavaVM *javaVM(); - jclass findClass(const QString &className, JNIEnv *env); AAssetManager *assetManager(); jclass applicationClass(); jobject activity(); diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index 5ff13902ac..abda72e636 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include @@ -53,8 +54,8 @@ QT_BEGIN_NAMESPACE static QAndroidInputContext *m_androidInputContext = 0; -static char const *const QtNativeInputConnectionClassName = "org.qtproject.qt5.android.QtNativeInputConnection"; -static char const *const QtExtractedTextClassName = "org.qtproject.qt5.android.QtExtractedText"; +static char const *const QtNativeInputConnectionClassName = "org/qtproject/qt5/android/QtNativeInputConnection"; +static char const *const QtExtractedTextClassName = "org/qtproject/qt5/android/QtExtractedText"; static jclass m_extractedTextClass = 0; static jmethodID m_classConstructorMethodID = 0; static jfieldID m_partialEndOffsetFieldID = 0; @@ -334,11 +335,7 @@ static JNINativeMethod methods[] = { QAndroidInputContext::QAndroidInputContext() : QPlatformInputContext(), m_composingTextStart(-1), m_blockUpdateSelection(false), m_batchEditNestingLevel(0), m_focusObject(0) { - QtAndroid::AttachedJNIEnv env; - if (!env.jniEnv) - return; - - jclass clazz = QtAndroid::findClass(QtNativeInputConnectionClassName, env.jniEnv); + jclass clazz = QJNIEnvironmentPrivate::findClass(QtNativeInputConnectionClassName); if (clazz == NULL) { qCritical() << "Native registration unable to find class '" << QtNativeInputConnectionClassName @@ -346,14 +343,15 @@ QAndroidInputContext::QAndroidInputContext() return; } - if (env.jniEnv->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0) { + QJNIEnvironmentPrivate env; + if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0) { qCritical() << "RegisterNatives failed for '" << QtNativeInputConnectionClassName << "'"; return; } - clazz = QtAndroid::findClass(QtExtractedTextClassName, env.jniEnv); + clazz = QJNIEnvironmentPrivate::findClass(QtExtractedTextClassName); if (clazz == NULL) { qCritical() << "Native registration unable to find class '" << QtExtractedTextClassName @@ -361,44 +359,44 @@ QAndroidInputContext::QAndroidInputContext() return; } - m_extractedTextClass = static_cast(env.jniEnv->NewGlobalRef(clazz)); - m_classConstructorMethodID = env.jniEnv->GetMethodID(m_extractedTextClass, "", "()V"); + m_extractedTextClass = static_cast(env->NewGlobalRef(clazz)); + m_classConstructorMethodID = env->GetMethodID(m_extractedTextClass, "", "()V"); if (m_classConstructorMethodID == NULL) { qCritical() << "GetMethodID failed"; return; } - m_partialEndOffsetFieldID = env.jniEnv->GetFieldID(m_extractedTextClass, "partialEndOffset", "I"); + m_partialEndOffsetFieldID = env->GetFieldID(m_extractedTextClass, "partialEndOffset", "I"); if (m_partialEndOffsetFieldID == NULL) { qCritical() << "Can't find field partialEndOffset"; return; } - m_partialStartOffsetFieldID = env.jniEnv->GetFieldID(m_extractedTextClass, "partialStartOffset", "I"); + m_partialStartOffsetFieldID = env->GetFieldID(m_extractedTextClass, "partialStartOffset", "I"); if (m_partialStartOffsetFieldID == NULL) { qCritical() << "Can't find field partialStartOffset"; return; } - m_selectionEndFieldID = env.jniEnv->GetFieldID(m_extractedTextClass, "selectionEnd", "I"); + m_selectionEndFieldID = env->GetFieldID(m_extractedTextClass, "selectionEnd", "I"); if (m_selectionEndFieldID == NULL) { qCritical() << "Can't find field selectionEnd"; return; } - m_selectionStartFieldID = env.jniEnv->GetFieldID(m_extractedTextClass, "selectionStart", "I"); + m_selectionStartFieldID = env->GetFieldID(m_extractedTextClass, "selectionStart", "I"); if (m_selectionStartFieldID == NULL) { qCritical() << "Can't find field selectionStart"; return; } - m_startOffsetFieldID = env.jniEnv->GetFieldID(m_extractedTextClass, "startOffset", "I"); + m_startOffsetFieldID = env->GetFieldID(m_extractedTextClass, "startOffset", "I"); if (m_startOffsetFieldID == NULL) { qCritical() << "Can't find field startOffset"; return; } - m_textFieldID = env.jniEnv->GetFieldID(m_extractedTextClass, "text", "Ljava/lang/String;"); + m_textFieldID = env->GetFieldID(m_extractedTextClass, "text", "Ljava/lang/String;"); if (m_textFieldID == NULL) { qCritical() << "Can't find field text"; return; diff --git a/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp index 5f2a877ed3..2ea4c90324 100644 --- a/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp +++ b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp @@ -44,6 +44,8 @@ QT_BEGIN_NAMESPACE namespace QtAndroidDialogHelpers { static jclass g_messageDialogHelperClass = 0; +static const char QtMessageHandlerHelperClassName[] = "org/qtproject/qt5/android/QtMessageDialogHelper"; + QAndroidPlatformMessageDialogHelper::QAndroidPlatformMessageDialogHelper() :m_buttonId(-1) ,m_javaMessageDialog(g_messageDialogHelperClass, "(Landroid/app/Activity;)V", QtAndroid::activity()) @@ -148,10 +150,10 @@ static JNINativeMethod methods[] = { bool registerNatives(JNIEnv *env) { - jclass clazz = QtAndroid::findClass("org.qtproject.qt5.android.QtMessageDialogHelper", env); + jclass clazz = QJNIEnvironmentPrivate::findClass(QtMessageHandlerHelperClassName, env); if (!clazz) { __android_log_print(ANDROID_LOG_FATAL, QtAndroid::qtTagText(), QtAndroid::classErrorMsgFmt() - , "org/qtproject/qt5/android/QtMessageDialogHelper"); + , QtMessageHandlerHelperClassName); return false; } g_messageDialogHelperClass = static_cast(env->NewGlobalRef(clazz));