Index: android_webview/java/src/org/chromium/android_webview/CallbackJNIBridge.java |
diff --git a/android_webview/java/src/org/chromium/android_webview/CallbackJNIBridge.java b/android_webview/java/src/org/chromium/android_webview/CallbackJNIBridge.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0b18383a949a65d4d99669d9e4a02079fdb1a72f |
--- /dev/null |
+++ b/android_webview/java/src/org/chromium/android_webview/CallbackJNIBridge.java |
@@ -0,0 +1,298 @@ |
+// Copyright (c) 2012 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. |
+ |
+package org.chromium.android_webview; |
+ |
+import android.util.Log; |
+import android.webkit.ValueCallback; |
+ |
+import org.chromium.base.CalledByNative; |
+import org.chromium.base.CalledByNativeUnchecked; |
+import org.chromium.base.NativeCall; |
+import org.chromium.base.JNINamespace; |
+import org.chromium.content.common.CleanupReference; |
+ |
+import java.util.Set; |
+import java.util.HashSet; |
+ |
+/** |
+ * This class facilitates delegating callback method invocations across the JNI boundary. |
+ * |
+ * The basic motivation for this code is to encapsulate C++ <-> Java callback invocations. There |
+ * are two main use cases described below. The implementation makes two assumptions about the |
+ * callbacks: |
+ * 1) callbacks are "one-shot". Calling a ValueCallback.onReceiveValue or base::Callback.Run |
+ * method more than once on a given instance is not allowed |
+ * 2) Java -> C++ callbacks are created and called on the same thread. |
+ * |
+ * Converting a Java ValueCallback<Integer> to a C++ base::Callback<void(int)>: |
+ * |
+ * Java: |
+ * doSomethingInCpp(ValueCallback<Integer> vc) { |
+ * nativeDoSomethingInCpp(CallbackJNIBridge.wrapCallbackInt(vc)); |
+ * } |
+ * |
+ * private native void nativeDoSomethingInCpp(JavaCallbackInt callback); |
+ * |
+ * C++: |
+ * void object::DoSomethingInCpp(jobject jvalue_callback) { |
+ * base::Callback<void(int)> callback = CallbackJNIBridge::FromJavaCallbackInt(jvalue_callback); |
+ * callback.Run(1); // vc.onReceiveValue(1); gets called Java-side |
+ * } |
+ * |
+ * Converting a Java ValueCallback<T> to a C++ base::Callback<void(T)>: |
+ * |
+ * C++: |
+ * void CustomObject* customObjectConverter(ScopedJavaLocalRef<jobject> jobject); |
+ * |
+ * void object::DoSomethingInCpp(jobject jvalue_callback) { |
+ * base::Callback<void(CustomObject*)> callback = |
+ * CallbackJNIBridge::FromJavaCallback(jvalue_callback, base::Bind(&customObjectConverter); |
+ * callback.Run(1); // vc.onReceiveValue(1); gets called Java-side |
+ * } |
+ * |
+ * Converting a C++ base::Callback<void(int)> to a Java ValueCallback<Integer>: |
+ * |
+ * C++: |
+ * android::ScopedLocalJavaRef<jobject> jcallback = |
+ * JavaIntCallback(cpp_object, &Object::onIntValue); |
+ * Java_className_doSomething(jcallback.obj()); |
+ * |
+ * in Java: |
+ * private void doSomething(ValueCallback<Integer> vc) { |
+ * int value = 3; |
+ * vc.onReceiveValue(value); // calls cpp_object->onIntValue(3); |
+ * } |
+ * |
+ */ |
+@JNINamespace("android_webview") |
+public class CallbackJNIBridge { |
+ private static final String TAG = "CallbackJNIBridge"; |
+ |
+ /** |
+ * Interface used for native -> Java callback dispatching. |
+ */ |
+ public interface JavaCallback { |
+ @CalledByNative("JavaCallback") |
+ void invoke(Object value); |
+ } |
+ |
+ /** |
+ * Convert a ValueCallback to a form that can be easily passed to the native side. |
+ */ |
+ @SuppressWarnings("unchecked") |
mkosiba (inactive)
2013/02/25 23:43:44
I think this guy will definitely stay - ie. I don'
|
+ public static <T> JavaCallback wrapCallback(final ValueCallback<T> vc) { |
+ return new JavaCallback() { |
+ @Override |
+ public void invoke(Object value) { |
+ try { |
+ ((ValueCallback) vc).onReceiveValue(value); |
+ } catch (RuntimeException e) { |
+ Log.e(TAG, "An error occurred while invoking a callback.", e); |
+ throw e; |
+ } |
+ } |
+ }; |
+ } |
+ |
+ public interface JavaCallbackInt { |
+ @CalledByNative("JavaCallbackInt") |
+ void invoke(int value); |
+ } |
+ |
+ public static JavaCallbackInt wrapCallbackInt(final ValueCallback<Integer> vc) { |
mkosiba (inactive)
2013/02/25 23:43:44
It would be useful if the same method call could p
|
+ return new JavaCallbackInt() { |
+ @Override |
+ public void invoke(int value) { |
+ try { |
+ vc.onReceiveValue(value); |
+ } catch (RuntimeException e) { |
+ Log.e(TAG, "An error occurred while invoking a callback.", e); |
+ throw e; |
+ } |
+ } |
+ }; |
+ } |
+ |
+ public interface JavaCallbackLong { |
+ @CalledByNative("JavaCallbackLong") |
+ void invoke(long value); |
+ } |
+ |
+ public static JavaCallbackLong wrapCallbackLong(final ValueCallback<Long> vc) { |
+ return new JavaCallbackLong() { |
+ @Override |
+ public void invoke(long value) { |
+ try { |
+ vc.onReceiveValue(value); |
+ } catch (RuntimeException e) { |
+ Log.e(TAG, "An error occurred while invoking a callback.", e); |
+ throw e; |
+ } |
+ } |
+ }; |
+ } |
+ |
+ public interface JavaCallbackBoolean { |
+ @CalledByNative("JavaCallbackBoolean") |
+ void invoke(boolean value); |
+ } |
+ |
+ public static JavaCallbackBoolean wrapCallbackBoolean(final ValueCallback<Boolean> vc) { |
+ return new JavaCallbackBoolean() { |
+ @Override |
+ public void invoke(boolean value) { |
+ try { |
+ vc.onReceiveValue(value); |
+ } catch (RuntimeException e) { |
+ Log.e(TAG, "An error occurred while invoking a callback.", e); |
+ throw e; |
+ } |
+ } |
+ }; |
+ } |
+ |
+ /** |
+ * Base class for Java -> C++ callbacks. |
+ */ |
+ private abstract static class NativeCallbackBase<T> implements ValueCallback<T> { |
mkosiba (inactive)
2013/02/25 23:43:44
these guys don't seem to have the problem the Java
|
+ private CleanupReference mCleanupReference; |
+ private int mNativeCallback; |
+ |
+ public NativeCallbackBase(int nativeCallback) { |
+ assert nativeCallback != 0; |
+ mNativeCallback = nativeCallback; |
+ mCleanupReference = new CleanupReference(this, new Runnable() { |
+ @Override |
+ public void run() { |
+ if (mNativeCallback != 0) { |
+ clear(mNativeCallback); |
+ mNativeCallback = 0; |
+ } |
+ } |
+ }); |
+ } |
+ |
+ @Override |
+ public void onReceiveValue(T value) { |
+ assert mNativeCallback != 0; |
+ if (mNativeCallback != 0) { |
+ invoke(mNativeCallback, value); |
+ clear(mNativeCallback); |
+ mNativeCallback = 0; |
+ } |
+ } |
+ |
+ abstract protected void clear(int nativeCallback); |
+ abstract protected void invoke(int nativeCallback, T value); |
+ } |
+ |
+ private static class NativeCallback extends NativeCallbackBase { |
+ public NativeCallback(int nativeCallback) { |
+ super(nativeCallback); |
+ } |
+ |
+ @Override |
+ protected void clear(int nativeCallback) { |
+ nativeDestroyObj(nativeCallback); |
+ } |
+ |
+ @Override |
+ protected void invoke(int nativeCallback, Object value) { |
+ nativeInvokeObj(nativeCallback, value); |
+ } |
+ |
+ @CalledByNative("NativeCallback") |
+ public static NativeCallback create(int callbackPtr) { |
+ return new NativeCallback(callbackPtr); |
+ } |
+ |
+ @NativeCall("NativeCallback") |
+ private static native void nativeDestroyObj(int callbackPtr); |
+ |
+ @NativeCall("NativeCallback") |
+ private static native void nativeInvokeObj(int callbackPtr, Object value); |
+ } |
+ |
+ private static class NativeCallbackInt extends NativeCallbackBase<Integer> { |
+ public NativeCallbackInt(int nativeCallback) { |
+ super(nativeCallback); |
+ } |
+ |
+ @Override |
+ protected void clear(int nativeCallback) { |
+ nativeDestroyInt(nativeCallback); |
+ } |
+ |
+ @Override |
+ protected void invoke(int nativeCallback, Integer value) { |
+ nativeInvokeInt(nativeCallback, value); |
+ } |
+ |
+ @CalledByNative("NativeCallbackInt") |
+ public static NativeCallbackInt create(int callbackPtr) { |
+ return new NativeCallbackInt(callbackPtr); |
+ } |
+ |
+ @NativeCall("NativeCallbackInt") |
+ private static native void nativeDestroyInt(int callbackPtr); |
+ |
+ @NativeCall("NativeCallbackInt") |
+ private static native void nativeInvokeInt(int callbackPtr, int value); |
+ } |
+ |
+ private static class NativeCallbackLong extends NativeCallbackBase<Long> { |
+ public NativeCallbackLong(int nativeCallback) { |
+ super(nativeCallback); |
+ } |
+ |
+ @Override |
+ protected void clear(int nativeCallback) { |
+ nativeDestroyLong(nativeCallback); |
+ } |
+ |
+ @Override |
+ protected void invoke(int nativeCallback, Long value) { |
+ nativeInvokeLong(nativeCallback, value); |
+ } |
+ |
+ @CalledByNative("NativeCallbackLong") |
+ public static NativeCallbackLong create(int callbackPtr) { |
+ return new NativeCallbackLong(callbackPtr); |
+ } |
+ |
+ @NativeCall("NativeCallbackLong") |
+ private static native void nativeDestroyLong(int callbackPtr); |
+ |
+ @NativeCall("NativeCallbackLong") |
+ private static native void nativeInvokeLong(int callbackPtr, long value); |
+ } |
+ |
+ private static class NativeCallbackBoolean extends NativeCallbackBase<Boolean> { |
+ public NativeCallbackBoolean(int nativeCallback) { |
+ super(nativeCallback); |
+ } |
+ |
+ @Override |
+ protected void clear(int nativeCallback) { |
+ nativeDestroyBoolean(nativeCallback); |
+ } |
+ |
+ @Override |
+ protected void invoke(int nativeCallback, Boolean value) { |
+ nativeInvokeBoolean(nativeCallback, value); |
+ } |
+ |
+ @CalledByNative("NativeCallbackBoolean") |
+ public static NativeCallbackBoolean create(int callbackPtr) { |
+ return new NativeCallbackBoolean(callbackPtr); |
+ } |
+ |
+ @NativeCall("NativeCallbackBoolean") |
+ private static native void nativeDestroyBoolean(int callbackPtr); |
+ |
+ @NativeCall("NativeCallbackBoolean") |
+ private static native void nativeInvokeBoolean(int callbackPtr, boolean value); |
+ } |
+} |