| // 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. |
| |
| #ifndef BASE_ANDROID_CALLBACK_ANDROID_H_ |
| #define BASE_ANDROID_CALLBACK_ANDROID_H_ |
| |
| #include <string> |
| #include <type_traits> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/android/scoped_java_ref.h" |
| #include "base/base_export.h" |
| #include "base/functional/callback.h" |
| #include "base/time/time.h" |
| #include "base/types/optional_ref.h" |
| #include "third_party/jni_zero/default_conversions.h" |
| #include "third_party/jni_zero/jni_zero.h" |
| |
| // Provides helper utility methods that run the given callback with the |
| // specified argument. |
| namespace base::android { |
| |
| using JniOnceWrappedCallbackType = |
| base::OnceCallback<void(const jni_zero::JavaRef<jobject>&)>; |
| using JniRepeatingWrappedCallbackType = |
| base::RepeatingCallback<void(const jni_zero::JavaRef<jobject>&)>; |
| using JniOnceWrappedCallback2Type = |
| base::OnceCallback<void(const jni_zero::JavaRef<jobject>&, |
| const jni_zero::JavaRef<jobject>&)>; |
| using JniRepeatingWrappedCallback2Type = |
| base::RepeatingCallback<void(const jni_zero::JavaRef<jobject>&, |
| const jni_zero::JavaRef<jobject>&)>; |
| |
| BASE_EXPORT void RunObjectCallbackAndroid(const JavaRef<jobject>& callback, |
| const JavaRef<jobject>& arg); |
| |
| BASE_EXPORT void RunObjectCallbackAndroid2(const JavaRef<jobject>& callback, |
| const JavaRef<jobject>& arg1, |
| const JavaRef<jobject>& arg2); |
| |
| BASE_EXPORT void RunBooleanCallbackAndroid(const JavaRef<jobject>& callback, |
| bool arg); |
| |
| BASE_EXPORT void RunIntCallbackAndroid(const JavaRef<jobject>& callback, |
| int32_t arg); |
| |
| BASE_EXPORT void RunLongCallbackAndroid(const JavaRef<jobject>& callback, |
| int64_t arg); |
| |
| BASE_EXPORT void RunTimeCallbackAndroid(const JavaRef<jobject>& callback, |
| base::Time time); |
| |
| BASE_EXPORT void RunStringCallbackAndroid(const JavaRef<jobject>& callback, |
| const std::string& arg); |
| |
| BASE_EXPORT void RunOptionalStringCallbackAndroid( |
| const JavaRef<jobject>& callback, |
| base::optional_ref<const std::string> optional_string_arg); |
| |
| BASE_EXPORT void RunByteArrayCallbackAndroid(const JavaRef<jobject>& callback, |
| const std::vector<uint8_t>& arg); |
| |
| BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| base::OnceClosure&& callback); |
| BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| const base::RepeatingClosure& callback); |
| BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| base::RepeatingClosure&& callback); |
| BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| JniOnceWrappedCallbackType&& callback); |
| BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| JniRepeatingWrappedCallbackType&& callback); |
| BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| const JniRepeatingWrappedCallbackType& callback); |
| BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| JniOnceWrappedCallback2Type&& callback); |
| BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| JniRepeatingWrappedCallback2Type&& callback); |
| BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| const JniRepeatingWrappedCallback2Type& callback); |
| |
| // Java Callbacks don't return a value so any return value by the passed in |
| // callback will be ignored. |
| template <typename R, typename Arg1, typename Arg2> |
| BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| base::OnceCallback<R(Arg1, Arg2)>&& callback) { |
| return ToJniCallback( |
| env, base::BindOnce( |
| [](base::OnceCallback<R(Arg1, Arg2)> captured_callback, |
| const jni_zero::JavaRef<jobject>& j_result1, |
| const jni_zero::JavaRef<jobject>& j_result2) { |
| JNIEnv* env = jni_zero::AttachCurrentThread(); |
| std::move(captured_callback) |
| .Run(jni_zero::FromJniType<Arg1>(env, j_result1), |
| jni_zero::FromJniType<Arg2>(env, j_result2)); |
| }, |
| std::move(callback))); |
| } |
| |
| // Java Callbacks don't return a value so any return value by the passed in |
| // callback will be ignored. |
| template <typename R, typename Arg1, typename Arg2> |
| BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| const base::RepeatingCallback<R(Arg1, Arg2)>& callback) { |
| return ToJniCallback( |
| env, |
| base::BindRepeating( |
| [](const base::RepeatingCallback<R(Arg1, Arg2)>& captured_callback, |
| const jni_zero::JavaRef<jobject>& j_result1, |
| const jni_zero::JavaRef<jobject>& j_result2) { |
| JNIEnv* env = jni_zero::AttachCurrentThread(); |
| captured_callback.Run(jni_zero::FromJniType<Arg1>(env, j_result1), |
| jni_zero::FromJniType<Arg2>(env, j_result2)); |
| }, |
| callback)); |
| } |
| |
| // Java Callbacks don't return a value so any return value by the passed in |
| // callback will be ignored. |
| template <typename R, typename Arg> |
| BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| base::OnceCallback<R(Arg)>&& callback) { |
| return ToJniCallback( |
| env, base::BindOnce( |
| [](base::OnceCallback<R(Arg)> captured_callback, |
| const jni_zero::JavaRef<jobject>& j_result) { |
| JNIEnv* env = jni_zero::AttachCurrentThread(); |
| std::move(captured_callback) |
| .Run(jni_zero::FromJniType<Arg>(env, j_result)); |
| }, |
| std::move(callback))); |
| } |
| |
| // Java Callbacks don't return a value so any return value by the passed in |
| // callback will be ignored. |
| template <typename R> |
| BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| base::OnceCallback<R()>&& callback) { |
| return ToJniCallback(env, base::BindOnce( |
| [](base::OnceCallback<R()> captured_callback, |
| const jni_zero::JavaRef<jobject>& j_result) { |
| std::move(captured_callback).Run(); |
| }, |
| std::move(callback))); |
| } |
| |
| // Java Callbacks don't return a value so any return value by the passed in |
| // callback will be ignored. |
| template <typename R, typename Arg> |
| BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| const base::RepeatingCallback<R(Arg)>& callback) { |
| return ToJniCallback( |
| env, |
| base::BindRepeating( |
| [](const base::RepeatingCallback<R(Arg)>& captured_callback, |
| const jni_zero::JavaRef<jobject>& j_result) { |
| JNIEnv* env = jni_zero::AttachCurrentThread(); |
| captured_callback.Run(jni_zero::FromJniType<Arg>(env, j_result)); |
| }, |
| callback)); |
| } |
| |
| // Java Callbacks don't return a value so any return value by the passed in |
| // callback will be ignored. |
| template <typename R> |
| BASE_EXPORT ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| const base::RepeatingCallback<R()>& callback) { |
| return ToJniCallback( |
| env, base::BindRepeating( |
| [](const base::RepeatingCallback<R()>& captured_callback, |
| const jni_zero::JavaRef<jobject>& j_result) { |
| captured_callback.Run(); |
| }, |
| callback)); |
| } |
| } // namespace base::android |
| |
| namespace base::android::internal { |
| |
| template <typename T> |
| struct IsOnceCallback : std::false_type {}; |
| |
| template <> |
| struct IsOnceCallback<base::OnceCallback<void()>> : std::true_type {}; |
| |
| template <typename T> |
| struct IsOnceCallback<base::OnceCallback<void(T)>> : std::true_type { |
| using ArgType = T; |
| }; |
| |
| template <typename T1, typename T2> |
| struct IsOnceCallback<base::OnceCallback<void(T1, T2)>> : std::true_type { |
| using Arg1Type = T1; |
| using Arg2Type = T2; |
| }; |
| |
| template <typename T> |
| struct IsRepeatingCallback : std::false_type {}; |
| |
| template <> |
| struct IsRepeatingCallback<base::RepeatingCallback<void()>> : std::true_type {}; |
| |
| template <typename T> |
| struct IsRepeatingCallback<base::RepeatingCallback<void(T)>> : std::true_type { |
| using ArgType = T; |
| }; |
| |
| template <typename T1, typename T2> |
| struct IsRepeatingCallback<base::RepeatingCallback<void(T1, T2)>> |
| : std::true_type { |
| using Arg1Type = T1; |
| using Arg2Type = T2; |
| }; |
| |
| template <typename T> |
| void RunJavaCallback(const jni_zero::ScopedJavaGlobalRef<jobject>& callback, |
| T arg) { |
| JNIEnv* env = jni_zero::AttachCurrentThread(); |
| base::android::RunObjectCallbackAndroid( |
| callback, jni_zero::ToJniType(env, std::move(arg))); |
| } |
| |
| template <typename T1, typename T2> |
| void RunJavaCallback2(const jni_zero::ScopedJavaGlobalRef<jobject>& callback, |
| T1 arg1, |
| T2 arg2) { |
| JNIEnv* env = jni_zero::AttachCurrentThread(); |
| base::android::RunObjectCallbackAndroid2( |
| callback, jni_zero::ToJniType(env, std::move(arg1)), |
| jni_zero::ToJniType(env, std::move(arg2))); |
| } |
| |
| } // namespace base::android::internal |
| |
| namespace jni_zero { |
| |
| // @JniType("base::OnceCallback<void(NativeFoo)>") Callback<JavaFoo> |
| template <typename T> |
| requires(base::android::internal::IsOnceCallback<T>::value) |
| inline T FromJniType(JNIEnv* env, const JavaRef<jobject>& obj) { |
| namespace internal = base::android::internal; |
| if constexpr (std::same_as<std::remove_cvref_t<T>, base::OnceClosure>) { |
| return base::BindOnce(&jni_zero::RunRunnable, |
| jni_zero::ScopedJavaGlobalRef<jobject>(env, obj)); |
| } else if constexpr (requires { |
| typename internal::IsOnceCallback<T>::ArgType; |
| }) { |
| using ArgType = typename internal::IsOnceCallback<T>::ArgType; |
| return base::BindOnce(&internal::RunJavaCallback<ArgType>, |
| ScopedJavaGlobalRef<jobject>(env, obj)); |
| } else { |
| using Arg1Type = typename internal::IsOnceCallback<T>::Arg1Type; |
| using Arg2Type = typename internal::IsOnceCallback<T>::Arg2Type; |
| return base::BindOnce(&internal::RunJavaCallback2<Arg1Type, Arg2Type>, |
| ScopedJavaGlobalRef<jobject>(env, obj)); |
| } |
| } |
| |
| // @JniType("base::RepeatingCallback<void(NativeFoo)>") Callback<JavaFoo> |
| template <typename T> |
| requires(base::android::internal::IsRepeatingCallback<T>::value) |
| inline T FromJniType(JNIEnv* env, const JavaRef<jobject>& obj) { |
| namespace internal = base::android::internal; |
| if constexpr (std::same_as<std::remove_cvref_t<T>, base::RepeatingClosure>) { |
| return base::BindRepeating( |
| &jni_zero::RunRunnable, |
| jni_zero::ScopedJavaGlobalRef<jobject>(env, obj)); |
| } else if constexpr (requires { |
| typename internal::IsRepeatingCallback<T>::ArgType; |
| }) { |
| using ArgType = typename internal::IsRepeatingCallback<T>::ArgType; |
| return base::BindRepeating(&internal::RunJavaCallback<ArgType>, |
| ScopedJavaGlobalRef<jobject>(env, obj)); |
| } else { |
| using Arg1Type = typename internal::IsRepeatingCallback<T>::Arg1Type; |
| using Arg2Type = typename internal::IsRepeatingCallback<T>::Arg2Type; |
| return base::BindRepeating(&internal::RunJavaCallback2<Arg1Type, Arg2Type>, |
| ScopedJavaGlobalRef<jobject>(env, obj)); |
| } |
| } |
| |
| template <typename R, typename... Args> |
| inline ScopedJavaLocalRef<jobject> ToJniType( |
| JNIEnv* env, |
| base::OnceCallback<R(Args...)>&& callback) { |
| return base::android::ToJniCallback(env, std::move(callback)); |
| } |
| |
| template <> |
| inline ScopedJavaLocalRef<jobject> ToJniType<base::RepeatingClosure>( |
| JNIEnv* env, |
| const base::RepeatingClosure& callback) { |
| return base::android::ToJniCallback(env, callback); |
| } |
| |
| template <typename R, typename... Args> |
| inline ScopedJavaLocalRef<jobject> ToJniType( |
| JNIEnv* env, |
| base::RepeatingCallback<R(Args...)>&& callback) { |
| return base::android::ToJniCallback(env, std::move(callback)); |
| } |
| |
| template <typename R, typename... Args> |
| inline ScopedJavaLocalRef<jobject> ToJniType( |
| JNIEnv* env, |
| const base::RepeatingCallback<R(Args...)>& callback) { |
| return base::android::ToJniCallback(env, callback); |
| } |
| |
| } // namespace jni_zero |
| |
| #endif // BASE_ANDROID_CALLBACK_ANDROID_H_ |