Index: android_webview/native/callback_jni_bridge.cc |
diff --git a/android_webview/native/callback_jni_bridge.cc b/android_webview/native/callback_jni_bridge.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f0e79b53ab3560f34c75f4de38d8715bd9664fe6 |
--- /dev/null |
+++ b/android_webview/native/callback_jni_bridge.cc |
@@ -0,0 +1,254 @@ |
+// Copyright 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "android_webview/native/callback_jni_bridge.h" |
+ |
+#include <vector> |
+ |
+#include "base/android/scoped_java_ref.h" |
+#include "base/bind.h" |
+#include "base/threading/thread_checker.h" |
+#include "jni/CallbackJNIBridge_jni.h" |
+ |
+using base::Callback; |
+using base::android::AttachCurrentThread; |
+using base::android::ScopedJavaLocalRef; |
+using base::android::ScopedJavaGlobalRef; |
+ |
+namespace android_webview { |
+ |
+namespace { |
+ |
+// A bit of template magic lets us select the right JNI invoke and create |
+// method depending on the type of arguments being processed. |
+template<typename T> |
+struct JNISelector { |
+}; |
+ |
+template<> |
+struct JNISelector<int> { |
+ static void Invoke(JNIEnv* env, jobject obj, jint value) { |
+ Java_JavaCallbackInt_invoke(env, obj, value); |
+ } |
+ |
+ static ScopedJavaLocalRef<jobject> create(JNIEnv* env, jint callbackPtr) { |
+ return Java_NativeCallbackInt_create(env, callbackPtr); |
+ } |
+}; |
+ |
+template<> |
+struct JNISelector<long> { |
+ static void Invoke(JNIEnv* env, jobject obj, jlong value) { |
+ Java_JavaCallbackLong_invoke(env, obj, value); |
+ } |
+ |
+ static ScopedJavaLocalRef<jobject> create(JNIEnv* env, jint callbackPtr) { |
+ return Java_NativeCallbackLong_create(env, callbackPtr); |
+ } |
+}; |
+ |
+template<> |
+struct JNISelector<bool> { |
+ static void Invoke(JNIEnv* env, jobject obj, jboolean value) { |
+ Java_JavaCallbackBoolean_invoke(env, obj, value); |
+ } |
+ |
+ static ScopedJavaLocalRef<jobject> create(JNIEnv* env, jint callbackPtr) { |
+ return Java_NativeCallbackBoolean_create(env, callbackPtr); |
+ } |
+}; |
+ |
+template<> |
+struct JNISelector<ScopedJavaLocalRef<jobject> > { |
+ static void Invoke(JNIEnv* env, |
+ jobject obj, |
+ const ScopedJavaLocalRef<jobject>& value) { |
+ Java_JavaCallback_invoke(env, obj, value.obj()); |
+ } |
+ |
+ static ScopedJavaLocalRef<jobject> create(JNIEnv* env, jint callbackPtr) { |
+ return Java_NativeCallback_create(env, callbackPtr); |
+ } |
+}; |
+ |
+// This wraps a Java-side ValueCallback instance. |
+template<typename T> |
+class JavaCallback { |
+ public: |
+ JavaCallback(JNIEnv* env, |
+ const ScopedJavaLocalRef<jobject>& jvalue_callback) { |
+ jvalue_callback_.Reset(env, jvalue_callback.obj()); |
mkosiba (inactive)
2013/02/25 23:43:44
I think I'll add a DCHECK here to see if jvalue_ca
|
+ } |
+ |
+ void onReceiveValue(T value) { |
+ DCHECK(!jvalue_callback_.is_null()); |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ if (!jvalue_callback_.is_null()) { |
+ JNIEnv* env = AttachCurrentThread(); |
+ JNISelector<T>::Invoke(env, jvalue_callback_.obj(), value); |
+ jvalue_callback_.Reset(); |
+ } |
+ } |
+ |
+ private: |
+ ScopedJavaGlobalRef<jobject> jvalue_callback_; |
+ base::ThreadChecker thread_checker_; |
+}; |
+ |
+template <typename T> |
+static Callback<void(T)> FromJavaCallbackTemplate( |
+ JNIEnv* env, |
+ const ScopedJavaLocalRef<jobject>& jvalue_callback) { |
+ JavaCallback<T>* value_callback = new JavaCallback<T>(env, jvalue_callback); |
+ return base::Bind(&JavaCallback<T>::onReceiveValue, |
+ base::Owned(value_callback)); |
+} |
+ |
+} // namespace |
+ |
+Callback<void(int)> CallbackJNIBridge::FromJavaCallbackInt( |
+ JNIEnv* env, |
+ const ScopedJavaLocalRef<jobject>& jvalue_callback) { |
+ return FromJavaCallbackTemplate<int>(env, jvalue_callback); |
+} |
+ |
+Callback<void(long)> CallbackJNIBridge::FromJavaCallbackLong( |
+ JNIEnv* env, |
+ const ScopedJavaLocalRef<jobject>& jvalue_callback) { |
+ return FromJavaCallbackTemplate<long>(env, jvalue_callback); |
+} |
+ |
+Callback<void(bool)> CallbackJNIBridge::FromJavaCallbackBool( |
+ JNIEnv* env, |
+ const ScopedJavaLocalRef<jobject>& jvalue_callback) { |
+ return FromJavaCallbackTemplate<bool>(env, jvalue_callback); |
+} |
+ |
+base::Callback<void(ScopedJavaLocalRef<jobject>)> |
+CallbackJNIBridge::FromJavaCallbackObj( |
+ JNIEnv* env, |
+ const ScopedJavaLocalRef<jobject>& jvalue_callback) { |
+ return FromJavaCallbackTemplate<ScopedJavaLocalRef<jobject> >( |
+ env, jvalue_callback); |
+} |
+ |
+namespace { |
+ |
+template <typename T> |
+ScopedJavaLocalRef<jobject> ToJavaCallbackTemplate( |
+ JNIEnv* env, |
+ const base::Callback<void(T)>& callback) { |
+ Callback<void(T)>* native_callback = new Callback<void(T)>(callback); |
+ ScopedJavaLocalRef<jobject> jvalue_callback = Java_NativeCallbackInt_create( |
+ env, reinterpret_cast<int>(native_callback)); |
+ |
+ return jvalue_callback; |
+} |
+ |
+} // namespace |
+ |
+ScopedJavaLocalRef<jobject> CallbackJNIBridge::ToJavaCallbackInt( |
+ JNIEnv* env, |
+ const Callback<void(int)>& callback) { |
+ return ToJavaCallbackTemplate(env, callback); |
+} |
+ |
+ScopedJavaLocalRef<jobject> CallbackJNIBridge::ToJavaCallbackLong( |
+ JNIEnv* env, |
+ const Callback<void(long)>& callback) { |
+ return ToJavaCallbackTemplate(env, callback); |
+} |
+ |
+ScopedJavaLocalRef<jobject> CallbackJNIBridge::ToJavaCallbackBool( |
+ JNIEnv* env, |
+ const Callback<void(bool)>& callback) { |
+ return ToJavaCallbackTemplate(env, callback); |
+} |
+ |
+ScopedJavaLocalRef<jobject> CallbackJNIBridge::ToJavaCallbackObj( |
+ JNIEnv* env, |
+ const base::Callback<void(ScopedJavaLocalRef<jobject>)>& callback) { |
+ Callback<void(ScopedJavaLocalRef<jobject>)>* native_callback = |
+ new Callback<void(ScopedJavaLocalRef<jobject>)>(callback); |
+ ScopedJavaLocalRef<jobject> jvalue_callback = |
+ Java_NativeCallback_create( |
+ env, reinterpret_cast<int>(native_callback)); |
+ |
+ return jvalue_callback; |
+} |
+ |
+// static methods ------------------------------------------------------------- |
+namespace { |
+ |
+template <typename T> |
+void DestroyTemplate(JNIEnv* env, jclass clazz, jint callbackPtr) { |
+ Callback<void(T)>* native_callback = |
+ reinterpret_cast<Callback<void(T)>*>(callbackPtr); |
+ delete native_callback; |
+} |
+ |
+template <typename T, typename JT> |
+static void InvokeTemplate(JNIEnv* env, |
+ jclass clazz, |
+ jint callbackPtr, |
+ JT value) { |
+ Callback<void(T)>* native_callback = |
+ reinterpret_cast<Callback<void(T)>*>(callbackPtr); |
+ native_callback->Run(value); |
+} |
+ |
+} // namespace |
+ |
+static void DestroyInt(JNIEnv* env, jclass clazz, jint callbackPtr) { |
+ DestroyTemplate<int>(env, clazz, callbackPtr); |
+} |
+ |
+static void InvokeInt(JNIEnv* env, jclass clazz, jint callbackPtr, jint value) { |
+ InvokeTemplate<int, jint>(env, clazz, callbackPtr, value); |
+} |
+ |
+static void DestroyLong(JNIEnv* env, jclass clazz, jint callbackPtr) { |
+ DestroyTemplate<long>(env, clazz, callbackPtr); |
+} |
+ |
+static void InvokeLong(JNIEnv* env, |
+ jclass clazz, |
+ jint callbackPtr, |
+ jlong value) { |
+ InvokeTemplate<long, jlong>(env, clazz, callbackPtr, value); |
+} |
+ |
+static void DestroyBoolean(JNIEnv* env, jclass clazz, jint callbackPtr) { |
+ DestroyTemplate<bool>(env, clazz, callbackPtr); |
+} |
+ |
+static void InvokeBoolean(JNIEnv* env, |
+ jclass clazz, |
+ jint callbackPtr, |
+ jboolean value) { |
+ InvokeTemplate<bool, jboolean>(env, clazz, callbackPtr, value); |
+} |
+ |
+static void DestroyObj(JNIEnv* env, jclass clazz, jint callbackPtr) { |
+ DestroyTemplate<ScopedJavaLocalRef<jobject> >(env, clazz, callbackPtr); |
+} |
+ |
+static void InvokeObj(JNIEnv* env, |
+ jclass clazz, |
+ jint callbackPtr, |
+ jobject value) { |
+ ScopedJavaLocalRef<jobject> jvalue(env, value); |
+ InvokeTemplate<ScopedJavaLocalRef<jobject>, |
+ const ScopedJavaLocalRef<jobject>&>(env, |
+ clazz, |
+ callbackPtr, |
+ jvalue); |
+} |
+ |
+bool RegisterCallbackJNIBridge(JNIEnv* env) { |
+ return RegisterNativesImpl(env); |
+} |
+ |
+} // namespace android_webview |