You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2015/02/06 20:06:23 UTC
[3/3] android commit: Separate the registering of BridgeModes from
NativeToJsMessageQueue
Separate the registering of BridgeModes from NativeToJsMessageQueue
This makes the class usable no matter how a webview's bridge is
implemented under-the-hood.
This also deletes the PrivateApi bridge mode, which has never been a
good idea to use, and which we should replace with a Lollipop
"evaluateJavascript"-based bridge.
Project: http://git-wip-us.apache.org/repos/asf/cordova-android/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-android/commit/4cb64580
Tree: http://git-wip-us.apache.org/repos/asf/cordova-android/tree/4cb64580
Diff: http://git-wip-us.apache.org/repos/asf/cordova-android/diff/4cb64580
Branch: refs/heads/master
Commit: 4cb64580fd5d3e3c885847ef8d266aa9eaf87179
Parents: 5b2fa12
Author: Andrew Grieve <ag...@chromium.org>
Authored: Fri Feb 6 14:03:10 2015 -0500
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Fri Feb 6 14:03:10 2015 -0500
----------------------------------------------------------------------
.../src/org/apache/cordova/AndroidWebView.java | 20 +-
.../apache/cordova/NativeToJsMessageQueue.java | 197 +++++++------------
2 files changed, 90 insertions(+), 127 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4cb64580/framework/src/org/apache/cordova/AndroidWebView.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/AndroidWebView.java b/framework/src/org/apache/cordova/AndroidWebView.java
index d0b6d05..6ad1af6 100755
--- a/framework/src/org/apache/cordova/AndroidWebView.java
+++ b/framework/src/org/apache/cordova/AndroidWebView.java
@@ -113,7 +113,7 @@ public class AndroidWebView extends WebView implements CordovaWebView {
// Use two-phase init so that the control will work with XML layouts.
@Override
- public void init(CordovaInterface cordova, List<PluginEntry> pluginEntries,
+ public void init(final CordovaInterface cordova, List<PluginEntry> pluginEntries,
Whitelist internalWhitelist, Whitelist externalWhitelist,
CordovaPreferences preferences) {
if (this.cordova != null) {
@@ -127,9 +127,23 @@ public class AndroidWebView extends WebView implements CordovaWebView {
pluginManager = new PluginManager(this, this.cordova, pluginEntries);
cookieManager = new AndroidCookieManager(this);
resourceApi = new CordovaResourceApi(this.getContext(), pluginManager);
- bridge = new CordovaBridge(pluginManager, new NativeToJsMessageQueue(this, cordova), this.cordova.getActivity().getPackageName());
+ NativeToJsMessageQueue nativeToJsMessageQueue = new NativeToJsMessageQueue();
+ nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.NoOpBridgeMode());
+ nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.LoadUrlBridgeMode(this, cordova));
+ nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.OnlineEventsBridgeMode(new NativeToJsMessageQueue.OnlineEventsBridgeMode.OnlineEventsBridgeModeDelegate() {
+ @Override
+ public void setNetworkAvailable(boolean value) {
+ AndroidWebView.this.setNetworkAvailable(value);
+ }
+
+ @Override
+ public void runOnUiThread(Runnable r) {
+ cordova.getActivity().runOnUiThread(r);
+ }
+ }));
+ bridge = new CordovaBridge(pluginManager, nativeToJsMessageQueue, this.cordova.getActivity().getPackageName());
initWebViewSettings();
- pluginManager.addService(CoreAndroid.PLUGIN_NAME, "org.apache.cordova.CoreAndroid");
+ pluginManager.addService(CoreAndroid.PLUGIN_NAME, CoreAndroid.class.getCanonicalName());
pluginManager.init();
if (this.viewClient == null) {
http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4cb64580/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/NativeToJsMessageQueue.java b/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
index a697060..6f9db66 100755
--- a/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
+++ b/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
@@ -18,16 +18,10 @@
*/
package org.apache.cordova;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
+import java.util.ArrayList;
import java.util.LinkedList;
-import org.apache.cordova.CordovaInterface;
-import org.apache.cordova.PluginResult;
-
-import android.os.Message;
import android.util.Log;
-import android.webkit.WebView;
/**
* Holds the list of messages to be sent to the WebView.
@@ -63,7 +57,7 @@ public class NativeToJsMessageQueue {
/**
* The array of listeners that can be used to send messages to JS.
*/
- private final BridgeMode[] registeredListeners;
+ private ArrayList<BridgeMode> bridgeModes = new ArrayList<BridgeMode>();
/**
* When null, the bridge is disabled. This occurs during page transitions.
@@ -72,32 +66,26 @@ public class NativeToJsMessageQueue {
*/
private BridgeMode activeBridgeMode;
- private final CordovaInterface cordova;
- private final CordovaWebView webView;
-
- public NativeToJsMessageQueue(CordovaWebView webView, CordovaInterface cordova) {
- this.cordova = cordova;
- this.webView = webView;
- registeredListeners = new BridgeMode[4];
- registeredListeners[0] = new PollingBridgeMode();
- registeredListeners[1] = new LoadUrlBridgeMode();
- registeredListeners[2] = new OnlineEventsBridgeMode();
- registeredListeners[3] = new PrivateApiBridgeMode();
- reset();
+ public void addBridgeMode(BridgeMode bridgeMode) {
+ bridgeModes.add(bridgeMode);
}
-
+
public boolean isBridgeEnabled() {
return activeBridgeMode != null;
}
+ public boolean isEmpty() {
+ return queue.isEmpty();
+ }
+
/**
* Changes the bridge mode.
*/
public void setBridgeMode(int value) {
- if (value < -1 || value >= registeredListeners.length) {
+ if (value < -1 || value >= bridgeModes.size()) {
Log.d(LOG_TAG, "Invalid NativeToJsBridgeMode: " + value);
} else {
- BridgeMode newMode = value < 0 ? null : registeredListeners[value];
+ BridgeMode newMode = value < 0 ? null : bridgeModes.get(value);
if (newMode != activeBridgeMode) {
Log.d(LOG_TAG, "Set native->JS mode to " + (newMode == null ? "null" : newMode.getClass().getSimpleName()));
synchronized (this) {
@@ -105,7 +93,7 @@ public class NativeToJsMessageQueue {
if (newMode != null) {
newMode.reset();
if (!paused && !queue.isEmpty()) {
- newMode.onNativeToJsMessageAvailable();
+ newMode.onNativeToJsMessageAvailable(this);
}
}
}
@@ -146,7 +134,7 @@ public class NativeToJsMessageQueue {
if (activeBridgeMode == null) {
return null;
}
- activeBridgeMode.notifyOfFlush(fromOnlineEvent);
+ activeBridgeMode.notifyOfFlush(this, fromOnlineEvent);
if (queue.isEmpty()) {
return null;
}
@@ -179,7 +167,7 @@ public class NativeToJsMessageQueue {
/**
* Same as popAndEncode(), except encodes in a form that can be executed as JS.
*/
- private String popAndEncodeAsJs() {
+ public String popAndEncodeAsJs() {
synchronized (this) {
int length = queue.size();
if (length == 0) {
@@ -260,7 +248,7 @@ public class NativeToJsMessageQueue {
}
queue.add(message);
if (!paused) {
- activeBridgeMode.onNativeToJsMessageAvailable();
+ activeBridgeMode.onNativeToJsMessageAvailable(this);
}
}
}
@@ -275,133 +263,94 @@ public class NativeToJsMessageQueue {
if (!value) {
synchronized (this) {
if (!queue.isEmpty() && activeBridgeMode != null) {
- activeBridgeMode.onNativeToJsMessageAvailable();
+ activeBridgeMode.onNativeToJsMessageAvailable(this);
}
}
}
}
- private abstract class BridgeMode {
- abstract void onNativeToJsMessageAvailable();
- void notifyOfFlush(boolean fromOnlineEvent) {}
+ public static abstract class BridgeMode {
+ abstract void onNativeToJsMessageAvailable(NativeToJsMessageQueue queue);
+ void notifyOfFlush(NativeToJsMessageQueue queue, boolean fromOnlineEvent) {}
void reset() {}
}
/** Uses JS polls for messages on a timer.. */
- private class PollingBridgeMode extends BridgeMode {
- @Override void onNativeToJsMessageAvailable() {
+ public static class NoOpBridgeMode extends BridgeMode {
+ @Override public void onNativeToJsMessageAvailable(NativeToJsMessageQueue queue) {
}
}
/** Uses webView.loadUrl("javascript:") to execute messages. */
- private class LoadUrlBridgeMode extends BridgeMode {
- final Runnable runnable = new Runnable() {
- public void run() {
- String js = popAndEncodeAsJs();
- if (js != null) {
- webView.loadUrlIntoView("javascript:" + js, false);
+ public static class LoadUrlBridgeMode extends BridgeMode {
+ private final CordovaWebView webView;
+ private final CordovaInterface cordova;
+
+ public LoadUrlBridgeMode(CordovaWebView webView, CordovaInterface cordova) {
+ this.webView = webView;
+ this.cordova = cordova;
+ }
+
+ @Override
+ public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) {
+ cordova.getActivity().runOnUiThread(new Runnable() {
+ public void run() {
+ String js = queue.popAndEncodeAsJs();
+ if (js != null) {
+ webView.loadUrl("javascript:" + js);
+ }
}
- }
- };
-
- @Override void onNativeToJsMessageAvailable() {
- cordova.getActivity().runOnUiThread(runnable);
+ });
}
}
/** Uses online/offline events to tell the JS when to poll for messages. */
- private class OnlineEventsBridgeMode extends BridgeMode {
+ public static class OnlineEventsBridgeMode extends BridgeMode {
+ private final OnlineEventsBridgeModeDelegate delegate;
private boolean online;
private boolean ignoreNextFlush;
- final Runnable toggleNetworkRunnable = new Runnable() {
- public void run() {
- if (!queue.isEmpty()) {
- ignoreNextFlush = false;
- webView.setNetworkAvailable(online);
+ public interface OnlineEventsBridgeModeDelegate {
+ void setNetworkAvailable(boolean value);
+ void runOnUiThread(Runnable r);
+ }
+
+ public OnlineEventsBridgeMode(OnlineEventsBridgeModeDelegate delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void reset() {
+ delegate.runOnUiThread(new Runnable() {
+ public void run() {
+ online = false;
+ // If the following call triggers a notifyOfFlush, then ignore it.
+ ignoreNextFlush = true;
+ delegate.setNetworkAvailable(true);
}
- }
- };
- final Runnable resetNetworkRunnable = new Runnable() {
- public void run() {
- online = false;
- // If the following call triggers a notifyOfFlush, then ignore it.
- ignoreNextFlush = true;
- webView.setNetworkAvailable(true);
- }
- };
- @Override void reset() {
- cordova.getActivity().runOnUiThread(resetNetworkRunnable);
+ });
}
- @Override void onNativeToJsMessageAvailable() {
- cordova.getActivity().runOnUiThread(toggleNetworkRunnable);
+
+ @Override
+ public void onNativeToJsMessageAvailable(final NativeToJsMessageQueue queue) {
+ delegate.runOnUiThread(new Runnable() {
+ public void run() {
+ if (!queue.isEmpty()) {
+ ignoreNextFlush = false;
+ delegate.setNetworkAvailable(online);
+ }
+ }
+ });
}
// Track when online/offline events are fired so that we don't fire excess events.
- @Override void notifyOfFlush(boolean fromOnlineEvent) {
+ @Override
+ public void notifyOfFlush(final NativeToJsMessageQueue queue, boolean fromOnlineEvent) {
if (fromOnlineEvent && !ignoreNextFlush) {
online = !online;
}
}
}
-
- /**
- * Uses Java reflection to access an API that lets us eval JS.
- * Requires Android 3.2.4 or above.
- */
- private class PrivateApiBridgeMode extends BridgeMode {
- // Message added in commit:
- // http://omapzoom.org/?p=platform/frameworks/base.git;a=commitdiff;h=9497c5f8c4bc7c47789e5ccde01179abc31ffeb2
- // Which first appeared in 3.2.4ish.
- private static final int EXECUTE_JS = 194;
-
- Method sendMessageMethod;
- Object webViewCore;
- boolean initFailed;
-
- @SuppressWarnings("rawtypes")
- private void initReflection() {
- Object webViewObject = webView;
- Class webViewClass = WebView.class;
- try {
- Field f = webViewClass.getDeclaredField("mProvider");
- f.setAccessible(true);
- webViewObject = f.get(webView);
- webViewClass = webViewObject.getClass();
- } catch (Throwable e) {
- // mProvider is only required on newer Android releases.
- }
-
- try {
- Field f = webViewClass.getDeclaredField("mWebViewCore");
- f.setAccessible(true);
- webViewCore = f.get(webViewObject);
-
- if (webViewCore != null) {
- sendMessageMethod = webViewCore.getClass().getDeclaredMethod("sendMessage", Message.class);
- sendMessageMethod.setAccessible(true);
- }
- } catch (Throwable e) {
- initFailed = true;
- Log.e(LOG_TAG, "PrivateApiBridgeMode failed to find the expected APIs.", e);
- }
- }
-
- @Override void onNativeToJsMessageAvailable() {
- if (sendMessageMethod == null && !initFailed) {
- initReflection();
- }
- // webViewCore is lazily initialized, and so may not be available right away.
- if (sendMessageMethod != null) {
- String js = popAndEncodeAsJs();
- Message execJsMessage = Message.obtain(null, EXECUTE_JS, js);
- try {
- sendMessageMethod.invoke(webViewCore, execJsMessage);
- } catch (Throwable e) {
- Log.e(LOG_TAG, "Reflection message bridge failed.", e);
- }
- }
- }
- }
+
private static class JsMessage {
final String jsPayloadOrCallbackId;
final PluginResult pluginResult;
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org