Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4947)

Unified Diff: android_webview/java/src/org/chromium/android_webview/CallbackJNIBridge.java

Issue 12313042: [android_webview] Add a generic callback JNI bridge. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698