JNI: move signature/className template functions into a template class

Template functions don't permit partial specialization, e.g. we cannot
specialize typeSignature() to return an array signature for any
std::vector or QList type. We need to do that for better array support,
so move those functions as static members into a template class, which
then can be specialized.

Since submodules are both calling and specializing typeSignature and
className as template functions, keep and use those until the porting is
complete.

Change-Id: I74ec957fc41f78046cd9d0f803d8cc9d1e56672b
Reviewed-by: Petri Virkkunen <petri.virkkunen@qt.io>
Reviewed-by: Zoltan Gera <zoltan.gera@qt.io>
Reviewed-by: Tinja Paavoseppä <tinja.paavoseppa@qt.io>
This commit is contained in:
Volker Hilsheimer 2023-09-17 12:40:40 +02:00
parent 0022b05a9a
commit e1a349983c
9 changed files with 172 additions and 142 deletions

View File

@ -25,7 +25,7 @@ public:
JNIEnv *jniEnv() const; JNIEnv *jniEnv() const;
jclass findClass(const char *className); jclass findClass(const char *className);
template<typename Class> template<typename Class>
jclass findClass() { return findClass(QtJniTypes::className<Class>().data()); } jclass findClass() { return findClass(QtJniTypes::Traits<Class>::className().data()); }
jmethodID findMethod(jclass clazz, const char *methodName, const char *signature); jmethodID findMethod(jclass clazz, const char *methodName, const char *signature);
template<typename ...Args> template<typename ...Args>
jmethodID findMethod(jclass clazz, const char *methodName) { jmethodID findMethod(jclass clazz, const char *methodName) {

View File

@ -39,31 +39,35 @@ struct Type : Object \
#define Q_DECLARE_JNI_TYPE(Type, Signature) \ #define Q_DECLARE_JNI_TYPE(Type, Signature) \
Q_DECLARE_JNI_TYPE_HELPER(Type) \ Q_DECLARE_JNI_TYPE_HELPER(Type) \
template<> \ template<> \
constexpr auto QtJniTypes::typeSignature<QtJniTypes::Type>() \ struct QtJniTypes::Traits<QtJniTypes::Type> { \
{ \ static constexpr auto signature() \
static_assert((Signature[0] == 'L' || Signature[0] == '[') \ { \
&& Signature[sizeof(Signature) - 2] == ';', \ static_assert((Signature[0] == 'L' \
"Type signature needs to start with 'L' or '['" \ || Signature[0] == '[') \
" and end with ';'"); \ && Signature[sizeof(Signature) - 2] == ';', \
return QtJniTypes::CTString(Signature); \ "Type signature needs to start with 'L' or" \
} \ " '[' and end with ';'"); \
return QtJniTypes::CTString(Signature); \
} \
}; \
#define Q_DECLARE_JNI_CLASS(Type, Signature) \ #define Q_DECLARE_JNI_CLASS(Type, Signature) \
Q_DECLARE_JNI_TYPE_HELPER(Type) \ Q_DECLARE_JNI_TYPE_HELPER(Type) \
template<> \ template<> \
constexpr auto QtJniTypes::className<QtJniTypes::Type>() \ struct QtJniTypes::Traits<QtJniTypes::Type> { \
{ \ static constexpr auto className() \
return QtJniTypes::CTString(Signature); \ { \
} \ return QtJniTypes::CTString(Signature); \
template<> \ } \
constexpr auto QtJniTypes::typeSignature<QtJniTypes::Type>() \ static constexpr auto signature() \
{ \ { \
return QtJniTypes::CTString("L") \ return QtJniTypes::CTString("L") \
+ QtJniTypes::CTString(Signature) \ + className() \
+ QtJniTypes::CTString(";"); \ + QtJniTypes::CTString(";"); \
} \ } \
}; \
#define Q_DECLARE_JNI_NATIVE_METHOD(...) \ #define Q_DECLARE_JNI_NATIVE_METHOD(...) \
QT_OVERLOADED_MACRO(QT_DECLARE_JNI_NATIVE_METHOD, __VA_ARGS__) \ QT_OVERLOADED_MACRO(QT_DECLARE_JNI_NATIVE_METHOD, __VA_ARGS__) \
#define QT_DECLARE_JNI_NATIVE_METHOD_2(Method, Name) \ #define QT_DECLARE_JNI_NATIVE_METHOD_2(Method, Name) \

View File

@ -149,97 +149,113 @@ static void staticAssertTypeMismatch()
"Use a JNI based type instead."); "Use a JNI based type instead.");
} }
template<typename T>
constexpr auto typeSignature()
{
if constexpr (std::is_array_v<T>) {
using UnderlyingType = typename std::remove_extent_t<T>;
static_assert(!std::is_array_v<UnderlyingType>,
"typeSignature() does not handle multi-dimensional arrays");
return CTString("[") + typeSignature<UnderlyingType>();
} else if constexpr (std::is_same_v<T, jobject>) {
return CTString("Ljava/lang/Object;");
} else if constexpr (std::is_same_v<T, jclass>) {
return CTString("Ljava/lang/Class;");
} else if constexpr (std::is_same_v<T, jstring>) {
return CTString("Ljava/lang/String;");
} else if constexpr (std::is_same_v<T, jobjectArray>) {
return CTString("[Ljava/lang/Object;");
} else if constexpr (std::is_same_v<T, jthrowable>) {
return CTString("Ljava/lang/Throwable;");
} else if constexpr (std::is_same_v<T, jbooleanArray>) {
return CTString("[Z");
} else if constexpr (std::is_same_v<T, jbyteArray>) {
return CTString("[B");
} else if constexpr (std::is_same_v<T, jshortArray>) {
return CTString("[S");
} else if constexpr (std::is_same_v<T, jintArray>) {
return CTString("[I");
} else if constexpr (std::is_same_v<T, jlongArray>) {
return CTString("[J");
} else if constexpr (std::is_same_v<T, jfloatArray>) {
return CTString("[F");
} else if constexpr (std::is_same_v<T, jdoubleArray>) {
return CTString("[D");
} else if constexpr (std::is_same_v<T, jcharArray>) {
return CTString("[C");
} else if constexpr (std::is_same_v<T, jboolean>) {
return CTString("Z");
} else if constexpr (std::is_same_v<T, bool>) {
return CTString("Z");
} else if constexpr (std::is_same_v<T, jbyte>) {
return CTString("B");
} else if constexpr (std::is_same_v<T, jchar>) {
return CTString("C");
} else if constexpr (std::is_same_v<T, char>) {
return CTString("C");
} else if constexpr (std::is_same_v<T, jshort>) {
return CTString("S");
} else if constexpr (std::is_same_v<T, short>) {
return CTString("S");
} else if constexpr (std::is_same_v<T, jint>) {
return CTString("I");
} else if constexpr (std::is_same_v<T, int>) {
return CTString("I");
} else if constexpr (std::is_same_v<T, uint>) {
return CTString("I");
} else if constexpr (std::is_same_v<T, jlong>) {
return CTString("J");
} else if constexpr (std::is_same_v<T, long>) {
return CTString("J");
} else if constexpr (std::is_same_v<T, jfloat>) {
return CTString("F");
} else if constexpr (std::is_same_v<T, float>) {
return CTString("F");
} else if constexpr (std::is_same_v<T, jdouble>) {
return CTString("D");
} else if constexpr (std::is_same_v<T, double>) {
return CTString("D");
} else if constexpr (std::is_same_v<T, void>) {
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<bool flag = false> template<bool flag = false>
static void staticAssertClassNotRegistered() static void staticAssertClassNotRegistered()
{ {
static_assert(flag, "Class not registered, use Q_DECLARE_JNI_CLASS"); static_assert(flag, "Class not registered, use Q_DECLARE_JNI_CLASS");
} }
template<typename T> template <typename T>
constexpr auto className() 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<T, jstring>)
return CTString("java/lang/String");
else if constexpr (std::is_same_v<T, jobject>)
return CTString("java/lang/Object");
else if constexpr (std::is_same_v<T, jclass>)
return CTString("java/lang/Class");
else if constexpr (std::is_same_v<T, jthrowable>)
return CTString("java/lang/Throwable");
// else: return void -> not implemented
}
static constexpr auto signature()
{
if constexpr (!std::is_same_v<decltype(className()), void>) {
// the type signature of any object class is L<className>;
return CTString("L") + className() + CTString(";");
} else if constexpr (std::is_array_v<T>) {
using UnderlyingType = typename std::remove_extent_t<T>;
static_assert(!std::is_array_v<UnderlyingType>,
"Traits::signature() does not handle multi-dimensional arrays");
return CTString("[") + Traits<UnderlyingType>::signature();
} else if constexpr (std::is_same_v<T, jobjectArray>) {
return CTString("[Ljava/lang/Object;");
} else if constexpr (std::is_same_v<T, jbooleanArray>) {
return CTString("[Z");
} else if constexpr (std::is_same_v<T, jbyteArray>) {
return CTString("[B");
} else if constexpr (std::is_same_v<T, jshortArray>) {
return CTString("[S");
} else if constexpr (std::is_same_v<T, jintArray>) {
return CTString("[I");
} else if constexpr (std::is_same_v<T, jlongArray>) {
return CTString("[J");
} else if constexpr (std::is_same_v<T, jfloatArray>) {
return CTString("[F");
} else if constexpr (std::is_same_v<T, jdoubleArray>) {
return CTString("[D");
} else if constexpr (std::is_same_v<T, jcharArray>) {
return CTString("[C");
} else if constexpr (std::is_same_v<T, jboolean>) {
return CTString("Z");
} else if constexpr (std::is_same_v<T, bool>) {
return CTString("Z");
} else if constexpr (std::is_same_v<T, jbyte>) {
return CTString("B");
} else if constexpr (std::is_same_v<T, jchar>) {
return CTString("C");
} else if constexpr (std::is_same_v<T, char>) {
return CTString("C");
} else if constexpr (std::is_same_v<T, jshort>) {
return CTString("S");
} else if constexpr (std::is_same_v<T, short>) {
return CTString("S");
} else if constexpr (std::is_same_v<T, jint>) {
return CTString("I");
} else if constexpr (std::is_same_v<T, int>) {
return CTString("I");
} else if constexpr (std::is_same_v<T, uint>) {
return CTString("I");
} else if constexpr (std::is_same_v<T, jlong>) {
return CTString("J");
} else if constexpr (std::is_same_v<T, long>) {
return CTString("J");
} else if constexpr (std::is_same_v<T, jfloat>) {
return CTString("F");
} else if constexpr (std::is_same_v<T, float>) {
return CTString("F");
} else if constexpr (std::is_same_v<T, jdouble>) {
return CTString("D");
} else if constexpr (std::is_same_v<T, double>) {
return CTString("D");
} else if constexpr (std::is_same_v<T, void>) {
return CTString("V");
}
// else: return void -> not implemented
}
};
// compatibility until submodules are ported
template <typename T>
constexpr auto typeSignature()
{ {
if constexpr (std::is_same_v<T, jstring>) return Traits<T>::signature();
return CTString("java/lang/String");
else
staticAssertClassNotRegistered();
} }
template <typename T>
constexpr auto className()
{
return Traits<T>::className();
}
// have to use the compatibility functions here until porting is complete
template<typename T> template<typename T>
static constexpr bool isPrimitiveType() static constexpr bool isPrimitiveType()
{ {

View File

@ -31,7 +31,7 @@ QAndroidTimeZonePrivate::QAndroidTimeZonePrivate()
{ {
// Keep in sync with systemTimeZoneId(): // Keep in sync with systemTimeZoneId():
androidTimeZone = QJniObject::callStaticMethod<QtJniTypes::TimeZone>( androidTimeZone = QJniObject::callStaticMethod<QtJniTypes::TimeZone>(
QtJniTypes::className<QtJniTypes::TimeZone>(), "getDefault"); QtJniTypes::Traits<QtJniTypes::TimeZone>::className(), "getDefault");
const QJniObject id = androidTimeZone.callMethod<jstring>("getID"); const QJniObject id = androidTimeZone.callMethod<jstring>("getID");
m_id = id.toString().toUtf8(); 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 jbcpTag = QJniObject::fromString(locale.bcp47Name());
QJniObject jlocale = QJniObject::callStaticMethod<QtJniTypes::Locale>( QJniObject jlocale = QJniObject::callStaticMethod<QtJniTypes::Locale>(
QtJniTypes::className<QtJniTypes::Locale>(), "forLanguageTag", QtJniTypes::Traits<QtJniTypes::Locale>::className(), "forLanguageTag",
jbcpTag.object<jstring>()); jbcpTag.object<jstring>());
return zone.callMethod<jstring>("getDisplayName", dst, style, return zone.callMethod<jstring>("getDisplayName", dst, style,
@ -70,7 +70,7 @@ void QAndroidTimeZonePrivate::init(const QByteArray &ianaId)
{ {
const QString iana = QString::fromUtf8(ianaId); const QString iana = QString::fromUtf8(ianaId);
androidTimeZone = QJniObject::callStaticMethod<QtJniTypes::TimeZone>( androidTimeZone = QJniObject::callStaticMethod<QtJniTypes::TimeZone>(
QtJniTypes::className<QtJniTypes::TimeZone>(), "getTimeZone", QtJniTypes::Traits<QtJniTypes::TimeZone>::className(), "getTimeZone",
QJniObject::fromString(iana).object<jstring>()); QJniObject::fromString(iana).object<jstring>());
// The ID or display name of the zone we've got, if it looks like what we asked for: // 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: // Keep in sync with default constructor:
QJniObject androidSystemTimeZone = QJniObject::callStaticMethod<QtJniTypes::TimeZone>( QJniObject androidSystemTimeZone = QJniObject::callStaticMethod<QtJniTypes::TimeZone>(
QtJniTypes::className<QtJniTypes::TimeZone>(), "getDefault"); QtJniTypes::Traits<QtJniTypes::TimeZone>::className(), "getDefault");
const QJniObject id = androidSystemTimeZone.callMethod<jstring>("getID"); const QJniObject id = androidSystemTimeZone.callMethod<jstring>("getID");
return id.toString().toUtf8(); return id.toString().toUtf8();
} }
@ -209,7 +209,7 @@ QList<QByteArray> QAndroidTimeZonePrivate::availableTimeZoneIds() const
{ {
QList<QByteArray> availableTimeZoneIdList; QList<QByteArray> availableTimeZoneIdList;
QJniObject androidAvailableIdList = QJniObject::callStaticMethod<QtJniTypes::StringArray>( QJniObject androidAvailableIdList = QJniObject::callStaticMethod<QtJniTypes::StringArray>(
QtJniTypes::className<QtJniTypes::TimeZone>(), "getAvailableIDs"); QtJniTypes::Traits<QtJniTypes::TimeZone>::className(), "getAvailableIDs");
QJniEnvironment jniEnv; QJniEnvironment jniEnv;
int androidTZcount = jniEnv->GetArrayLength(androidAvailableIdList.object<jarray>()); int androidTZcount = jniEnv->GetArrayLength(androidAvailableIdList.object<jarray>());

View File

@ -465,7 +465,7 @@ const QLatin1String MIME_TYPE_DIR("vnd.android.document/directory");
QString documentId(const QJniObject &uri) QString documentId(const QJniObject &uri)
{ {
return QJniObject::callStaticMethod<jstring, QtJniTypes::UriType>( return QJniObject::callStaticMethod<jstring, QtJniTypes::UriType>(
QtJniTypes::className<QtJniTypes::DocumentsContract>(), QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"getDocumentId", "getDocumentId",
uri.object()).toString(); uri.object()).toString();
} }
@ -473,7 +473,7 @@ QString documentId(const QJniObject &uri)
QString treeDocumentId(const QJniObject &uri) QString treeDocumentId(const QJniObject &uri)
{ {
return QJniObject::callStaticMethod<jstring, QtJniTypes::UriType>( return QJniObject::callStaticMethod<jstring, QtJniTypes::UriType>(
QtJniTypes::className<QtJniTypes::DocumentsContract>(), QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"getTreeDocumentId", "getTreeDocumentId",
uri.object()).toString(); uri.object()).toString();
} }
@ -481,7 +481,7 @@ QString treeDocumentId(const QJniObject &uri)
QJniObject buildChildDocumentsUriUsingTree(const QJniObject &uri, const QString &parentDocumentId) QJniObject buildChildDocumentsUriUsingTree(const QJniObject &uri, const QString &parentDocumentId)
{ {
return QJniObject::callStaticMethod<QtJniTypes::UriType>( return QJniObject::callStaticMethod<QtJniTypes::UriType>(
QtJniTypes::className<QtJniTypes::DocumentsContract>(), QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"buildChildDocumentsUriUsingTree", "buildChildDocumentsUriUsingTree",
uri.object<QtJniTypes::UriType>(), uri.object<QtJniTypes::UriType>(),
QJniObject::fromString(parentDocumentId).object<jstring>()); QJniObject::fromString(parentDocumentId).object<jstring>());
@ -491,7 +491,7 @@ QJniObject buildChildDocumentsUriUsingTree(const QJniObject &uri, const QString
QJniObject buildDocumentUriUsingTree(const QJniObject &treeUri, const QString &documentId) QJniObject buildDocumentUriUsingTree(const QJniObject &treeUri, const QString &documentId)
{ {
return QJniObject::callStaticMethod<QtJniTypes::UriType>( return QJniObject::callStaticMethod<QtJniTypes::UriType>(
QtJniTypes::className<QtJniTypes::DocumentsContract>(), QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"buildDocumentUriUsingTree", "buildDocumentUriUsingTree",
treeUri.object<QtJniTypes::UriType>(), treeUri.object<QtJniTypes::UriType>(),
QJniObject::fromString(documentId).object<jstring>()); QJniObject::fromString(documentId).object<jstring>());
@ -500,7 +500,7 @@ QJniObject buildDocumentUriUsingTree(const QJniObject &treeUri, const QString &d
bool isDocumentUri(const QJniObject &uri) bool isDocumentUri(const QJniObject &uri)
{ {
return QJniObject::callStaticMethod<jboolean>( return QJniObject::callStaticMethod<jboolean>(
QtJniTypes::className<QtJniTypes::DocumentsContract>(), QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"isDocumentUri", "isDocumentUri",
QNativeInterface::QAndroidApplication::context(), QNativeInterface::QAndroidApplication::context(),
uri.object<QtJniTypes::UriType>()); uri.object<QtJniTypes::UriType>());
@ -509,7 +509,7 @@ bool isDocumentUri(const QJniObject &uri)
bool isTreeUri(const QJniObject &uri) bool isTreeUri(const QJniObject &uri)
{ {
return QJniObject::callStaticMethod<jboolean>( return QJniObject::callStaticMethod<jboolean>(
QtJniTypes::className<QtJniTypes::DocumentsContract>(), QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"isTreeUri", "isTreeUri",
uri.object<QtJniTypes::UriType>()); uri.object<QtJniTypes::UriType>());
} }
@ -518,7 +518,7 @@ QJniObject createDocument(const QJniObject &parentDocumentUri, const QString &mi
const QString &displayName) const QString &displayName)
{ {
return QJniObject::callStaticMethod<QtJniTypes::UriType>( return QJniObject::callStaticMethod<QtJniTypes::UriType>(
QtJniTypes::className<QtJniTypes::DocumentsContract>(), QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"createDocument", "createDocument",
contentResolverInstance().object<QtJniTypes::ContentResolverType>(), contentResolverInstance().object<QtJniTypes::ContentResolverType>(),
parentDocumentUri.object<QtJniTypes::UriType>(), parentDocumentUri.object<QtJniTypes::UriType>(),
@ -533,7 +533,7 @@ bool deleteDocument(const QJniObject &documentUri)
return {}; return {};
return QJniObject::callStaticMethod<jboolean>( return QJniObject::callStaticMethod<jboolean>(
QtJniTypes::className<QtJniTypes::DocumentsContract>(), QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"deleteDocument", "deleteDocument",
contentResolverInstance().object<QtJniTypes::ContentResolverType>(), contentResolverInstance().object<QtJniTypes::ContentResolverType>(),
documentUri.object<QtJniTypes::UriType>()); documentUri.object<QtJniTypes::UriType>());
@ -548,7 +548,7 @@ QJniObject moveDocument(const QJniObject &sourceDocumentUri,
return {}; return {};
return QJniObject::callStaticMethod<QtJniTypes::UriType>( return QJniObject::callStaticMethod<QtJniTypes::UriType>(
QtJniTypes::className<QtJniTypes::DocumentsContract>(), QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"moveDocument", "moveDocument",
contentResolverInstance().object<QtJniTypes::ContentResolverType>(), contentResolverInstance().object<QtJniTypes::ContentResolverType>(),
sourceDocumentUri.object<QtJniTypes::UriType>(), sourceDocumentUri.object<QtJniTypes::UriType>(),
@ -563,7 +563,7 @@ QJniObject renameDocument(const QJniObject &documentUri, const QString &displayN
return {}; return {};
return QJniObject::callStaticMethod<QtJniTypes::UriType>( return QJniObject::callStaticMethod<QtJniTypes::UriType>(
QtJniTypes::className<QtJniTypes::DocumentsContract>(), QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"renameDocument", "renameDocument",
contentResolverInstance().object<QtJniTypes::ContentResolverType>(), contentResolverInstance().object<QtJniTypes::ContentResolverType>(),
documentUri.object<QtJniTypes::UriType>(), documentUri.object<QtJniTypes::UriType>(),
@ -598,7 +598,7 @@ QJniObject parseUri(const QString &uri)
uriToParse.replace(' ', QUrl::toPercentEncoding(" ")); uriToParse.replace(' ', QUrl::toPercentEncoding(" "));
return QJniObject::callStaticMethod<QtJniTypes::UriType>( return QJniObject::callStaticMethod<QtJniTypes::UriType>(
QtJniTypes::className<QtJniTypes::Uri>(), QtJniTypes::Traits<QtJniTypes::Uri>::className(),
"parse", "parse",
QJniObject::fromString(uriToParse).object<jstring>()); QJniObject::fromString(uriToParse).object<jstring>());
} }

View File

@ -66,7 +66,7 @@ namespace {
QAndroidPlatformScreen* createScreenForDisplayId(int displayId) QAndroidPlatformScreen* createScreenForDisplayId(int displayId)
{ {
const QJniObject display = QJniObject::callStaticObjectMethod<QtJniTypes::Display>( const QJniObject display = QJniObject::callStaticObjectMethod<QtJniTypes::Display>(
QtJniTypes::className<QtJniTypes::QtNative>(), QtJniTypes::Traits<QtJniTypes::QtNative>::className(),
"getDisplay", "getDisplay",
displayId); displayId);
if (!display.isValid()) if (!display.isValid())
@ -184,10 +184,10 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
qFatal("Could not bind GL_ES API"); qFatal("Could not bind GL_ES API");
m_primaryDisplayId = QJniObject::getStaticField<jint>( m_primaryDisplayId = QJniObject::getStaticField<jint>(
QtJniTypes::className<QtJniTypes::Display>(), "DEFAULT_DISPLAY"); QtJniTypes::Traits<QtJniTypes::Display>::className(), "DEFAULT_DISPLAY");
const QJniObject nativeDisplaysList = QJniObject::callStaticObjectMethod<QtJniTypes::List>( const QJniObject nativeDisplaysList = QJniObject::callStaticObjectMethod<QtJniTypes::List>(
QtJniTypes::className<QtJniTypes::QtNative>(), QtJniTypes::Traits<QtJniTypes::QtNative>::className(),
"getAvailableDisplays"); "getAvailableDisplays");
const int numberOfAvailableDisplays = nativeDisplaysList.callMethod<jint>("size"); const int numberOfAvailableDisplays = nativeDisplaysList.callMethod<jint>("size");

View File

@ -92,7 +92,7 @@ QAndroidPlatformScreen::QAndroidPlatformScreen(const QJniObject &displayObject)
displayObject.object<QtJniTypes::Display>()); displayObject.object<QtJniTypes::Display>());
const auto sizeObj = QJniObject::callStaticMethod<QtJniTypes::Size>( const auto sizeObj = QJniObject::callStaticMethod<QtJniTypes::Size>(
QtJniTypes::className<QtJniTypes::QtNative>(), QtJniTypes::Traits<QtJniTypes::QtNative>::className(),
"getDisplaySize", "getDisplaySize",
displayContext.object<QtJniTypes::Context>(), displayContext.object<QtJniTypes::Context>(),
displayObject.object<QtJniTypes::Display>()); displayObject.object<QtJniTypes::Display>());

View File

@ -78,11 +78,11 @@ bool QAndroidPlatformServices::openUrl(const QUrl &theUrl)
const auto providerName = QJniObject::fromString(appId + ".qtprovider"_L1); const auto providerName = QJniObject::fromString(appId + ".qtprovider"_L1);
const auto urlPath = QJniObject::fromString(url.path()); const auto urlPath = QJniObject::fromString(url.path());
const auto urlFile = QJniObject(QtJniTypes::className<QtJniTypes::File>(), const auto urlFile = QJniObject(QtJniTypes::Traits<QtJniTypes::File>::className(),
urlPath.object<jstring>()); urlPath.object<jstring>());
const auto fileProviderUri = QJniObject::callStaticMethod<QtJniTypes::UriType>( const auto fileProviderUri = QJniObject::callStaticMethod<QtJniTypes::UriType>(
QtJniTypes::className<QtJniTypes::FileProvider>(), "getUriForFile", QtJniTypes::Traits<QtJniTypes::FileProvider>::className(), "getUriForFile",
QAndroidApplication::context(), providerName.object<jstring>(), QAndroidApplication::context(), providerName.object<jstring>(),
urlFile.object<QtJniTypes::FileType>()); urlFile.object<QtJniTypes::FileType>());

View File

@ -19,35 +19,45 @@ private slots:
struct QtJavaWrapper {}; struct QtJavaWrapper {};
template<> template<>
constexpr auto QtJniTypes::typeSignature<QtJavaWrapper>() struct QtJniTypes::Traits<QtJavaWrapper>
{ {
return QtJniTypes::CTString("Lorg/qtproject/qt/android/QtJavaWrapper;"); static constexpr auto signature()
} {
return QtJniTypes::CTString("Lorg/qtproject/qt/android/QtJavaWrapper;");
}
};
template<> template<>
constexpr auto QtJniTypes::typeSignature<QJniObject>() struct QtJniTypes::Traits<QJniObject>
{ {
return QtJniTypes::CTString("Ljava/lang/Object;"); static constexpr auto signature()
} {
return QtJniTypes::CTString("Ljava/lang/Object;");
}
};
struct QtCustomJniObject : QJniObject {}; struct QtCustomJniObject : QJniObject {};
template<>
constexpr auto QtJniTypes::typeSignature<QtCustomJniObject>()
{
return QtJniTypes::CTString("Lorg/qtproject/qt/android/QtCustomJniObject;");
}
static_assert(QtJniTypes::typeSignature<QtJavaWrapper>() == "Lorg/qtproject/qt/android/QtJavaWrapper;"); template<>
static_assert(QtJniTypes::typeSignature<QtJavaWrapper>() != "Ljava/lang/Object;"); struct QtJniTypes::Traits<QtCustomJniObject>
static_assert(!(QtJniTypes::typeSignature<QtJavaWrapper>() == "X")); {
static constexpr auto signature()
{
return QtJniTypes::CTString("Lorg/qtproject/qt/android/QtCustomJniObject;");
}
};
static_assert(QtJniTypes::Traits<QtJavaWrapper>::signature() == "Lorg/qtproject/qt/android/QtJavaWrapper;");
static_assert(QtJniTypes::Traits<QtJavaWrapper>::signature() != "Ljava/lang/Object;");
static_assert(!(QtJniTypes::Traits<QtJavaWrapper>::signature() == "X"));
Q_DECLARE_JNI_CLASS(JavaType, "org/qtproject/qt/JavaType"); Q_DECLARE_JNI_CLASS(JavaType, "org/qtproject/qt/JavaType");
static_assert(QtJniTypes::typeSignature<QtJniTypes::JavaType>() == "Lorg/qtproject/qt/JavaType;"); static_assert(QtJniTypes::Traits<QtJniTypes::JavaType>::signature() == "Lorg/qtproject/qt/JavaType;");
Q_DECLARE_JNI_TYPE(ArrayType, "[Lorg/qtproject/qt/ArrayType;") Q_DECLARE_JNI_TYPE(ArrayType, "[Lorg/qtproject/qt/ArrayType;")
static_assert(QtJniTypes::typeSignature<QtJniTypes::ArrayType>() == "[Lorg/qtproject/qt/ArrayType;"); static_assert(QtJniTypes::Traits<QtJniTypes::ArrayType>::signature() == "[Lorg/qtproject/qt/ArrayType;");
Q_DECLARE_JNI_CLASS(QtTextToSpeech, "org/qtproject/qt/android/speech/QtTextToSpeech") Q_DECLARE_JNI_CLASS(QtTextToSpeech, "org/qtproject/qt/android/speech/QtTextToSpeech")
static_assert(QtJniTypes::className<QtJniTypes::QtTextToSpeech>() == "org/qtproject/qt/android/speech/QtTextToSpeech"); static_assert(QtJniTypes::Traits<QtJniTypes::QtTextToSpeech>::className() == "org/qtproject/qt/android/speech/QtTextToSpeech");
static_assert(QtJniTypes::fieldSignature<jint>() == "I"); static_assert(QtJniTypes::fieldSignature<jint>() == "I");
static_assert(QtJniTypes::fieldSignature<jint[]>() == "[I"); static_assert(QtJniTypes::fieldSignature<jint[]>() == "[I");