| // 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) |