diff --git a/src/corelib/kernel/qjnienvironment.h b/src/corelib/kernel/qjnienvironment.h index 2121ceb6fe1..db41e1d4ab0 100644 --- a/src/corelib/kernel/qjnienvironment.h +++ b/src/corelib/kernel/qjnienvironment.h @@ -25,7 +25,7 @@ public: JNIEnv *jniEnv() const; jclass findClass(const char *className); template - jclass findClass() { return findClass(QtJniTypes::className().data()); } + jclass findClass() { return findClass(QtJniTypes::Traits::className().data()); } jmethodID findMethod(jclass clazz, const char *methodName, const char *signature); template jmethodID findMethod(jclass clazz, const char *methodName) { diff --git a/src/corelib/kernel/qjnitypes.h b/src/corelib/kernel/qjnitypes.h index d3634d6bc5d..6007dd32975 100644 --- a/src/corelib/kernel/qjnitypes.h +++ b/src/corelib/kernel/qjnitypes.h @@ -39,31 +39,35 @@ struct Type : Object \ #define Q_DECLARE_JNI_TYPE(Type, Signature) \ Q_DECLARE_JNI_TYPE_HELPER(Type) \ 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::CTString(Signature); \ -} \ +struct QtJniTypes::Traits { \ + static constexpr auto signature() \ + { \ + static_assert((Signature[0] == 'L' \ + || Signature[0] == '[') \ + && Signature[sizeof(Signature) - 2] == ';', \ + "Type signature needs to start with 'L' or" \ + " '[' and end with ';'"); \ + return QtJniTypes::CTString(Signature); \ + } \ +}; \ #define Q_DECLARE_JNI_CLASS(Type, Signature) \ Q_DECLARE_JNI_TYPE_HELPER(Type) \ template<> \ -constexpr auto QtJniTypes::className() \ -{ \ - return QtJniTypes::CTString(Signature); \ -} \ -template<> \ -constexpr auto QtJniTypes::typeSignature() \ -{ \ - return QtJniTypes::CTString("L") \ - + QtJniTypes::CTString(Signature) \ - + QtJniTypes::CTString(";"); \ -} \ +struct QtJniTypes::Traits { \ + static constexpr auto className() \ + { \ + return QtJniTypes::CTString(Signature); \ + } \ + static constexpr auto signature() \ + { \ + return QtJniTypes::CTString("L") \ + + className() \ + + QtJniTypes::CTString(";"); \ + } \ +}; \ -#define Q_DECLARE_JNI_NATIVE_METHOD(...) \ +#define Q_DECLARE_JNI_NATIVE_METHOD(...) \ QT_OVERLOADED_MACRO(QT_DECLARE_JNI_NATIVE_METHOD, __VA_ARGS__) \ #define QT_DECLARE_JNI_NATIVE_METHOD_2(Method, Name) \ diff --git a/src/corelib/kernel/qjnitypes_impl.h b/src/corelib/kernel/qjnitypes_impl.h index a671eeae350..7b8bd1819af 100644 --- a/src/corelib/kernel/qjnitypes_impl.h +++ b/src/corelib/kernel/qjnitypes_impl.h @@ -149,97 +149,113 @@ static void staticAssertTypeMismatch() "Use a JNI based type instead."); } -template -constexpr auto typeSignature() -{ - if constexpr (std::is_array_v) { - using UnderlyingType = typename std::remove_extent_t; - static_assert(!std::is_array_v, - "typeSignature() does not handle multi-dimensional arrays"); - return CTString("[") + typeSignature(); - } else if constexpr (std::is_same_v) { - return CTString("Ljava/lang/Object;"); - } else if constexpr (std::is_same_v) { - return CTString("Ljava/lang/Class;"); - } else if constexpr (std::is_same_v) { - return CTString("Ljava/lang/String;"); - } else if constexpr (std::is_same_v) { - return CTString("[Ljava/lang/Object;"); - } else if constexpr (std::is_same_v) { - return CTString("Ljava/lang/Throwable;"); - } else if constexpr (std::is_same_v) { - return CTString("[Z"); - } else if constexpr (std::is_same_v) { - return CTString("[B"); - } else if constexpr (std::is_same_v) { - return CTString("[S"); - } else if constexpr (std::is_same_v) { - return CTString("[I"); - } else if constexpr (std::is_same_v) { - return CTString("[J"); - } else if constexpr (std::is_same_v) { - return CTString("[F"); - } else if constexpr (std::is_same_v) { - return CTString("[D"); - } else if constexpr (std::is_same_v) { - return CTString("[C"); - } else if constexpr (std::is_same_v) { - return CTString("Z"); - } else if constexpr (std::is_same_v) { - return CTString("Z"); - } else if constexpr (std::is_same_v) { - return CTString("B"); - } else if constexpr (std::is_same_v) { - return CTString("C"); - } else if constexpr (std::is_same_v) { - return CTString("C"); - } else if constexpr (std::is_same_v) { - return CTString("S"); - } else if constexpr (std::is_same_v) { - return CTString("S"); - } else if constexpr (std::is_same_v) { - return CTString("I"); - } else if constexpr (std::is_same_v) { - return CTString("I"); - } else if constexpr (std::is_same_v) { - return CTString("I"); - } else if constexpr (std::is_same_v) { - return CTString("J"); - } else if constexpr (std::is_same_v) { - return CTString("J"); - } else if constexpr (std::is_same_v) { - return CTString("F"); - } else if constexpr (std::is_same_v) { - return CTString("F"); - } else if constexpr (std::is_same_v) { - return CTString("D"); - } else if constexpr (std::is_same_v) { - return CTString("D"); - } else if constexpr (std::is_same_v) { - return CTString("V"); - } - - // else: The return type becomes void, indicating that the typeSignature - // template is not implemented for the respective type. We use this to - // detect invalid types in the ValidSignatureTypes and ValidFieldType - // predicates below. -} - template static void staticAssertClassNotRegistered() { static_assert(flag, "Class not registered, use Q_DECLARE_JNI_CLASS"); } -template -constexpr auto className() +template +struct Traits { + // The return type of className/signature becomes void for any type + // not handled here. This indicates that the Traits type is not specialized + // for the respective type, which we use to detect invalid types in the + // ValidSignatureTypes and ValidFieldType predicates below. + + static constexpr auto className() + { + if constexpr (std::is_same_v) + return CTString("java/lang/String"); + else if constexpr (std::is_same_v) + return CTString("java/lang/Object"); + else if constexpr (std::is_same_v) + return CTString("java/lang/Class"); + else if constexpr (std::is_same_v) + return CTString("java/lang/Throwable"); + // else: return void -> not implemented + } + + static constexpr auto signature() + { + if constexpr (!std::is_same_v) { + // the type signature of any object class is L; + return CTString("L") + className() + CTString(";"); + } else if constexpr (std::is_array_v) { + using UnderlyingType = typename std::remove_extent_t; + static_assert(!std::is_array_v, + "Traits::signature() does not handle multi-dimensional arrays"); + return CTString("[") + Traits::signature(); + } else if constexpr (std::is_same_v) { + return CTString("[Ljava/lang/Object;"); + } else if constexpr (std::is_same_v) { + return CTString("[Z"); + } else if constexpr (std::is_same_v) { + return CTString("[B"); + } else if constexpr (std::is_same_v) { + return CTString("[S"); + } else if constexpr (std::is_same_v) { + return CTString("[I"); + } else if constexpr (std::is_same_v) { + return CTString("[J"); + } else if constexpr (std::is_same_v) { + return CTString("[F"); + } else if constexpr (std::is_same_v) { + return CTString("[D"); + } else if constexpr (std::is_same_v) { + return CTString("[C"); + } else if constexpr (std::is_same_v) { + return CTString("Z"); + } else if constexpr (std::is_same_v) { + return CTString("Z"); + } else if constexpr (std::is_same_v) { + return CTString("B"); + } else if constexpr (std::is_same_v) { + return CTString("C"); + } else if constexpr (std::is_same_v) { + return CTString("C"); + } else if constexpr (std::is_same_v) { + return CTString("S"); + } else if constexpr (std::is_same_v) { + return CTString("S"); + } else if constexpr (std::is_same_v) { + return CTString("I"); + } else if constexpr (std::is_same_v) { + return CTString("I"); + } else if constexpr (std::is_same_v) { + return CTString("I"); + } else if constexpr (std::is_same_v) { + return CTString("J"); + } else if constexpr (std::is_same_v) { + return CTString("J"); + } else if constexpr (std::is_same_v) { + return CTString("F"); + } else if constexpr (std::is_same_v) { + return CTString("F"); + } else if constexpr (std::is_same_v) { + return CTString("D"); + } else if constexpr (std::is_same_v) { + return CTString("D"); + } else if constexpr (std::is_same_v) { + return CTString("V"); + } + // else: return void -> not implemented + } +}; + +// compatibility until submodules are ported +template +constexpr auto typeSignature() { - if constexpr (std::is_same_v) - return CTString("java/lang/String"); - else - staticAssertClassNotRegistered(); + return Traits::signature(); } +template +constexpr auto className() +{ + return Traits::className(); +} + +// have to use the compatibility functions here until porting is complete template static constexpr bool isPrimitiveType() { diff --git a/src/corelib/time/qtimezoneprivate_android.cpp b/src/corelib/time/qtimezoneprivate_android.cpp index c4ca0e42146..935a0cd7454 100644 --- a/src/corelib/time/qtimezoneprivate_android.cpp +++ b/src/corelib/time/qtimezoneprivate_android.cpp @@ -31,7 +31,7 @@ QAndroidTimeZonePrivate::QAndroidTimeZonePrivate() { // Keep in sync with systemTimeZoneId(): androidTimeZone = QJniObject::callStaticMethod( - QtJniTypes::className(), "getDefault"); + QtJniTypes::Traits::className(), "getDefault"); const QJniObject id = androidTimeZone.callMethod("getID"); m_id = id.toString().toUtf8(); } @@ -59,7 +59,7 @@ static QString getDisplayName(QJniObject zone, jint style, jboolean dst, { QJniObject jbcpTag = QJniObject::fromString(locale.bcp47Name()); QJniObject jlocale = QJniObject::callStaticMethod( - QtJniTypes::className(), "forLanguageTag", + QtJniTypes::Traits::className(), "forLanguageTag", jbcpTag.object()); return zone.callMethod("getDisplayName", dst, style, @@ -70,7 +70,7 @@ void QAndroidTimeZonePrivate::init(const QByteArray &ianaId) { const QString iana = QString::fromUtf8(ianaId); androidTimeZone = QJniObject::callStaticMethod( - QtJniTypes::className(), "getTimeZone", + QtJniTypes::Traits::className(), "getTimeZone", QJniObject::fromString(iana).object()); // The ID or display name of the zone we've got, if it looks like what we asked for: @@ -200,7 +200,7 @@ QByteArray QAndroidTimeZonePrivate::systemTimeZoneId() const { // Keep in sync with default constructor: QJniObject androidSystemTimeZone = QJniObject::callStaticMethod( - QtJniTypes::className(), "getDefault"); + QtJniTypes::Traits::className(), "getDefault"); const QJniObject id = androidSystemTimeZone.callMethod("getID"); return id.toString().toUtf8(); } @@ -209,7 +209,7 @@ QList QAndroidTimeZonePrivate::availableTimeZoneIds() const { QList availableTimeZoneIdList; QJniObject androidAvailableIdList = QJniObject::callStaticMethod( - QtJniTypes::className(), "getAvailableIDs"); + QtJniTypes::Traits::className(), "getAvailableIDs"); QJniEnvironment jniEnv; int androidTZcount = jniEnv->GetArrayLength(androidAvailableIdList.object()); diff --git a/src/plugins/platforms/android/androidcontentfileengine.cpp b/src/plugins/platforms/android/androidcontentfileengine.cpp index b5f4517850c..cd7913fddfe 100644 --- a/src/plugins/platforms/android/androidcontentfileengine.cpp +++ b/src/plugins/platforms/android/androidcontentfileengine.cpp @@ -465,7 +465,7 @@ const QLatin1String MIME_TYPE_DIR("vnd.android.document/directory"); QString documentId(const QJniObject &uri) { return QJniObject::callStaticMethod( - QtJniTypes::className(), + QtJniTypes::Traits::className(), "getDocumentId", uri.object()).toString(); } @@ -473,7 +473,7 @@ QString documentId(const QJniObject &uri) QString treeDocumentId(const QJniObject &uri) { return QJniObject::callStaticMethod( - QtJniTypes::className(), + QtJniTypes::Traits::className(), "getTreeDocumentId", uri.object()).toString(); } @@ -481,7 +481,7 @@ QString treeDocumentId(const QJniObject &uri) QJniObject buildChildDocumentsUriUsingTree(const QJniObject &uri, const QString &parentDocumentId) { return QJniObject::callStaticMethod( - QtJniTypes::className(), + QtJniTypes::Traits::className(), "buildChildDocumentsUriUsingTree", uri.object(), QJniObject::fromString(parentDocumentId).object()); @@ -491,7 +491,7 @@ QJniObject buildChildDocumentsUriUsingTree(const QJniObject &uri, const QString QJniObject buildDocumentUriUsingTree(const QJniObject &treeUri, const QString &documentId) { return QJniObject::callStaticMethod( - QtJniTypes::className(), + QtJniTypes::Traits::className(), "buildDocumentUriUsingTree", treeUri.object(), QJniObject::fromString(documentId).object()); @@ -500,7 +500,7 @@ QJniObject buildDocumentUriUsingTree(const QJniObject &treeUri, const QString &d bool isDocumentUri(const QJniObject &uri) { return QJniObject::callStaticMethod( - QtJniTypes::className(), + QtJniTypes::Traits::className(), "isDocumentUri", QNativeInterface::QAndroidApplication::context(), uri.object()); @@ -509,7 +509,7 @@ bool isDocumentUri(const QJniObject &uri) bool isTreeUri(const QJniObject &uri) { return QJniObject::callStaticMethod( - QtJniTypes::className(), + QtJniTypes::Traits::className(), "isTreeUri", uri.object()); } @@ -518,7 +518,7 @@ QJniObject createDocument(const QJniObject &parentDocumentUri, const QString &mi const QString &displayName) { return QJniObject::callStaticMethod( - QtJniTypes::className(), + QtJniTypes::Traits::className(), "createDocument", contentResolverInstance().object(), parentDocumentUri.object(), @@ -533,7 +533,7 @@ bool deleteDocument(const QJniObject &documentUri) return {}; return QJniObject::callStaticMethod( - QtJniTypes::className(), + QtJniTypes::Traits::className(), "deleteDocument", contentResolverInstance().object(), documentUri.object()); @@ -548,7 +548,7 @@ QJniObject moveDocument(const QJniObject &sourceDocumentUri, return {}; return QJniObject::callStaticMethod( - QtJniTypes::className(), + QtJniTypes::Traits::className(), "moveDocument", contentResolverInstance().object(), sourceDocumentUri.object(), @@ -563,7 +563,7 @@ QJniObject renameDocument(const QJniObject &documentUri, const QString &displayN return {}; return QJniObject::callStaticMethod( - QtJniTypes::className(), + QtJniTypes::Traits::className(), "renameDocument", contentResolverInstance().object(), documentUri.object(), @@ -598,7 +598,7 @@ QJniObject parseUri(const QString &uri) uriToParse.replace(' ', QUrl::toPercentEncoding(" ")); return QJniObject::callStaticMethod( - QtJniTypes::className(), + QtJniTypes::Traits::className(), "parse", QJniObject::fromString(uriToParse).object()); } diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index 7e509ecf3a0..bf6dc85a06b 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -66,7 +66,7 @@ namespace { QAndroidPlatformScreen* createScreenForDisplayId(int displayId) { const QJniObject display = QJniObject::callStaticObjectMethod( - QtJniTypes::className(), + QtJniTypes::Traits::className(), "getDisplay", displayId); if (!display.isValid()) @@ -184,10 +184,10 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶ qFatal("Could not bind GL_ES API"); m_primaryDisplayId = QJniObject::getStaticField( - QtJniTypes::className(), "DEFAULT_DISPLAY"); + QtJniTypes::Traits::className(), "DEFAULT_DISPLAY"); const QJniObject nativeDisplaysList = QJniObject::callStaticObjectMethod( - QtJniTypes::className(), + QtJniTypes::Traits::className(), "getAvailableDisplays"); const int numberOfAvailableDisplays = nativeDisplaysList.callMethod("size"); diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp index cb5006c5d4c..aec2d69fc03 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -92,7 +92,7 @@ QAndroidPlatformScreen::QAndroidPlatformScreen(const QJniObject &displayObject) displayObject.object()); const auto sizeObj = QJniObject::callStaticMethod( - QtJniTypes::className(), + QtJniTypes::Traits::className(), "getDisplaySize", displayContext.object(), displayObject.object()); diff --git a/src/plugins/platforms/android/qandroidplatformservices.cpp b/src/plugins/platforms/android/qandroidplatformservices.cpp index d0a94645c9e..f43e7cdd6a3 100644 --- a/src/plugins/platforms/android/qandroidplatformservices.cpp +++ b/src/plugins/platforms/android/qandroidplatformservices.cpp @@ -78,11 +78,11 @@ bool QAndroidPlatformServices::openUrl(const QUrl &theUrl) const auto providerName = QJniObject::fromString(appId + ".qtprovider"_L1); const auto urlPath = QJniObject::fromString(url.path()); - const auto urlFile = QJniObject(QtJniTypes::className(), + const auto urlFile = QJniObject(QtJniTypes::Traits::className(), urlPath.object()); const auto fileProviderUri = QJniObject::callStaticMethod( - QtJniTypes::className(), "getUriForFile", + QtJniTypes::Traits::className(), "getUriForFile", QAndroidApplication::context(), providerName.object(), urlFile.object()); diff --git a/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp b/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp index d7b7059bd31..b7685538f19 100644 --- a/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp +++ b/tests/auto/corelib/kernel/qjnitypes/tst_qjnitypes.cpp @@ -19,35 +19,45 @@ private slots: struct QtJavaWrapper {}; template<> -constexpr auto QtJniTypes::typeSignature() +struct QtJniTypes::Traits { - return QtJniTypes::CTString("Lorg/qtproject/qt/android/QtJavaWrapper;"); -} + static constexpr auto signature() + { + return QtJniTypes::CTString("Lorg/qtproject/qt/android/QtJavaWrapper;"); + } +}; template<> -constexpr auto QtJniTypes::typeSignature() +struct QtJniTypes::Traits { - return QtJniTypes::CTString("Ljava/lang/Object;"); -} + static constexpr auto signature() + { + return QtJniTypes::CTString("Ljava/lang/Object;"); + } +}; struct QtCustomJniObject : QJniObject {}; -template<> -constexpr auto QtJniTypes::typeSignature() -{ - return QtJniTypes::CTString("Lorg/qtproject/qt/android/QtCustomJniObject;"); -} -static_assert(QtJniTypes::typeSignature() == "Lorg/qtproject/qt/android/QtJavaWrapper;"); -static_assert(QtJniTypes::typeSignature() != "Ljava/lang/Object;"); -static_assert(!(QtJniTypes::typeSignature() == "X")); +template<> +struct QtJniTypes::Traits +{ + static constexpr auto signature() + { + return QtJniTypes::CTString("Lorg/qtproject/qt/android/QtCustomJniObject;"); + } +}; + +static_assert(QtJniTypes::Traits::signature() == "Lorg/qtproject/qt/android/QtJavaWrapper;"); +static_assert(QtJniTypes::Traits::signature() != "Ljava/lang/Object;"); +static_assert(!(QtJniTypes::Traits::signature() == "X")); Q_DECLARE_JNI_CLASS(JavaType, "org/qtproject/qt/JavaType"); -static_assert(QtJniTypes::typeSignature() == "Lorg/qtproject/qt/JavaType;"); +static_assert(QtJniTypes::Traits::signature() == "Lorg/qtproject/qt/JavaType;"); Q_DECLARE_JNI_TYPE(ArrayType, "[Lorg/qtproject/qt/ArrayType;") -static_assert(QtJniTypes::typeSignature() == "[Lorg/qtproject/qt/ArrayType;"); +static_assert(QtJniTypes::Traits::signature() == "[Lorg/qtproject/qt/ArrayType;"); Q_DECLARE_JNI_CLASS(QtTextToSpeech, "org/qtproject/qt/android/speech/QtTextToSpeech") -static_assert(QtJniTypes::className() == "org/qtproject/qt/android/speech/QtTextToSpeech"); +static_assert(QtJniTypes::Traits::className() == "org/qtproject/qt/android/speech/QtTextToSpeech"); static_assert(QtJniTypes::fieldSignature() == "I"); static_assert(QtJniTypes::fieldSignature() == "[I");