blob: af02c10f4c239f17c9de6c1edd7e8c9baac68ff4 [file] [log] [blame]
/*
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "sdk/android/native_api/jni/java_types.h"
#include <memory>
#include <string>
#include <utility>
#include "sdk/android/generated_external_classes_jni/ArrayList_jni.h"
#include "sdk/android/generated_external_classes_jni/Boolean_jni.h"
#include "sdk/android/generated_external_classes_jni/Double_jni.h"
#include "sdk/android/generated_external_classes_jni/Enum_jni.h"
#include "sdk/android/generated_external_classes_jni/Integer_jni.h"
#include "sdk/android/generated_external_classes_jni/Iterable_jni.h"
#include "sdk/android/generated_external_classes_jni/Iterator_jni.h"
#include "sdk/android/generated_external_classes_jni/LinkedHashMap_jni.h"
#include "sdk/android/generated_external_classes_jni/Long_jni.h"
#include "sdk/android/generated_external_classes_jni/Map_jni.h"
#include "sdk/android/generated_native_api_jni/JniHelper_jni.h"
namespace webrtc {
Iterable::Iterable(JNIEnv* jni, const JavaRef<jobject>& iterable)
: jni_(jni), iterable_(jni, iterable) {}
Iterable::Iterable(Iterable&& other) = default;
Iterable::~Iterable() = default;
// Creates an iterator representing the end of any collection.
Iterable::Iterator::Iterator() = default;
// Creates an iterator pointing to the beginning of the specified collection.
Iterable::Iterator::Iterator(JNIEnv* jni, const JavaRef<jobject>& iterable)
: jni_(jni) {
iterator_ = JNI_Iterable::Java_Iterable_iterator(jni, iterable);
RTC_CHECK(!iterator_.is_null());
// Start at the first element in the collection.
++(*this);
}
// Move constructor - necessary to be able to return iterator types from
// functions.
Iterable::Iterator::Iterator(Iterator&& other)
: jni_(std::move(other.jni_)),
iterator_(std::move(other.iterator_)),
value_(std::move(other.value_)) {
RTC_DCHECK_RUN_ON(&thread_checker_);
}
Iterable::Iterator::~Iterator() = default;
// Advances the iterator one step.
Iterable::Iterator& Iterable::Iterator::operator++() {
RTC_DCHECK_RUN_ON(&thread_checker_);
if (AtEnd()) {
// Can't move past the end.
return *this;
}
bool has_next = JNI_Iterator::Java_Iterator_hasNext(jni_, iterator_);
if (!has_next) {
iterator_ = nullptr;
value_ = nullptr;
return *this;
}
value_ = JNI_Iterator::Java_Iterator_next(jni_, iterator_);
return *this;
}
void Iterable::Iterator::Remove() {
JNI_Iterator::Java_Iterator_remove(jni_, iterator_);
}
// Provides a way to compare the iterator with itself and with the end iterator.
// Note: all other comparison results are undefined, just like for C++ input
// iterators.
bool Iterable::Iterator::operator==(const Iterable::Iterator& other) {
// Two different active iterators should never be compared.
RTC_DCHECK(this == &other || AtEnd() || other.AtEnd());
return AtEnd() == other.AtEnd();
}
ScopedJavaLocalRef<jobject>& Iterable::Iterator::operator*() {
RTC_CHECK(!AtEnd());
return value_;
}
bool Iterable::Iterator::AtEnd() const {
RTC_DCHECK_RUN_ON(&thread_checker_);
return jni_ == nullptr || IsNull(jni_, iterator_);
}
bool IsNull(JNIEnv* jni, const JavaRef<jobject>& obj) {
return jni->IsSameObject(obj.obj(), nullptr);
}
std::string GetJavaEnumName(JNIEnv* jni, const JavaRef<jobject>& j_enum) {
return JavaToStdString(jni, JNI_Enum::Java_Enum_name(jni, j_enum));
}
Iterable GetJavaMapEntrySet(JNIEnv* jni, const JavaRef<jobject>& j_map) {
return Iterable(jni, JNI_Map::Java_Map_entrySet(jni, j_map));
}
ScopedJavaLocalRef<jobject> GetJavaMapEntryKey(
JNIEnv* jni,
const JavaRef<jobject>& j_entry) {
return jni::Java_JniHelper_getKey(jni, j_entry);
}
ScopedJavaLocalRef<jobject> GetJavaMapEntryValue(
JNIEnv* jni,
const JavaRef<jobject>& j_entry) {
return jni::Java_JniHelper_getValue(jni, j_entry);
}
int64_t JavaToNativeLong(JNIEnv* env, const JavaRef<jobject>& j_long) {
return JNI_Long::Java_Long_longValue(env, j_long);
}
absl::optional<bool> JavaToNativeOptionalBool(JNIEnv* jni,
const JavaRef<jobject>& boolean) {
if (IsNull(jni, boolean))
return absl::nullopt;
return JNI_Boolean::Java_Boolean_booleanValue(jni, boolean);
}
absl::optional<double> JavaToNativeOptionalDouble(
JNIEnv* jni,
const JavaRef<jobject>& j_double) {
if (IsNull(jni, j_double))
return absl::nullopt;
return JNI_Double::Java_Double_doubleValue(jni, j_double);
}
absl::optional<int32_t> JavaToNativeOptionalInt(
JNIEnv* jni,
const JavaRef<jobject>& integer) {
if (IsNull(jni, integer))
return absl::nullopt;
return JNI_Integer::Java_Integer_intValue(jni, integer);
}
// Given a jstring, reinterprets it to a new native string.
std::string JavaToNativeString(JNIEnv* jni, const JavaRef<jstring>& j_string) {
const ScopedJavaLocalRef<jbyteArray> j_byte_array =
jni::Java_JniHelper_getStringBytes(jni, j_string);
const size_t len = jni->GetArrayLength(j_byte_array.obj());
CHECK_EXCEPTION(jni) << "error during GetArrayLength";
std::string str(len, '\0');
jni->GetByteArrayRegion(j_byte_array.obj(), 0, len,
reinterpret_cast<jbyte*>(&str[0]));
CHECK_EXCEPTION(jni) << "error during GetByteArrayRegion";
return str;
}
std::map<std::string, std::string> JavaToNativeStringMap(
JNIEnv* jni,
const JavaRef<jobject>& j_map) {
return JavaToNativeMap<std::string, std::string>(
jni, j_map,
[](JNIEnv* env, JavaRef<jobject> const& key,
JavaRef<jobject> const& value) {
return std::make_pair(
JavaToNativeString(env, static_java_ref_cast<jstring>(env, key)),
JavaToNativeString(env, static_java_ref_cast<jstring>(env, value)));
});
}
ScopedJavaLocalRef<jobject> NativeToJavaBoolean(JNIEnv* env, bool b) {
return JNI_Boolean::Java_Boolean_ConstructorJLB_Z(env, b);
}
ScopedJavaLocalRef<jobject> NativeToJavaDouble(JNIEnv* env, double d) {
return JNI_Double::Java_Double_ConstructorJLD_D(env, d);
}
ScopedJavaLocalRef<jobject> NativeToJavaInteger(JNIEnv* jni, int32_t i) {
return JNI_Integer::Java_Integer_ConstructorJLI_I(jni, i);
}
ScopedJavaLocalRef<jobject> NativeToJavaLong(JNIEnv* env, int64_t u) {
return JNI_Long::Java_Long_ConstructorJLLO_J(env, u);
}
ScopedJavaLocalRef<jstring> NativeToJavaString(JNIEnv* env, const char* str) {
jstring j_str = env->NewStringUTF(str);
CHECK_EXCEPTION(env) << "error during NewStringUTF";
return ScopedJavaLocalRef<jstring>(env, j_str);
}
ScopedJavaLocalRef<jstring> NativeToJavaString(JNIEnv* jni,
const std::string& str) {
return NativeToJavaString(jni, str.c_str());
}
ScopedJavaLocalRef<jobject> NativeToJavaDouble(
JNIEnv* jni,
const absl::optional<double>& optional_double) {
return optional_double ? NativeToJavaDouble(jni, *optional_double) : nullptr;
}
ScopedJavaLocalRef<jobject> NativeToJavaInteger(
JNIEnv* jni,
const absl::optional<int32_t>& optional_int) {
return optional_int ? NativeToJavaInteger(jni, *optional_int) : nullptr;
}
ScopedJavaLocalRef<jstring> NativeToJavaString(
JNIEnv* jni,
const absl::optional<std::string>& str) {
return str ? NativeToJavaString(jni, *str) : nullptr;
}
ScopedJavaLocalRef<jbyteArray> NativeToJavaByteArray(
JNIEnv* env,
rtc::ArrayView<int8_t> container) {
ScopedJavaLocalRef<jbyteArray> jarray(env,
env->NewByteArray(container.size()));
int8_t* array_ptr =
env->GetByteArrayElements(jarray.obj(), /*isCopy=*/nullptr);
memcpy(array_ptr, container.data(), container.size() * sizeof(int8_t));
env->ReleaseByteArrayElements(jarray.obj(), array_ptr, /*mode=*/0);
return jarray;
}
ScopedJavaLocalRef<jintArray> NativeToJavaIntArray(
JNIEnv* env,
rtc::ArrayView<int32_t> container) {
ScopedJavaLocalRef<jintArray> jarray(env, env->NewIntArray(container.size()));
int32_t* array_ptr =
env->GetIntArrayElements(jarray.obj(), /*isCopy=*/nullptr);
memcpy(array_ptr, container.data(), container.size() * sizeof(int32_t));
env->ReleaseIntArrayElements(jarray.obj(), array_ptr, /*mode=*/0);
return jarray;
}
std::vector<int8_t> JavaToNativeByteArray(JNIEnv* env,
const JavaRef<jbyteArray>& jarray) {
int8_t* array_ptr =
env->GetByteArrayElements(jarray.obj(), /*isCopy=*/nullptr);
size_t array_length = env->GetArrayLength(jarray.obj());
std::vector<int8_t> container(array_ptr, array_ptr + array_length);
env->ReleaseByteArrayElements(jarray.obj(), array_ptr, /*mode=*/JNI_ABORT);
return container;
}
std::vector<int32_t> JavaToNativeIntArray(JNIEnv* env,
const JavaRef<jintArray>& jarray) {
int32_t* array_ptr =
env->GetIntArrayElements(jarray.obj(), /*isCopy=*/nullptr);
size_t array_length = env->GetArrayLength(jarray.obj());
std::vector<int32_t> container(array_ptr, array_ptr + array_length);
env->ReleaseIntArrayElements(jarray.obj(), array_ptr, /*mode=*/JNI_ABORT);
return container;
}
ScopedJavaLocalRef<jobjectArray> NativeToJavaBooleanArray(
JNIEnv* env,
const std::vector<bool>& container) {
return NativeToJavaObjectArray(env, container, java_lang_Boolean_clazz(env),
&NativeToJavaBoolean);
}
ScopedJavaLocalRef<jobjectArray> NativeToJavaDoubleArray(
JNIEnv* env,
const std::vector<double>& container) {
ScopedJavaLocalRef<jobject> (*convert_function)(JNIEnv*, double) =
&NativeToJavaDouble;
return NativeToJavaObjectArray(env, container, java_lang_Double_clazz(env),
convert_function);
}
ScopedJavaLocalRef<jobjectArray> NativeToJavaIntegerArray(
JNIEnv* env,
const std::vector<int32_t>& container) {
ScopedJavaLocalRef<jobject> (*convert_function)(JNIEnv*, int32_t) =
&NativeToJavaInteger;
return NativeToJavaObjectArray(env, container, java_lang_Integer_clazz(env),
convert_function);
}
ScopedJavaLocalRef<jobjectArray> NativeToJavaLongArray(
JNIEnv* env,
const std::vector<int64_t>& container) {
return NativeToJavaObjectArray(env, container, java_lang_Long_clazz(env),
&NativeToJavaLong);
}
ScopedJavaLocalRef<jobjectArray> NativeToJavaStringArray(
JNIEnv* env,
const std::vector<std::string>& container) {
ScopedJavaLocalRef<jstring> (*convert_function)(JNIEnv*, const std::string&) =
&NativeToJavaString;
return NativeToJavaObjectArray(
env, container,
static_cast<jclass>(jni::Java_JniHelper_getStringClass(env).obj()),
convert_function);
}
JavaListBuilder::JavaListBuilder(JNIEnv* env)
: env_(env), j_list_(JNI_ArrayList::Java_ArrayList_ConstructorJUALI(env)) {}
JavaListBuilder::~JavaListBuilder() = default;
void JavaListBuilder::add(const JavaRef<jobject>& element) {
JNI_ArrayList::Java_ArrayList_addZ_JUE(env_, j_list_, element);
}
JavaMapBuilder::JavaMapBuilder(JNIEnv* env)
: env_(env),
j_map_(JNI_LinkedHashMap::Java_LinkedHashMap_ConstructorJULIHM(env)) {}
JavaMapBuilder::~JavaMapBuilder() = default;
void JavaMapBuilder::put(const JavaRef<jobject>& key,
const JavaRef<jobject>& value) {
JNI_Map::Java_Map_put(env_, j_map_, key, value);
}
jlong NativeToJavaPointer(void* ptr) {
static_assert(sizeof(intptr_t) <= sizeof(jlong),
"Time to rethink the use of jlongs");
// Going through intptr_t to be obvious about the definedness of the
// conversion from pointer to integral type. intptr_t to jlong is a standard
// widening by the static_assert above.
jlong ret = reinterpret_cast<intptr_t>(ptr);
RTC_DCHECK(reinterpret_cast<void*>(ret) == ptr);
return ret;
}
// Given a list of jstrings, reinterprets it to a new vector of native strings.
std::vector<std::string> JavaToStdVectorStrings(JNIEnv* jni,
const JavaRef<jobject>& list) {
std::vector<std::string> converted_list;
if (!list.is_null()) {
for (const JavaRef<jobject>& str : Iterable(jni, list)) {
converted_list.push_back(JavaToStdString(
jni, JavaParamRef<jstring>(static_cast<jstring>(str.obj()))));
}
}
return converted_list;
}
} // namespace webrtc