Commit 82c4fe51 authored by Volker Krause's avatar Volker Krause
Browse files

Implement JNI basic type array decoding

parent 1090ec41
Pipeline #106178 passed with stage
in 1 minute and 16 seconds
......@@ -34,6 +34,10 @@ private Q_SLOTS:
const auto a2 = Jni::fromArray<QStringList>(array);
QCOMPARE(a2.size(), 2);
QCOMPARE(a2, QStringList({ QStringLiteral("ctor: 0"), QStringLiteral("ctor: 1") }));
JNIEnv::m_arrayLength = 4;
const auto a3 = Jni::fromArray<std::vector<int>>(array);
QCOMPARE(a3.size(), 4);
#endif
}
};
......
......@@ -25,6 +25,7 @@ public:
JNI_METHOD(void, startIntent, android::content::Intent)
JNI_METHOD(android::content::Intent, getIntent)
JNI_METHOD(Jni::Array<java::lang::String>, getStringList)
JNI_METHOD(Jni::Array<jshort>, getShortList)
JNI_PROPERTY(java::lang::String, name)
......@@ -101,11 +102,12 @@ private Q_SLOTS:
j = obj.getStringList();
QStringList l = obj.getStringList();
std::vector<QString> l2 = obj.getStringList();
std::vector<jshort> l3 = obj.getShortList();
// nullptr arguments
obj.startIntent(nullptr);
QCOMPARE(obj.handle().protocol().size(), 21);
QCOMPARE(obj.handle().protocol().size(), 22);
QCOMPARE(obj.handle().protocol()[0], QLatin1String("callObjectMethod: getName ()Ljava/lang/String; ()"));
QCOMPARE(obj.handle().protocol()[1], QLatin1String("callMethod: setName (Ljava/lang/String;)V (o)"));
QCOMPARE(obj.handle().protocol()[2], QLatin1String("callMethod: setName (Ljava/lang/String;)V (o)"));
......@@ -127,7 +129,8 @@ private Q_SLOTS:
QCOMPARE(obj.handle().protocol()[17], QLatin1String("callObjectMethod: getStringList ()[Ljava/lang/String; ()"));
QCOMPARE(obj.handle().protocol()[18], QLatin1String("callObjectMethod: getStringList ()[Ljava/lang/String; ()"));
QCOMPARE(obj.handle().protocol()[19], QLatin1String("callObjectMethod: getStringList ()[Ljava/lang/String; ()"));
QCOMPARE(obj.handle().protocol()[20], QLatin1String("callMethod: startIntent (Landroid/content/Intent;)V (o)"));
QCOMPARE(obj.handle().protocol()[20], QLatin1String("callObjectMethod: getShortList ()[S ()"));
QCOMPARE(obj.handle().protocol()[21], QLatin1String("callMethod: startIntent (Landroid/content/Intent;)V (o)"));
#if 0
// stuff that must not compile
obj.setName(42);
......
......@@ -12,10 +12,11 @@
class QAndroidJniEnvironment
{
public:
inline operator JNIEnv*() const { return &m_env; }
inline JNIEnv* operator->() { return &m_env; }
private:
JNIEnv m_env;
mutable JNIEnv m_env;
};
#endif
......@@ -22,11 +22,21 @@ typedef int64_t jlong;
typedef float jfloat;
typedef double jdouble;
typedef jint jsize;
typedef void* jobject;
typedef jobject jclass;
typedef jobject jstring;
typedef jobject jarray;
typedef jarray jobjectArray;
typedef jarray jbooleanArray;
typedef jarray jbyteArray;
typedef jarray jcharArray;
typedef jarray jshortArray;
typedef jarray jintArray;
typedef jarray jlongArray;
typedef jarray jfloatArray;
typedef jarray jdoubleArray;
struct JNIEnv
{
......@@ -35,7 +45,46 @@ struct JNIEnv
inline int GetArrayLength(jobjectArray) { return m_arrayLength; }
inline jobject GetObjectArrayElement(jobjectArray, int index) { return reinterpret_cast<jobject>(index); }
inline jbooleanArray NewBooleanArray(jsize) { return nullptr; }
inline jbyteArray NewByteArray (jsize) { return nullptr; }
inline jcharArray NewCharArray (jsize) { return nullptr; }
inline jshortArray NewShortArray (jsize) { return nullptr; }
inline jintArray NewIntArray (jsize) { return nullptr; }
inline jlongArray NewLongArray (jsize) { return nullptr; }
inline jfloatArray NewFloatArray (jsize) { return nullptr; }
inline jdoubleArray NewDoubleArray (jsize) { return nullptr; }
inline jboolean* GetBooleanArrayElements(jbooleanArray, jboolean*) { return new jboolean[m_arrayLength]; }
inline jbyte* GetByteArrayElements (jbyteArray, jboolean*) { return new jbyte[m_arrayLength]; }
inline jchar* GetCharArrayElements (jcharArray, jboolean*) { return new jchar[m_arrayLength]; }
inline jshort* GetShortArrayElements (jshortArray, jboolean*) { return new jshort[m_arrayLength]; }
inline jint* GetIntArrayElements (jintArray, jboolean*) { return new jint[m_arrayLength]; }
inline jlong* GetLongArrayElements (jlongArray, jboolean*) { return new jlong[m_arrayLength]; }
inline jfloat* GetFloatArrayElements (jfloatArray, jboolean*) { return new jfloat[m_arrayLength]; }
inline jdouble* GetDoubleArrayElements (jdoubleArray, jboolean*) { return new jdouble[m_arrayLength]; }
inline void ReleaseBooleanArrayElements(jbooleanArray, jboolean *data, jint) { delete[] data; }
inline void ReleaseByteArrayElements (jbyteArray, jbyte *data, jint) { delete[] data; }
inline void ReleaseCharArrayElements (jcharArray, jchar *data, jint) { delete[] data; }
inline void ReleaseShortArrayElements (jshortArray, jshort *data, jint) { delete[] data; }
inline void ReleaseIntArrayElements (jintArray, jint *data, jint) { delete[] data; }
inline void ReleaseLongArrayElements (jlongArray, jlong *data, jint) { delete[] data; }
inline void ReleaseFloatArrayElements (jfloatArray, jfloat *data, jint) { delete[] data; }
inline void ReleaseDoubleArrayElements (jdoubleArray, jdouble *data, jint) { delete[] data; }
inline void SetBooleanArrayRegion(jbooleanArray, jsize, jsize, const jboolean*) {}
inline void SetByteArrayRegion (jbyteArray, jsize, jsize, const jbyte*) {}
inline void SetCharArrayRegion (jcharArray, jsize, jsize, const jchar*) {}
inline void SetShortArrayRegion (jshortArray, jsize, jsize, const jshort*) {}
inline void SetIntArrayRegion (jintArray, jsize, jsize, const jint*) {}
inline void SetLongArrayRegion (jlongArray, jsize, jsize, const jlong*) {}
inline void SetFloatArrayRegion (jfloatArray, jsize, jsize, const jfloat*) {}
inline void SetDoubleArrayRegion (jdoubleArray, jsize, jsize, const jdouble*) {}
static int m_arrayLength;
};
#define JNI_COMMIT 1
#define JNI_ABORT 2
#endif
......@@ -7,18 +7,44 @@
#ifndef KANDROIDEXTRAS_JNIARRAY_H
#define KANDROIDEXTRAS_JNIARRAY_H
#include "jnitypetraits.h"
#include <QAndroidJniEnvironment>
#include <QAndroidJniObject>
namespace KAndroidExtras {
///@cond internal
namespace Internal {
/** Basic type array type traits. */
template <typename T> struct array_trait {};
#define MAKE_ARRAY_TRAIT(base_type, type_name) \
template <> struct array_trait<base_type> { \
typedef base_type ## Array type; \
static inline type newArray(JNIEnv *env, jsize size) { return env->New ## type_name ## Array(size); } \
static inline base_type* getArrayElements(JNIEnv *env, type array, jboolean *isCopy) { return env->Get ## type_name ## ArrayElements(array, isCopy); } \
static inline void releaseArrayElements(JNIEnv *env, type array, base_type *data, jint mode) { return env->Release ## type_name ## ArrayElements(array, data, mode); } \
static inline void setArrayRegion(JNIEnv *env, type array, jsize start, jsize length, const base_type *data) { env->Set ## type_name ## ArrayRegion(array, start, length, data); } \
};
MAKE_ARRAY_TRAIT(jboolean, Boolean)
MAKE_ARRAY_TRAIT(jbyte, Byte)
MAKE_ARRAY_TRAIT(jchar, Char)
MAKE_ARRAY_TRAIT(jshort, Short)
MAKE_ARRAY_TRAIT(jint, Int)
MAKE_ARRAY_TRAIT(jlong, Long)
MAKE_ARRAY_TRAIT(jfloat, Float)
MAKE_ARRAY_TRAIT(jdouble, Double)
#undef MAKE_ARRAY_TRAIT
/** Meta function for retrieving a JNI array .*/
template <typename Container, typename Value> struct FromArray {};
template <typename Container, typename Value, bool is_basic> struct FromArray {};
template <typename Container>
struct FromArray<Container, QAndroidJniObject>
struct FromArray<Container, QAndroidJniObject, false>
{
inline auto operator()(const QAndroidJniObject &array) const
{
......@@ -38,7 +64,7 @@ struct FromArray<Container, QAndroidJniObject>
};
template <typename Container>
struct FromArray<Container, QString>
struct FromArray<Container, QString, false>
{
inline auto operator()(const QAndroidJniObject &array) const
{
......@@ -57,15 +83,39 @@ struct FromArray<Container, QString>
}
};
// TODO specializations for basic types
// specializations for basic types
template <typename Container, typename Value>
struct FromArray<Container, Value, true>
{
typedef array_trait<Value> _t;
inline auto operator()(const QAndroidJniObject &array) const
{
if (!array.isValid()) {
return Container{};
}
const auto a = static_cast<typename _t::type>(array.object());
QAndroidJniEnvironment env;
const auto size = env->GetArrayLength(a);
Container r;
r.reserve(size);
auto data = _t::getArrayElements(env, a, nullptr);
std::copy(data, data + size, std::back_inserter(r));
_t::releaseArrayElements(env, a, data, JNI_ABORT);
return r;
}
};
}
///@endcond
namespace Jni {
/** Convert a JNI array to a C++ container.
* Container value types can be any of QAndroidJniObject, QString or a basic JNI type.
*/
template <typename Container> constexpr __attribute__((__unused__)) Internal::FromArray<Container, typename Container::value_type> fromArray = {};
template <typename Container> constexpr __attribute__((__unused__)) Internal::FromArray<Container, typename Container::value_type, Jni::is_basic_type<typename Container::value_type>::value> fromArray = {};
}
}
......
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