diff --git a/src/corelib/kernel/qcoreapplication_platform.h b/src/corelib/kernel/qcoreapplication_platform.h index 9807cb7817..fe0fee915b 100644 --- a/src/corelib/kernel/qcoreapplication_platform.h +++ b/src/corelib/kernel/qcoreapplication_platform.h @@ -18,6 +18,7 @@ #include #if defined(Q_OS_ANDROID) || defined(Q_CLANG_QDOC) +#include #if QT_CONFIG(future) && !defined(QT_NO_QOBJECT) #include #include @@ -31,13 +32,21 @@ typedef _jobject* jobject; QT_BEGIN_NAMESPACE +#if defined(Q_OS_ANDROID) +Q_DECLARE_JNI_TYPE(Context, "Landroid/content/Context;") +#endif + namespace QNativeInterface { #if defined(Q_OS_ANDROID) || defined(Q_CLANG_QDOC) struct Q_CORE_EXPORT QAndroidApplication { QT_DECLARE_NATIVE_INTERFACE(QAndroidApplication, 1, QCoreApplication) +#ifdef Q_CLANG_QDOC static jobject context(); +#else + static QtJniTypes::Context context(); +#endif static bool isActivityContext(); static int sdkVersion(); static void hideSplashScreen(int duration = 0); diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp index 6954ed1193..ec6a7a58a3 100644 --- a/src/corelib/kernel/qjnihelpers.cpp +++ b/src/corelib/kernel/qjnihelpers.cpp @@ -289,18 +289,18 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env) return JNI_OK; } -jobject QtAndroidPrivate::activity() +QtJniTypes::Activity QtAndroidPrivate::activity() { QReadLocker locker(g_updateMutex()); return g_jActivity; } -jobject QtAndroidPrivate::service() +QtJniTypes::Service QtAndroidPrivate::service() { return g_jService; } -jobject QtAndroidPrivate::context() +QtJniTypes::Context QtAndroidPrivate::context() { QReadLocker locker(g_updateMutex()); if (g_jActivity) diff --git a/src/corelib/kernel/qjnihelpers_p.h b/src/corelib/kernel/qjnihelpers_p.h index b0f80204e9..bce2b782de 100644 --- a/src/corelib/kernel/qjnihelpers_p.h +++ b/src/corelib/kernel/qjnihelpers_p.h @@ -18,9 +18,13 @@ #include #include #include +#include QT_BEGIN_NAMESPACE +Q_DECLARE_JNI_TYPE(Activity, "Landroid/app/Activity;") +Q_DECLARE_JNI_TYPE(Service, "Landroid/app/Service;") + namespace QtAndroidPrivate { class Q_CORE_EXPORT ActivityResultListener @@ -66,9 +70,9 @@ namespace QtAndroidPrivate virtual jobject onBind(jobject intent) = 0; }; - Q_CORE_EXPORT jobject activity(); - Q_CORE_EXPORT jobject service(); - Q_CORE_EXPORT jobject context(); + Q_CORE_EXPORT QtJniTypes::Activity activity(); + Q_CORE_EXPORT QtJniTypes::Service service(); + Q_CORE_EXPORT QtJniTypes::Context context(); Q_CORE_EXPORT JavaVM *javaVM(); Q_CORE_EXPORT jint initJNI(JavaVM *vm, JNIEnv *env); Q_CORE_EXPORT jclass findClass(const char *className, JNIEnv *env); diff --git a/src/corelib/kernel/qjniobject.h b/src/corelib/kernel/qjniobject.h index 0d5c95b405..bbaa6ee70c 100644 --- a/src/corelib/kernel/qjniobject.h +++ b/src/corelib/kernel/qjniobject.h @@ -42,6 +42,7 @@ public: std::forward(args)...) {} QJniObject(jobject globalRef); + inline QJniObject(QtJniTypes::Object wrapper) noexcept : QJniObject(jobject(wrapper)) {} ~QJniObject(); jobject object() const; diff --git a/src/corelib/kernel/qjnitypes.h b/src/corelib/kernel/qjnitypes.h index 3d723a8782..e5306f3c54 100644 --- a/src/corelib/kernel/qjnitypes.h +++ b/src/corelib/kernel/qjnitypes.h @@ -227,7 +227,8 @@ static constexpr bool isObjectType() return true; } else { constexpr auto signature = typeSignature(); - return signature.startsWith('L') && signature.endsWith(';'); + return (signature.startsWith('L') || signature.startsWith('[')) + && signature.endsWith(';'); } } @@ -273,8 +274,35 @@ static constexpr auto constructorSignature() return methodSignature(); } +// A generic thin wrapper around jobject, convertible to jobject. +// We need this as a baseclass so that QJniObject can be implicitly +// constructed from the various subclasses - we can't provide an +// operator QJniObject() here as the class is not declared. +struct Object +{ + jobject _object; + constexpr operator jobject() const { return _object; } +}; + } // namespace QtJniTypes +#define Q_DECLARE_JNI_TYPE(Type, Signature) \ +namespace QtJniTypes { \ +struct Type : Object \ +{ \ + constexpr Type(jobject o) noexcept : Object{o} {} \ +}; \ +} \ +template<> \ +constexpr auto QtJniTypes::typeSignature() \ +{ \ + static_assert((Signature[0] == 'L' || Signature[0] == '[') \ + && Signature[sizeof(Signature) - 2] == ';', \ + "Type signature needs to start with 'L' or '['" \ + " and end with ';'"); \ + return QtJniTypes::String(Signature); \ +} \ + QT_END_NAMESPACE #endif diff --git a/src/corelib/platform/android/qandroidnativeinterface.cpp b/src/corelib/platform/android/qandroidnativeinterface.cpp index 09c24df410..a93844139b 100644 --- a/src/corelib/platform/android/qandroidnativeinterface.cpp +++ b/src/corelib/platform/android/qandroidnativeinterface.cpp @@ -38,14 +38,14 @@ static QBasicMutex g_pendingRunnablesMutex; QT_DEFINE_NATIVE_INTERFACE(QAndroidApplication); /*! - \fn jobject QNativeInterface::QAndroidApplication::context() + \fn jobject QNativeInterface::QAndroidApplication::context() Returns the Android context as a \c jobject. The context is an \c Activity if the main activity object is valid. Otherwise, the context is a \c Service. \since 6.2 */ -jobject QNativeInterface::QAndroidApplication::context() +QtJniTypes::Context QNativeInterface::QAndroidApplication::context() { return QtAndroidPrivate::context(); } diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 0f417cdb23..3b5e656630 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -43,9 +43,9 @@ static jmethodID m_loadClassMethodID = nullptr; static AAssetManager *m_assetManager = nullptr; static jobject m_assets = nullptr; static jobject m_resourcesObj = nullptr; -static jobject m_activityObject = nullptr; +static QtJniTypes::Activity m_activityObject = nullptr; static jmethodID m_createSurfaceMethodID = nullptr; -static jobject m_serviceObject = nullptr; +static QtJniTypes::Service m_serviceObject = nullptr; static jmethodID m_setSurfaceGeometryMethodID = nullptr; static jmethodID m_destroySurfaceMethodID = nullptr; @@ -159,12 +159,12 @@ namespace QtAndroid return m_applicationClass; } - jobject activity() + QtJniTypes::Activity activity() { return m_activityObject; } - jobject service() + QtJniTypes::Service service() { return m_serviceObject; } diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h index 1425d2173c..8d05e31f66 100644 --- a/src/plugins/platforms/android/androidjnimain.h +++ b/src/plugins/platforms/android/androidjnimain.h @@ -11,6 +11,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -49,8 +50,8 @@ namespace QtAndroid jobject assets(); AAssetManager *assetManager(); jclass applicationClass(); - jobject activity(); - jobject service(); + QtJniTypes::Activity activity(); + QtJniTypes::Service service(); // Keep synchronized with flags in ActivityDelegate.java enum SystemUiVisibility { diff --git a/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp b/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp index 49835a0e45..c4abfe399a 100644 --- a/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp +++ b/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp @@ -40,6 +40,11 @@ static_assert(QtJniTypes::typeSignature() == "Lorg/qtproject/qt/a static_assert(QtJniTypes::typeSignature() != "Ljava/lang/Object;"); static_assert(!(QtJniTypes::typeSignature() == "X")); +Q_DECLARE_JNI_TYPE(JavaType, "Lorg/qtproject/qt/JavaType;"); +static_assert(QtJniTypes::typeSignature() == "Lorg/qtproject/qt/JavaType;"); +Q_DECLARE_JNI_TYPE(ArrayType, "[Lorg/qtproject/qt/ArrayType;") +static_assert(QtJniTypes::typeSignature() == "[Lorg/qtproject/qt/ArrayType;"); + static_assert(QtJniTypes::fieldSignature() == "I"); static_assert(QtJniTypes::fieldSignature() != "X"); static_assert(QtJniTypes::fieldSignature() != "Ljava/lang/Object;"); @@ -57,6 +62,8 @@ static_assert(QtJniTypes::methodSignature() == "(I)V"); static_assert(QtJniTypes::methodSignature() == "(ILjava/lang/String;)V"); static_assert(QtJniTypes::methodSignature() == "(ILjava/lang/Class;)J"); static_assert(QtJniTypes::methodSignature() == "(ILjava/lang/String;)Ljava/lang/Object;"); +static_assert(QtJniTypes::methodSignature() + == "(ILjava/lang/String;)Lorg/qtproject/qt/JavaType;"); static_assert(QtJniTypes::isPrimitiveType()); static_assert(QtJniTypes::isPrimitiveType()); @@ -66,6 +73,7 @@ static_assert(!QtJniTypes::isPrimitiveType()); static_assert(!QtJniTypes::isObjectType()); static_assert(!QtJniTypes::isObjectType()); static_assert(QtJniTypes::isObjectType()); +static_assert(QtJniTypes::isObjectType()); static_assert(QtJniTypes::isObjectType()); static_assert(QtJniTypes::String("ABCDE").startsWith("ABC")); @@ -86,6 +94,7 @@ static_assert(!QtJniTypes::String("ABCDE").endsWith('F')); void tst_QJniTypes::initTestCase() { + } QTEST_MAIN(tst_QJniTypes)