| // Copyright 2016 The Chromium Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "base/android/callback_android.h" | |
| #include "base/android/jni_android.h" | |
| #include "base/android/jni_array.h" | |
| #include "base/android/jni_string.h" | |
| #include "base/android/scoped_java_ref.h" | |
| #include "base/time/time.h" | |
| #include "base/types/optional_ref.h" | |
| // Must come after all headers that specialize FromJniType() / ToJniType(). | |
| #include "base/callback_jni/Callback2_jni.h" | |
| #include "base/callback_jni/Callback_jni.h" | |
| #include "base/jni_callback_jni/JniCallbackImpl_jni.h" | |
| namespace base { | |
| namespace android { | |
| namespace { | |
| class JniOnceCallback { | |
| public: | |
| explicit JniOnceCallback(JniOnceWrappedCallbackType&& on_complete) | |
| : wrapped_callback_(std::make_unique<JniOnceWrappedCallbackType>( | |
| std::move(on_complete))) {} | |
| ~JniOnceCallback() = default; | |
| JniOnceCallback(const JniOnceCallback&) = delete; | |
| const JniOnceCallback& operator=(const JniOnceCallback&) = delete; | |
| jni_zero::ScopedJavaLocalRef<jobject> TransferToJava(JNIEnv* env) && { | |
| CHECK(wrapped_callback_); | |
| CHECK(!wrapped_callback_->is_null()); | |
| bool is_repeating = false; | |
| return Java_JniCallbackImpl_Constructor( | |
| env, is_repeating, | |
| reinterpret_cast<int64_t>(wrapped_callback_.release())); | |
| } | |
| private: | |
| std::unique_ptr<JniOnceWrappedCallbackType> wrapped_callback_; | |
| }; | |
| class JniRepeatingCallback { | |
| public: | |
| explicit JniRepeatingCallback( | |
| const JniRepeatingWrappedCallbackType& on_complete) | |
| : wrapped_callback_( | |
| std::make_unique<JniRepeatingWrappedCallbackType>(on_complete)) {} | |
| explicit JniRepeatingCallback(JniRepeatingWrappedCallbackType&& on_complete) | |
| : wrapped_callback_(std::make_unique<JniRepeatingWrappedCallbackType>( | |
| std::move(on_complete))) {} | |
| ~JniRepeatingCallback() = default; | |
| jni_zero::ScopedJavaLocalRef<jobject> TransferToJava(JNIEnv* env) && { | |
| CHECK(wrapped_callback_); | |
| CHECK(!wrapped_callback_->is_null()); | |
| bool is_repeating = true; | |
| return Java_JniCallbackImpl_Constructor( | |
| env, is_repeating, | |
| reinterpret_cast<int64_t>(wrapped_callback_.release())); | |
| } | |
| JniRepeatingCallback(const JniRepeatingCallback&) = delete; | |
| const JniRepeatingCallback& operator=(const JniRepeatingCallback&) = delete; | |
| private: | |
| std::unique_ptr<JniRepeatingWrappedCallbackType> wrapped_callback_; | |
| }; | |
| class JniOnceCallback2 { | |
| public: | |
| explicit JniOnceCallback2(JniOnceWrappedCallback2Type&& on_complete) | |
| : wrapped_callback_(std::make_unique<JniOnceWrappedCallback2Type>( | |
| std::move(on_complete))) {} | |
| ~JniOnceCallback2() = default; | |
| JniOnceCallback2(const JniOnceCallback2&) = delete; | |
| const JniOnceCallback2& operator=(const JniOnceCallback2&) = delete; | |
| jni_zero::ScopedJavaLocalRef<jobject> TransferToJava(JNIEnv* env) && { | |
| CHECK(wrapped_callback_); | |
| CHECK(!wrapped_callback_->is_null()); | |
| bool is_repeating = false; | |
| return Java_JniCallbackImpl_Constructor( | |
| env, is_repeating, | |
| reinterpret_cast<int64_t>(wrapped_callback_.release())); | |
| } | |
| private: | |
| std::unique_ptr<JniOnceWrappedCallback2Type> wrapped_callback_; | |
| }; | |
| class JniRepeatingCallback2 { | |
| public: | |
| explicit JniRepeatingCallback2( | |
| const JniRepeatingWrappedCallback2Type& on_complete) | |
| : wrapped_callback_( | |
| std::make_unique<JniRepeatingWrappedCallback2Type>(on_complete)) {} | |
| explicit JniRepeatingCallback2(JniRepeatingWrappedCallback2Type&& on_complete) | |
| : wrapped_callback_(std::make_unique<JniRepeatingWrappedCallback2Type>( | |
| std::move(on_complete))) {} | |
| ~JniRepeatingCallback2() = default; | |
| jni_zero::ScopedJavaLocalRef<jobject> TransferToJava(JNIEnv* env) && { | |
| CHECK(wrapped_callback_); | |
| CHECK(!wrapped_callback_->is_null()); | |
| bool is_repeating = true; | |
| return Java_JniCallbackImpl_Constructor( | |
| env, is_repeating, | |
| reinterpret_cast<int64_t>(wrapped_callback_.release())); | |
| } | |
| JniRepeatingCallback2(const JniRepeatingCallback2&) = delete; | |
| const JniRepeatingCallback2& operator=(const JniRepeatingCallback2&) = delete; | |
| private: | |
| std::unique_ptr<JniRepeatingWrappedCallback2Type> wrapped_callback_; | |
| }; | |
| } // namespace | |
| void RunObjectCallbackAndroid(const JavaRef<jobject>& callback, | |
| const JavaRef<jobject>& arg) { | |
| Java_Helper_onObjectResultFromNative(AttachCurrentThread(), callback, arg); | |
| } | |
| void RunObjectCallbackAndroid2(const JavaRef<jobject>& callback, | |
| const JavaRef<jobject>& arg1, | |
| const JavaRef<jobject>& arg2) { | |
| Java_JniHelper_onResultFromNative(AttachCurrentThread(), callback, arg1, | |
| arg2); | |
| } | |
| void RunBooleanCallbackAndroid(const JavaRef<jobject>& callback, bool arg) { | |
| Java_Helper_onBooleanResultFromNative(AttachCurrentThread(), callback, arg); | |
| } | |
| void RunIntCallbackAndroid(const JavaRef<jobject>& callback, int32_t arg) { | |
| Java_Helper_onIntResultFromNative(AttachCurrentThread(), callback, arg); | |
| } | |
| void RunLongCallbackAndroid(const JavaRef<jobject>& callback, int64_t arg) { | |
| Java_Helper_onLongResultFromNative(AttachCurrentThread(), callback, arg); | |
| } | |
| void RunTimeCallbackAndroid(const JavaRef<jobject>& callback, base::Time time) { | |
| RunLongCallbackAndroid(callback, time.InMillisecondsSinceUnixEpoch()); | |
| } | |
| void RunStringCallbackAndroid(const JavaRef<jobject>& callback, | |
| const std::string& arg) { | |
| JNIEnv* env = AttachCurrentThread(); | |
| ScopedJavaLocalRef<jstring> java_string = ConvertUTF8ToJavaString(env, arg); | |
| Java_Helper_onObjectResultFromNative(env, callback, java_string); | |
| } | |
| void RunOptionalStringCallbackAndroid( | |
| const JavaRef<jobject>& callback, | |
| base::optional_ref<const std::string> optional_string_arg) { | |
| JNIEnv* env = AttachCurrentThread(); | |
| RunObjectCallbackAndroid( | |
| callback, optional_string_arg | |
| ? ConvertUTF8ToJavaString(env, optional_string_arg.value()) | |
| : nullptr); | |
| } | |
| void RunByteArrayCallbackAndroid(const JavaRef<jobject>& callback, | |
| const std::vector<uint8_t>& arg) { | |
| JNIEnv* env = AttachCurrentThread(); | |
| ScopedJavaLocalRef<jbyteArray> j_bytes = ToJavaByteArray(env, arg); | |
| Java_Helper_onObjectResultFromNative(env, callback, j_bytes); | |
| } | |
| ScopedJavaLocalRef<jobject> ToJniCallback(JNIEnv* env, | |
| base::OnceClosure&& callback) { | |
| if (callback.is_null()) { | |
| return nullptr; | |
| } | |
| return ToJniCallback(env, base::BindOnce( | |
| [](base::OnceClosure captured_callback, | |
| const jni_zero::JavaRef<jobject>& j_null) { | |
| // For callbacks with no parameters, the | |
| // parameter from Java should be null. | |
| CHECK(!j_null); | |
| std::move(captured_callback).Run(); | |
| }, | |
| std::move(callback))); | |
| } | |
| ScopedJavaLocalRef<jobject> ToJniCallback( | |
| JNIEnv* env, | |
| const base::RepeatingClosure& callback) { | |
| if (callback.is_null()) { | |
| return nullptr; | |
| } | |
| return ToJniCallback(env, | |
| base::BindRepeating( | |
| [](const base::RepeatingClosure& captured_callback, | |
| const jni_zero::JavaRef<jobject>& j_null) { | |
| // For callbacks with no parameters, the parameter | |
| // from Java should be null. | |
| CHECK(!j_null); | |
| captured_callback.Run(); | |
| }, | |
| callback)); | |
| } | |
| ScopedJavaLocalRef<jobject> ToJniCallback(JNIEnv* env, | |
| base::RepeatingClosure&& callback) { | |
| if (callback.is_null()) { | |
| return nullptr; | |
| } | |
| return ToJniCallback(env, base::BindRepeating( | |
| [](base::RepeatingClosure captured_callback, | |
| const jni_zero::JavaRef<jobject>& j_null) { | |
| // For callbacks with no parameters, the | |
| // parameter from Java should be null. | |
| CHECK(!j_null); | |
| captured_callback.Run(); | |
| }, | |
| std::move(callback))); | |
| } | |
| ScopedJavaLocalRef<jobject> ToJniCallback( | |
| JNIEnv* env, | |
| JniOnceWrappedCallbackType&& callback) { | |
| return JniOnceCallback(std::move(callback)).TransferToJava(env); | |
| } | |
| ScopedJavaLocalRef<jobject> ToJniCallback( | |
| JNIEnv* env, | |
| JniRepeatingWrappedCallbackType&& callback) { | |
| return JniRepeatingCallback(std::move(callback)).TransferToJava(env); | |
| } | |
| ScopedJavaLocalRef<jobject> ToJniCallback( | |
| JNIEnv* env, | |
| const JniRepeatingWrappedCallbackType& callback) { | |
| return JniRepeatingCallback(callback).TransferToJava(env); | |
| } | |
| ScopedJavaLocalRef<jobject> ToJniCallback( | |
| JNIEnv* env, | |
| JniOnceWrappedCallback2Type&& callback) { | |
| return JniOnceCallback2(std::move(callback)).TransferToJava(env); | |
| } | |
| ScopedJavaLocalRef<jobject> ToJniCallback( | |
| JNIEnv* env, | |
| JniRepeatingWrappedCallback2Type&& callback) { | |
| return JniRepeatingCallback2(std::move(callback)).TransferToJava(env); | |
| } | |
| ScopedJavaLocalRef<jobject> ToJniCallback( | |
| JNIEnv* env, | |
| const JniRepeatingWrappedCallback2Type& callback) { | |
| return JniRepeatingCallback2(callback).TransferToJava(env); | |
| } | |
| static void JNI_JniCallbackImpl_OnResult( | |
| JNIEnv* env, | |
| bool isRepeating, | |
| int64_t callbackPtr, | |
| const jni_zero::JavaRef<jobject>& j_result) { | |
| if (isRepeating) { | |
| auto* callback = | |
| reinterpret_cast<JniRepeatingWrappedCallbackType*>(callbackPtr); | |
| callback->Run(j_result); | |
| } else { | |
| auto* callback = reinterpret_cast<JniOnceWrappedCallbackType*>(callbackPtr); | |
| std::move(*callback).Run(j_result); | |
| delete callback; | |
| } | |
| } | |
| static void JNI_JniCallbackImpl_OnResult2( | |
| JNIEnv* env, | |
| bool isRepeating, | |
| int64_t callbackPtr, | |
| const jni_zero::JavaRef<jobject>& j_result1, | |
| const jni_zero::JavaRef<jobject>& j_result2) { | |
| if (isRepeating) { | |
| auto* callback = | |
| reinterpret_cast<JniRepeatingWrappedCallback2Type*>(callbackPtr); | |
| callback->Run(j_result1, j_result2); | |
| } else { | |
| auto* callback = | |
| reinterpret_cast<JniOnceWrappedCallback2Type*>(callbackPtr); | |
| std::move(*callback).Run(j_result1, j_result2); | |
| delete callback; | |
| } | |
| } | |
| static void JNI_JniCallbackImpl_Destroy(JNIEnv* env, | |
| bool isRepeating, | |
| int64_t callbackPtr) { | |
| if (isRepeating) { | |
| auto* callback = | |
| reinterpret_cast<JniRepeatingWrappedCallbackType*>(callbackPtr); | |
| // Call Reset to ensure all accidental use-after-frees fail loudly. | |
| callback->Reset(); | |
| delete callback; | |
| } else { | |
| auto* callback = reinterpret_cast<JniOnceWrappedCallbackType*>(callbackPtr); | |
| // Call Reset to ensure all accidental use-after-frees fail loudly. | |
| callback->Reset(); | |
| delete callback; | |
| } | |
| } | |
| } // namespace android | |
| } // namespace base | |
| DEFINE_JNI(Callback) | |
| DEFINE_JNI(JniCallbackImpl) |