| /* |
| * 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. |
| */ |
| |
| // Android's FindClass() is tricky because the app-specific ClassLoader is not |
| // consulted when there is no app-specific frame on the stack (i.e. when called |
| // from a thread created from native C++ code). These helper functions provide a |
| // workaround for this. |
| // http://developer.android.com/training/articles/perf-jni.html#faq_FindClass |
| |
| #ifndef SDK_ANDROID_NATIVE_API_JNI_JAVA_TYPES_H_ |
| #define SDK_ANDROID_NATIVE_API_JNI_JAVA_TYPES_H_ |
| |
| #include <jni.h> |
| |
| #include <map> |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "absl/types/optional.h" |
| #include "api/array_view.h" |
| #include "api/sequence_checker.h" |
| #include "rtc_base/checks.h" |
| #include "sdk/android/native_api/jni/scoped_java_ref.h" |
| |
| // Abort the process if |jni| has a Java exception pending. |
| // This macros uses the comma operator to execute ExceptionDescribe |
| // and ExceptionClear ignoring their return values and sending "" |
| // to the error stream. |
| #define CHECK_EXCEPTION(jni) \ |
| RTC_CHECK(!jni->ExceptionCheck()) \ |
| << (jni->ExceptionDescribe(), jni->ExceptionClear(), "") |
| |
| namespace webrtc { |
| |
| // --------------- |
| // -- Utilities -- |
| // --------------- |
| |
| // Provides a convenient way to iterate over a Java Iterable using the |
| // C++ range-for loop. |
| // E.g. for (jobject value : Iterable(jni, j_iterable)) { ... } |
| // Note: Since Java iterators cannot be duplicated, the iterator class is not |
| // copyable to prevent creating multiple C++ iterators that refer to the same |
| // Java iterator. |
| class Iterable { |
| public: |
| Iterable(JNIEnv* jni, const JavaRef<jobject>& iterable); |
| Iterable(Iterable&& other); |
| |
| ~Iterable(); |
| |
| class Iterator { |
| public: |
| // Creates an iterator representing the end of any collection. |
| Iterator(); |
| // Creates an iterator pointing to the beginning of the specified |
| // collection. |
| Iterator(JNIEnv* jni, const JavaRef<jobject>& iterable); |
| |
| // Move constructor - necessary to be able to return iterator types from |
| // functions. |
| Iterator(Iterator&& other); |
| |
| ~Iterator(); |
| |
| // Move assignment should not be used. |
| Iterator& operator=(Iterator&&) = delete; |
| |
| // Advances the iterator one step. |
| Iterator& operator++(); |
| |
| // Removes the element the iterator is pointing to. Must still advance the |
| // iterator afterwards. |
| void Remove(); |
| |
| // 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 operator==(const Iterator& other); |
| bool operator!=(const Iterator& other) { return !(*this == other); } |
| ScopedJavaLocalRef<jobject>& operator*(); |
| |
| private: |
| bool AtEnd() const; |
| |
| JNIEnv* jni_ = nullptr; |
| ScopedJavaLocalRef<jobject> iterator_; |
| ScopedJavaLocalRef<jobject> value_; |
| SequenceChecker thread_checker_; |
| |
| RTC_DISALLOW_COPY_AND_ASSIGN(Iterator); |
| }; |
| |
| Iterable::Iterator begin() { return Iterable::Iterator(jni_, iterable_); } |
| Iterable::Iterator end() { return Iterable::Iterator(); } |
| |
| private: |
| JNIEnv* jni_; |
| ScopedJavaLocalRef<jobject> iterable_; |
| |
| RTC_DISALLOW_COPY_AND_ASSIGN(Iterable); |
| }; |
| |
| // Returns true if |obj| == null in Java. |
| bool IsNull(JNIEnv* jni, const JavaRef<jobject>& obj); |
| |
| // Returns the name of a Java enum. |
| std::string GetJavaEnumName(JNIEnv* jni, const JavaRef<jobject>& j_enum); |
| |
| Iterable GetJavaMapEntrySet(JNIEnv* jni, const JavaRef<jobject>& j_map); |
| ScopedJavaLocalRef<jobject> GetJavaMapEntryKey(JNIEnv* jni, |
| const JavaRef<jobject>& j_entry); |
| ScopedJavaLocalRef<jobject> GetJavaMapEntryValue( |
| JNIEnv* jni, |
| const JavaRef<jobject>& j_entry); |
| |
| // -------------------------------------------------------- |
| // -- Methods for converting Java types to native types. -- |
| // -------------------------------------------------------- |
| |
| int64_t JavaToNativeLong(JNIEnv* env, const JavaRef<jobject>& j_long); |
| |
| absl::optional<bool> JavaToNativeOptionalBool(JNIEnv* jni, |
| const JavaRef<jobject>& boolean); |
| absl::optional<double> JavaToNativeOptionalDouble( |
| JNIEnv* jni, |
| const JavaRef<jobject>& j_double); |
| absl::optional<int32_t> JavaToNativeOptionalInt( |
| JNIEnv* jni, |
| const JavaRef<jobject>& integer); |
| |
| // Given a (UTF-16) jstring return a new UTF-8 native string. |
| std::string JavaToNativeString(JNIEnv* jni, const JavaRef<jstring>& j_string); |
| |
| template <typename T, typename Convert> |
| std::vector<T> JavaToNativeVector(JNIEnv* env, |
| const JavaRef<jobjectArray>& j_container, |
| Convert convert) { |
| std::vector<T> container; |
| const size_t size = env->GetArrayLength(j_container.obj()); |
| container.reserve(size); |
| for (size_t i = 0; i < size; ++i) { |
| container.emplace_back(convert( |
| env, ScopedJavaLocalRef<jobject>( |
| env, env->GetObjectArrayElement(j_container.obj(), i)))); |
| } |
| CHECK_EXCEPTION(env) << "Error during JavaToNativeVector"; |
| return container; |
| } |
| |
| template <typename T, typename Java_T = jobject, typename Convert> |
| std::vector<T> JavaListToNativeVector(JNIEnv* env, |
| const JavaRef<jobject>& j_list, |
| Convert convert) { |
| std::vector<T> native_list; |
| if (!j_list.is_null()) { |
| for (ScopedJavaLocalRef<jobject>& j_item : Iterable(env, j_list)) { |
| native_list.emplace_back( |
| convert(env, static_java_ref_cast<Java_T>(env, j_item))); |
| } |
| CHECK_EXCEPTION(env) << "Error during JavaListToNativeVector"; |
| } |
| return native_list; |
| } |
| |
| template <typename Key, typename T, typename Convert> |
| std::map<Key, T> JavaToNativeMap(JNIEnv* env, |
| const JavaRef<jobject>& j_map, |
| Convert convert) { |
| std::map<Key, T> container; |
| for (auto const& j_entry : GetJavaMapEntrySet(env, j_map)) { |
| container.emplace(convert(env, GetJavaMapEntryKey(env, j_entry), |
| GetJavaMapEntryValue(env, j_entry))); |
| } |
| return container; |
| } |
| |
| // Converts Map<String, String> to std::map<std::string, std::string>. |
| std::map<std::string, std::string> JavaToNativeStringMap( |
| JNIEnv* env, |
| const JavaRef<jobject>& j_map); |
| |
| // -------------------------------------------------------- |
| // -- Methods for converting native types to Java types. -- |
| // -------------------------------------------------------- |
| |
| ScopedJavaLocalRef<jobject> NativeToJavaBoolean(JNIEnv* env, bool b); |
| ScopedJavaLocalRef<jobject> NativeToJavaDouble(JNIEnv* env, double d); |
| ScopedJavaLocalRef<jobject> NativeToJavaInteger(JNIEnv* jni, int32_t i); |
| ScopedJavaLocalRef<jobject> NativeToJavaLong(JNIEnv* env, int64_t u); |
| ScopedJavaLocalRef<jstring> NativeToJavaString(JNIEnv* jni, const char* str); |
| ScopedJavaLocalRef<jstring> NativeToJavaString(JNIEnv* jni, |
| const std::string& str); |
| |
| ScopedJavaLocalRef<jobject> NativeToJavaDouble( |
| JNIEnv* jni, |
| const absl::optional<double>& optional_double); |
| ScopedJavaLocalRef<jobject> NativeToJavaInteger( |
| JNIEnv* jni, |
| const absl::optional<int32_t>& optional_int); |
| ScopedJavaLocalRef<jstring> NativeToJavaString( |
| JNIEnv* jni, |
| const absl::optional<std::string>& str); |
| |
| // Helper function for converting std::vector<T> into a Java array. |
| template <typename T, typename Convert> |
| ScopedJavaLocalRef<jobjectArray> NativeToJavaObjectArray( |
| JNIEnv* env, |
| const std::vector<T>& container, |
| jclass clazz, |
| Convert convert) { |
| ScopedJavaLocalRef<jobjectArray> j_container( |
| env, env->NewObjectArray(container.size(), clazz, nullptr)); |
| int i = 0; |
| for (const T& element : container) { |
| env->SetObjectArrayElement(j_container.obj(), i, |
| convert(env, element).obj()); |
| ++i; |
| } |
| return j_container; |
| } |
| |
| ScopedJavaLocalRef<jbyteArray> NativeToJavaByteArray( |
| JNIEnv* env, |
| rtc::ArrayView<int8_t> container); |
| ScopedJavaLocalRef<jintArray> NativeToJavaIntArray( |
| JNIEnv* env, |
| rtc::ArrayView<int32_t> container); |
| |
| std::vector<int8_t> JavaToNativeByteArray(JNIEnv* env, |
| const JavaRef<jbyteArray>& jarray); |
| std::vector<int32_t> JavaToNativeIntArray(JNIEnv* env, |
| const JavaRef<jintArray>& jarray); |
| |
| ScopedJavaLocalRef<jobjectArray> NativeToJavaBooleanArray( |
| JNIEnv* env, |
| const std::vector<bool>& container); |
| ScopedJavaLocalRef<jobjectArray> NativeToJavaDoubleArray( |
| JNIEnv* env, |
| const std::vector<double>& container); |
| ScopedJavaLocalRef<jobjectArray> NativeToJavaIntegerArray( |
| JNIEnv* env, |
| const std::vector<int32_t>& container); |
| ScopedJavaLocalRef<jobjectArray> NativeToJavaLongArray( |
| JNIEnv* env, |
| const std::vector<int64_t>& container); |
| ScopedJavaLocalRef<jobjectArray> NativeToJavaStringArray( |
| JNIEnv* env, |
| const std::vector<std::string>& container); |
| |
| // This is a helper class for NativeToJavaList(). Use that function instead of |
| // using this class directly. |
| class JavaListBuilder { |
| public: |
| explicit JavaListBuilder(JNIEnv* env); |
| ~JavaListBuilder(); |
| void add(const JavaRef<jobject>& element); |
| ScopedJavaLocalRef<jobject> java_list() { return j_list_; } |
| |
| private: |
| JNIEnv* env_; |
| ScopedJavaLocalRef<jobject> j_list_; |
| }; |
| |
| template <typename C, typename Convert> |
| ScopedJavaLocalRef<jobject> NativeToJavaList(JNIEnv* env, |
| const C& container, |
| Convert convert) { |
| JavaListBuilder builder(env); |
| for (const auto& e : container) |
| builder.add(convert(env, e)); |
| return builder.java_list(); |
| } |
| |
| // This is a helper class for NativeToJavaMap(). Use that function instead of |
| // using this class directly. |
| class JavaMapBuilder { |
| public: |
| explicit JavaMapBuilder(JNIEnv* env); |
| ~JavaMapBuilder(); |
| void put(const JavaRef<jobject>& key, const JavaRef<jobject>& value); |
| ScopedJavaLocalRef<jobject> GetJavaMap() { return j_map_; } |
| |
| private: |
| JNIEnv* env_; |
| ScopedJavaLocalRef<jobject> j_map_; |
| }; |
| |
| template <typename C, typename Convert> |
| ScopedJavaLocalRef<jobject> NativeToJavaMap(JNIEnv* env, |
| const C& container, |
| Convert convert) { |
| JavaMapBuilder builder(env); |
| for (const auto& e : container) { |
| const auto key_value_pair = convert(env, e); |
| builder.put(key_value_pair.first, key_value_pair.second); |
| } |
| return builder.GetJavaMap(); |
| } |
| |
| template <typename C> |
| ScopedJavaLocalRef<jobject> NativeToJavaStringMap(JNIEnv* env, |
| const C& container) { |
| JavaMapBuilder builder(env); |
| for (const auto& e : container) { |
| const auto key_value_pair = std::make_pair( |
| NativeToJavaString(env, e.first), NativeToJavaString(env, e.second)); |
| builder.put(key_value_pair.first, key_value_pair.second); |
| } |
| return builder.GetJavaMap(); |
| } |
| |
| // Return a |jlong| that will correctly convert back to |ptr|. This is needed |
| // because the alternative (of silently passing a 32-bit pointer to a vararg |
| // function expecting a 64-bit param) picks up garbage in the high 32 bits. |
| jlong NativeToJavaPointer(void* ptr); |
| |
| // ------------------------ |
| // -- Deprecated methods -- |
| // ------------------------ |
| |
| // Deprecated. Use JavaToNativeString. |
| inline std::string JavaToStdString(JNIEnv* jni, |
| const JavaRef<jstring>& j_string) { |
| return JavaToNativeString(jni, j_string); |
| } |
| |
| // Deprecated. Use scoped jobjects instead. |
| inline std::string JavaToStdString(JNIEnv* jni, jstring j_string) { |
| return JavaToStdString(jni, JavaParamRef<jstring>(j_string)); |
| } |
| |
| // Deprecated. Use JavaListToNativeVector<std::string, jstring> instead. |
| // Given a List of (UTF-16) jstrings |
| // return a new vector of UTF-8 native strings. |
| std::vector<std::string> JavaToStdVectorStrings(JNIEnv* jni, |
| const JavaRef<jobject>& list); |
| |
| // Deprecated. Use JavaToNativeStringMap instead. |
| // Parses Map<String, String> to std::map<std::string, std::string>. |
| inline std::map<std::string, std::string> JavaToStdMapStrings( |
| JNIEnv* jni, |
| const JavaRef<jobject>& j_map) { |
| return JavaToNativeStringMap(jni, j_map); |
| } |
| |
| // Deprecated. Use scoped jobjects instead. |
| inline std::map<std::string, std::string> JavaToStdMapStrings(JNIEnv* jni, |
| jobject j_map) { |
| return JavaToStdMapStrings(jni, JavaParamRef<jobject>(j_map)); |
| } |
| |
| } // namespace webrtc |
| |
| #endif // SDK_ANDROID_NATIVE_API_JNI_JAVA_TYPES_H_ |