2018-12-31 20:04:05 +01:00
|
|
|
//
|
2022-12-31 22:28:08 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
|
2018-12-31 20:04:05 +01:00
|
|
|
//
|
|
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
//
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <jni.h>
|
|
|
|
|
|
|
|
#include <cstdint>
|
|
|
|
#include <memory>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace td {
|
|
|
|
namespace td_api {
|
|
|
|
class keyboardButton;
|
|
|
|
class inlineKeyboardButton;
|
2019-02-07 00:58:27 +01:00
|
|
|
class pageBlockTableCell;
|
2018-12-31 20:04:05 +01:00
|
|
|
} // namespace td_api
|
|
|
|
|
|
|
|
namespace jni {
|
|
|
|
|
|
|
|
extern thread_local bool parse_error;
|
|
|
|
|
|
|
|
extern jclass ArrayKeyboardButtonClass;
|
|
|
|
extern jclass ArrayInlineKeyboardButtonClass;
|
2019-02-07 00:58:27 +01:00
|
|
|
extern jclass ArrayPageBlockTableCellClass;
|
2018-12-31 20:04:05 +01:00
|
|
|
extern jmethodID GetConstructorID;
|
|
|
|
extern jmethodID BooleanGetValueMethodID;
|
|
|
|
extern jmethodID IntegerGetValueMethodID;
|
|
|
|
extern jmethodID LongGetValueMethodID;
|
|
|
|
extern jmethodID DoubleGetValueMethodID;
|
|
|
|
|
2018-01-22 10:51:04 +01:00
|
|
|
jclass get_jclass(JNIEnv *env, const char *class_name);
|
|
|
|
|
|
|
|
jmethodID get_method_id(JNIEnv *env, jclass clazz, const char *name, const char *signature);
|
|
|
|
|
|
|
|
jfieldID get_field_id(JNIEnv *env, jclass clazz, const char *name, const char *signature);
|
|
|
|
|
|
|
|
void register_native_method(JNIEnv *env, jclass clazz, std::string name, std::string signature, void *function_ptr);
|
|
|
|
|
2018-01-28 11:20:43 +01:00
|
|
|
class JvmThreadDetacher {
|
|
|
|
JavaVM *java_vm_;
|
|
|
|
|
|
|
|
void detach() {
|
|
|
|
if (java_vm_ != nullptr) {
|
|
|
|
java_vm_->DetachCurrentThread();
|
|
|
|
java_vm_ = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2018-02-01 23:44:51 +01:00
|
|
|
explicit JvmThreadDetacher(JavaVM *java_vm) : java_vm_(java_vm) {
|
2018-01-28 11:20:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
JvmThreadDetacher(const JvmThreadDetacher &other) = delete;
|
|
|
|
JvmThreadDetacher &operator=(const JvmThreadDetacher &other) = delete;
|
2018-02-01 23:44:51 +01:00
|
|
|
JvmThreadDetacher(JvmThreadDetacher &&other) : java_vm_(other.java_vm_) {
|
2018-01-28 11:20:43 +01:00
|
|
|
other.java_vm_ = nullptr;
|
|
|
|
}
|
|
|
|
JvmThreadDetacher &operator=(JvmThreadDetacher &&other) = delete;
|
|
|
|
~JvmThreadDetacher() {
|
|
|
|
detach();
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator()(JNIEnv *env) {
|
|
|
|
detach();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
std::unique_ptr<JNIEnv, JvmThreadDetacher> get_jni_env(JavaVM *java_vm, jint jni_version);
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
std::string fetch_string(JNIEnv *env, jobject o, jfieldID id);
|
|
|
|
|
|
|
|
inline jobject fetch_object(JNIEnv *env, const jobject &o, const jfieldID &id) {
|
|
|
|
// null return object is implicitly allowed
|
|
|
|
return env->GetObjectField(o, id);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool have_parse_error() {
|
|
|
|
return parse_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void reset_parse_error() {
|
|
|
|
parse_error = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string from_jstring(JNIEnv *env, jstring s);
|
|
|
|
|
|
|
|
jstring to_jstring(JNIEnv *env, const std::string &s);
|
|
|
|
|
|
|
|
std::string from_bytes(JNIEnv *env, jbyteArray arr);
|
|
|
|
|
|
|
|
jbyteArray to_bytes(JNIEnv *env, const std::string &b);
|
|
|
|
|
2018-01-22 10:51:04 +01:00
|
|
|
void init_vars(JNIEnv *env, const char *td_api_java_package);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
jintArray store_vector(JNIEnv *env, const std::vector<std::int32_t> &v);
|
|
|
|
|
|
|
|
jlongArray store_vector(JNIEnv *env, const std::vector<std::int64_t> &v);
|
|
|
|
|
|
|
|
jdoubleArray store_vector(JNIEnv *env, const std::vector<double> &v);
|
|
|
|
|
|
|
|
jobjectArray store_vector(JNIEnv *env, const std::vector<std::string> &v);
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
jobjectArray store_vector(JNIEnv *env, const std::vector<T> &v) {
|
2021-10-20 00:27:02 +02:00
|
|
|
auto length = static_cast<jint>(v.size());
|
2018-12-31 20:04:05 +01:00
|
|
|
jobjectArray arr = env->NewObjectArray(length, T::element_type::Class, jobject());
|
2018-01-15 14:47:24 +01:00
|
|
|
if (arr != nullptr) {
|
2018-12-31 20:04:05 +01:00
|
|
|
for (jint i = 0; i < length; i++) {
|
|
|
|
if (v[i] != nullptr) {
|
|
|
|
jobject stored_object;
|
|
|
|
v[i]->store(env, stored_object);
|
|
|
|
if (stored_object) {
|
|
|
|
env->SetObjectArrayElement(arr, i, stored_object);
|
|
|
|
env->DeleteLocalRef(stored_object);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return arr;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
class get_array_class {
|
|
|
|
static jclass get();
|
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
|
|
|
class get_array_class<td_api::keyboardButton> {
|
|
|
|
public:
|
|
|
|
static jclass get() {
|
|
|
|
return ArrayKeyboardButtonClass;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
|
|
|
class get_array_class<td_api::inlineKeyboardButton> {
|
|
|
|
public:
|
|
|
|
static jclass get() {
|
|
|
|
return ArrayInlineKeyboardButtonClass;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-02-07 00:58:27 +01:00
|
|
|
template <>
|
|
|
|
class get_array_class<td_api::pageBlockTableCell> {
|
|
|
|
public:
|
|
|
|
static jclass get() {
|
|
|
|
return ArrayPageBlockTableCellClass;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
template <class T>
|
|
|
|
jobjectArray store_vector(JNIEnv *env, const std::vector<std::vector<T>> &v) {
|
2021-10-20 00:27:02 +02:00
|
|
|
auto length = static_cast<jint>(v.size());
|
2018-12-31 20:04:05 +01:00
|
|
|
jobjectArray arr = env->NewObjectArray(length, get_array_class<typename T::element_type>::get(), 0);
|
2018-01-15 14:47:24 +01:00
|
|
|
if (arr != nullptr) {
|
2018-12-31 20:04:05 +01:00
|
|
|
for (jint i = 0; i < length; i++) {
|
|
|
|
auto stored_array = store_vector(env, v[i]);
|
|
|
|
if (stored_array) {
|
|
|
|
env->SetObjectArrayElement(arr, i, stored_array);
|
|
|
|
env->DeleteLocalRef(stored_array);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return arr;
|
|
|
|
}
|
|
|
|
|
2018-01-15 14:47:24 +01:00
|
|
|
template <class T>
|
|
|
|
auto fetch_tl_object(JNIEnv *env, jobject obj) {
|
|
|
|
decltype(T::fetch(env, obj)) result;
|
|
|
|
if (obj != nullptr) {
|
|
|
|
result = T::fetch(env, obj);
|
|
|
|
env->DeleteLocalRef(obj);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::int32_t> fetch_vector(JNIEnv *env, jintArray arr);
|
|
|
|
|
|
|
|
std::vector<std::int64_t> fetch_vector(JNIEnv *env, jlongArray arr);
|
|
|
|
|
|
|
|
std::vector<double> fetch_vector(JNIEnv *env, jdoubleArray arr);
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
struct FetchVector {
|
|
|
|
static auto fetch(JNIEnv *env, jobjectArray arr) {
|
|
|
|
std::vector<decltype(fetch_tl_object<T>(env, jobject()))> result;
|
|
|
|
if (arr != nullptr) {
|
|
|
|
jsize length = env->GetArrayLength(arr);
|
|
|
|
result.reserve(length);
|
|
|
|
for (jsize i = 0; i < length; i++) {
|
|
|
|
result.push_back(fetch_tl_object<T>(env, env->GetObjectArrayElement(arr, i)));
|
|
|
|
}
|
|
|
|
env->DeleteLocalRef(arr);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct FetchVector<std::string> {
|
|
|
|
static std::vector<std::string> fetch(JNIEnv *env, jobjectArray arr) {
|
|
|
|
std::vector<std::string> result;
|
|
|
|
if (arr != nullptr) {
|
|
|
|
jsize length = env->GetArrayLength(arr);
|
|
|
|
result.reserve(length);
|
|
|
|
for (jsize i = 0; i < length; i++) {
|
|
|
|
jstring str = (jstring)env->GetObjectArrayElement(arr, i);
|
2020-03-25 00:14:08 +01:00
|
|
|
result.push_back(from_jstring(env, str));
|
2018-01-15 14:47:24 +01:00
|
|
|
if (str) {
|
|
|
|
env->DeleteLocalRef(str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
env->DeleteLocalRef(arr);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-03-25 00:14:08 +01:00
|
|
|
template <>
|
|
|
|
struct FetchVector<jbyteArray> {
|
|
|
|
static std::vector<std::string> fetch(JNIEnv *env, jobjectArray arr) {
|
|
|
|
std::vector<std::string> result;
|
|
|
|
if (arr != nullptr) {
|
|
|
|
jsize length = env->GetArrayLength(arr);
|
|
|
|
result.reserve(length);
|
|
|
|
for (jsize i = 0; i < length; i++) {
|
|
|
|
jbyteArray bytes = (jbyteArray)env->GetObjectArrayElement(arr, i);
|
|
|
|
result.push_back(from_bytes(env, bytes));
|
|
|
|
if (bytes) {
|
|
|
|
env->DeleteLocalRef(bytes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
env->DeleteLocalRef(arr);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-01-15 14:47:24 +01:00
|
|
|
template <class T>
|
|
|
|
struct FetchVector<std::vector<T>> {
|
|
|
|
static auto fetch(JNIEnv *env, jobjectArray arr) {
|
|
|
|
std::vector<decltype(FetchVector<T>::fetch(env, jobjectArray()))> result;
|
|
|
|
if (arr != nullptr) {
|
|
|
|
jsize length = env->GetArrayLength(arr);
|
|
|
|
result.reserve(length);
|
|
|
|
for (jsize i = 0; i < length; i++) {
|
|
|
|
result.push_back(FetchVector<T>::fetch(env, (jobjectArray)env->GetObjectArrayElement(arr, i)));
|
|
|
|
}
|
|
|
|
env->DeleteLocalRef(arr);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
} // namespace jni
|
|
|
|
} // namespace td
|