Commit 707869d8 authored by Volker Krause's avatar Volker Krause
Browse files

Add JNI wrapper for reading/writing properties

There is one issue with this, assigning to a auto variable copies the
property wrapper object rather than returning the value. Preventing that
is possible, but would make the owning object non-copyable as well.
parent bbbc71f1
......@@ -18,8 +18,16 @@ public:
JNI_CONSTANT(java::lang::String, ACTION_CREATE_DOCUMENT)
JNI_CONSTANT(jint, FLAG_GRANT_READ_URI_PERMISSION)
JNI_CONSTANT(android::net::Uri, OBJECT_TYPE_PROPERTY)
JNI_PROPERTY(TestClass, java::lang::String, myStringField)
JNI_PROPERTY(TestClass, int, myIntField)
JNI_PROPERTY(TestClass, android::net::Uri, myUriField)
QAndroidJniObject m_handle;
};
static_assert(sizeof(TestClass) == sizeof(QAndroidJniObject));
class JniPropertyTest : public QObject
{
Q_OBJECT
......@@ -42,6 +50,22 @@ private Q_SLOTS:
const QString p4 = ManifestPermission::READ_CALENDAR;
Q_UNUSED(p4)
QCOMPARE(QAndroidJniObject::m_staticProtocol.at(3), QLatin1String("getStaticObjectField: android/Manifest$permission READ_CALENDAR Ljava/lang/String;"));
TestClass obj;
const QString foo = obj.myStringField;
obj.myStringField = foo;
const int bar = obj.myIntField;
obj.myIntField = 42;
const QAndroidJniObject bla = obj.myUriField;
obj.myUriField = bla;
QCOMPARE(obj.m_handle.m_protocol.size(), 6);
QCOMPARE(obj.m_handle.m_protocol.at(0), QLatin1String("getObjectField: myStringField Ljava/lang/String;"));
QCOMPARE(obj.m_handle.m_protocol.at(1), QLatin1String("setField: myStringField Ljava/lang/String;"));
QCOMPARE(obj.m_handle.m_protocol.at(2), QLatin1String("getField: myIntField I"));
QCOMPARE(obj.m_handle.m_protocol.at(3), QLatin1String("setField: myIntField I"));
QCOMPARE(obj.m_handle.m_protocol.at(4), QLatin1String("getObjectField: myUriField Landroid/net/Uri;"));
QCOMPARE(obj.m_handle.m_protocol.at(5), QLatin1String("setField: myUriField Landroid/net/Uri;"));
#endif
}
};
......
......@@ -59,6 +59,26 @@ public:
return obj;
}
template <typename T>
T getField(const char *fieldName) const
{
m_protocol.push_back(QLatin1String("getField: ") + QLatin1String(fieldName) + QLatin1Char(' ') + QLatin1String(KAndroidExtras::Jni::signature<T>()));
return {};
}
QAndroidJniObject getObjectField(const char *fieldName, const char *signature) const
{
m_protocol.push_back(QLatin1String("getObjectField: ") + QLatin1String(fieldName) + QLatin1Char(' ') + QLatin1String(signature));
return {};
}
template <typename T>
void setField(const char *fieldName, const char *signature, T value)
{
Q_UNUSED(value);
m_protocol.push_back(QLatin1String("setField: ") + QLatin1String(fieldName) + QLatin1Char(' ') + QLatin1String(signature));
}
static QAndroidJniObject callStaticObjectMethod(const char *methodName, const char *signature, ...)
{
QAndroidJniObject obj;
......
......@@ -53,6 +53,71 @@ struct StaticProperty<PropType, ClassType, NameHolder, true> {
}
};
template <typename ClassType, typename OffsetHolder>
class PropertyBase {
protected:
inline QAndroidJniObject& handle() {
const auto owner = reinterpret_cast<ClassType*>(reinterpret_cast<char*>(this) - OffsetHolder::offset());
return owner->m_handle;
}
inline const QAndroidJniObject& handle() const {
const auto owner = reinterpret_cast<const ClassType*>(reinterpret_cast<const char*>(this) - OffsetHolder::offset());
return owner->m_handle;
}
};
template <typename PropType, typename ClassType, typename NameHolder, typename OffsetHolder, bool BasicType> struct Property {};
template <typename PropType, typename ClassType, typename NameHolder, typename OffsetHolder>
class Property<PropType, ClassType, NameHolder, OffsetHolder, false> : public PropertyBase<ClassType, OffsetHolder> {
public:
inline operator QAndroidJniObject() const
{
return this->handle().getObjectField(Jni::typeName<NameHolder>(), Jni::signature<PropType>());
}
inline Property& operator=(const QAndroidJniObject &value)
{
this->handle().setField(Jni::typeName<NameHolder>(), Jni::signature<PropType>(), value.object());
return *this;
}
};
template <typename ClassType, typename NameHolder, typename OffsetHolder>
class Property<java::lang::String, ClassType, NameHolder, OffsetHolder, false> : public PropertyBase<ClassType, OffsetHolder> {
public:
inline operator QAndroidJniObject() const
{
return this->handle().getObjectField(Jni::typeName<NameHolder>(), Jni::signature<java::lang::String>());
}
inline operator QString() const
{
return this->handle().getObjectField(Jni::typeName<NameHolder>(), Jni::signature<java::lang::String>()).toString();
}
inline Property& operator=(const QAndroidJniObject &value)
{
this->handle().setField(Jni::typeName<NameHolder>(), Jni::signature<java::lang::String>(), value.object());
return *this;
}
inline Property& operator=(const QString &value)
{
this->handle().setField(Jni::typeName<NameHolder>(), Jni::signature<java::lang::String>(), QAndroidJniObject::fromString(value).object());
return *this;
}
};
template <typename PropType, typename ClassType, typename NameHolder, typename OffsetHolder>
class Property<PropType, ClassType, NameHolder, OffsetHolder, true> : public PropertyBase<ClassType, OffsetHolder> {
public:
inline operator PropType() const
{
return this->handle().template getField<PropType>(Jni::typeName<NameHolder>());
}
inline Property& operator=(PropType value)
{
this->handle().setField(Jni::typeName<NameHolder>(), Jni::signature<PropType>(), value);
return *this;
}
};
}
#define JNI_CONSTANT(type, name) \
......@@ -60,6 +125,14 @@ private: \
struct name ## __NameHolder { static constexpr const char* jniName() { return "" #name; } }; \
public: \
static inline const Jni::StaticProperty<type, JniBaseType, name ## __NameHolder, Jni::is_basic_type<type>::value> name;
#define JNI_PROPERTY(Class, type, name) \
private: \
struct name ## __NameHolder { static constexpr const char* jniName() { return "" #name; } }; \
struct name ## __OffsetHolder { static constexpr std::size_t offset() { return offsetof(Class, name); } }; \
public: \
[[no_unique_address]] Jni::Property<type, Class, name ## __NameHolder, name ## __OffsetHolder, Jni::is_basic_type<type>::value> name;
}
#endif // KANDROIDEXTRAS_JNIPROPERTIES_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment