Delete Cordova*Client classes, Create CordovaBridge, Delete more CordovaWebView symbols

Changes made in order to get xwalk working again
This commit is contained in:
Andrew Grieve 2014-07-09 09:29:33 -04:00
parent 25a7b66296
commit efcedabee0
14 changed files with 302 additions and 575 deletions

View File

@ -20,8 +20,6 @@ package org.apache.cordova;
import org.apache.cordova.CordovaInterface; import org.apache.cordova.CordovaInterface;
import org.apache.cordova.LOG; import org.apache.cordova.LOG;
import org.json.JSONArray;
import org.json.JSONException;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.app.AlertDialog; import android.app.AlertDialog;
@ -44,7 +42,6 @@ import android.widget.EditText;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.util.Log;
/** /**
* This class is the WebChromeClient that implements callbacks for our web view. * This class is the WebChromeClient that implements callbacks for our web view.
@ -57,7 +54,7 @@ import android.util.Log;
* @see CordovaWebViewClient * @see CordovaWebViewClient
* @see CordovaWebView * @see CordovaWebView
*/ */
public class AndroidChromeClient extends WebChromeClient implements CordovaChromeClient { public class AndroidChromeClient extends WebChromeClient {
public static final int FILECHOOSER_RESULTCODE = 5173; public static final int FILECHOOSER_RESULTCODE = 5173;
private static final String LOG_TAG = "AndroidChromeClient"; private static final String LOG_TAG = "AndroidChromeClient";
@ -69,7 +66,7 @@ public class AndroidChromeClient extends WebChromeClient implements CordovaChrom
private View mVideoProgressView; private View mVideoProgressView;
// File Chooser // File Chooser
public ValueCallback<Uri> mUploadMessage; protected ValueCallback<Uri> mUploadMessage;
public AndroidChromeClient(CordovaInterface ctx, AndroidWebView app) { public AndroidChromeClient(CordovaInterface ctx, AndroidWebView app) {
this.cordova = ctx; this.cordova = ctx;
@ -182,67 +179,9 @@ public class AndroidChromeClient extends WebChromeClient implements CordovaChrom
@Override @Override
public boolean onJsPrompt(WebView view, String origin, String message, String defaultValue, JsPromptResult result) { public boolean onJsPrompt(WebView view, String origin, String message, String defaultValue, JsPromptResult result) {
// Unlike the @JavascriptInterface bridge, this method is always called on the UI thread. // Unlike the @JavascriptInterface bridge, this method is always called on the UI thread.
if (defaultValue != null && defaultValue.length() > 3 && defaultValue.startsWith("gap:")) { String handledRet = appView.bridge.promptOnJsPrompt(origin, message, defaultValue);
JSONArray array; if (handledRet != null) {
try { result.confirm(handledRet);
array = new JSONArray(defaultValue.substring(4));
int bridgeSecret = array.getInt(0);
String service = array.getString(1);
String action = array.getString(2);
String callbackId = array.getString(3);
String r = appView.exposedJsApi.exec(bridgeSecret, service, action, callbackId, message);
result.confirm(r == null ? "" : r);
} catch (JSONException e) {
e.printStackTrace();
result.cancel();
} catch (IllegalAccessException e) {
e.printStackTrace();
result.cancel();
}
}
// Sets the native->JS bridge mode.
else if (defaultValue != null && defaultValue.startsWith("gap_bridge_mode:")) {
try {
int bridgeSecret = Integer.parseInt(defaultValue.substring(16));
appView.exposedJsApi.setNativeToJsBridgeMode(bridgeSecret, Integer.parseInt(message));
result.cancel();
} catch (NumberFormatException e){
e.printStackTrace();
result.cancel();
} catch (IllegalAccessException e) {
e.printStackTrace();
result.cancel();
}
}
// Polling for JavaScript messages
else if (defaultValue != null && defaultValue.startsWith("gap_poll:")) {
int bridgeSecret = Integer.parseInt(defaultValue.substring(9));
try {
String r = appView.exposedJsApi.retrieveJsMessages(bridgeSecret, "1".equals(message));
result.confirm(r == null ? "" : r);
} catch (IllegalAccessException e) {
e.printStackTrace();
result.cancel();
}
}
else if (defaultValue != null && defaultValue.startsWith("gap_init:")) {
// Protect against random iframes being able to talk through the bridge.
// Trust only file URLs and the start URL's domain.
// The extra origin.startsWith("http") is to protect against iframes with data: having "" as origin.
if (origin.startsWith("file:") || (origin.startsWith("http") && appView.loadedUrl.startsWith(origin))) {
// Enable the bridge
int bridgeMode = Integer.parseInt(defaultValue.substring(9));
appView.jsMessageQueue.setBridgeMode(bridgeMode);
// Tell JS the bridge secret.
int secret = appView.exposedJsApi.generateBridgeSecret();
result.confirm(""+secret);
} else {
Log.e(LOG_TAG, "gap_init called from restricted origin: " + origin);
result.cancel();
}
} else { } else {
// Returning false would also show a dialog, but the default one shows the origin (ugly). // Returning false would also show a dialog, but the default one shows the origin (ugly).
final JsPromptResult res = result; final JsPromptResult res = result;
@ -375,8 +314,4 @@ public class AndroidChromeClient extends WebChromeClient implements CordovaChrom
this.cordova.getActivity().startActivityForResult(Intent.createChooser(i, "File Browser"), this.cordova.getActivity().startActivityForResult(Intent.createChooser(i, "File Browser"),
FILECHOOSER_RESULTCODE); FILECHOOSER_RESULTCODE);
} }
public ValueCallback<Uri> getValueCallback() {
return this.mUploadMessage;
}
} }

View File

@ -19,7 +19,6 @@
package org.apache.cordova; package org.apache.cordova;
import android.webkit.JavascriptInterface; import android.webkit.JavascriptInterface;
import org.apache.cordova.PluginManager;
import org.json.JSONException; import org.json.JSONException;
/** /**
@ -28,70 +27,24 @@ import org.json.JSONException;
* cordova-js/lib/android/plugin/android/promptbasednativeapi.js * cordova-js/lib/android/plugin/android/promptbasednativeapi.js
*/ */
class AndroidExposedJsApi implements ExposedJsApi { class AndroidExposedJsApi implements ExposedJsApi {
private final CordovaBridge bridge;
private PluginManager pluginManager; AndroidExposedJsApi(CordovaBridge bridge) {
private NativeToJsMessageQueue jsMessageQueue; this.bridge = bridge;
private volatile int bridgeSecret = -1; // written by UI thread, read by JS thread.
public AndroidExposedJsApi(PluginManager pluginManager, NativeToJsMessageQueue jsMessageQueue) {
this.pluginManager = pluginManager;
this.jsMessageQueue = jsMessageQueue;
} }
@JavascriptInterface @JavascriptInterface
public String exec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException { public String exec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException {
verifySecret(bridgeSecret); return bridge.jsExec(bridgeSecret, service, action, callbackId, arguments);
// If the arguments weren't received, send a message back to JS. It will switch bridge modes and try again. See CB-2666.
// We send a message meant specifically for this case. It starts with "@" so no other message can be encoded into the same string.
if (arguments == null) {
return "@Null arguments.";
}
jsMessageQueue.setPaused(true);
try {
// Tell the resourceApi what thread the JS is running on.
CordovaResourceApi.jsThread = Thread.currentThread();
pluginManager.exec(service, action, callbackId, arguments);
String ret = "";
if (!NativeToJsMessageQueue.DISABLE_EXEC_CHAINING) {
ret = jsMessageQueue.popAndEncode(false);
}
return ret;
} catch (Throwable e) {
e.printStackTrace();
return "";
} finally {
jsMessageQueue.setPaused(false);
}
} }
@JavascriptInterface @JavascriptInterface
public void setNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException { public void setNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException {
verifySecret(bridgeSecret); bridge.jsSetNativeToJsBridgeMode(bridgeSecret, value);
jsMessageQueue.setBridgeMode(value);
} }
@JavascriptInterface @JavascriptInterface
public String retrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException { public String retrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException {
verifySecret(bridgeSecret); return bridge.jsRetrieveJsMessages(bridgeSecret, fromOnlineEvent);
return jsMessageQueue.popAndEncode(fromOnlineEvent);
}
private void verifySecret(int value) throws IllegalAccessException {
if (bridgeSecret < 0 || value != bridgeSecret) {
throw new IllegalAccessException();
}
}
/** Called on page transitions */
void clearBridgeSecret() {
bridgeSecret = -1;
}
/** Called by cordova.js to initialize the bridge. */
int generateBridgeSecret() {
bridgeSecret = (int)(Math.random() * Integer.MAX_VALUE);
return bridgeSecret;
} }
} }

View File

@ -24,7 +24,6 @@ import java.lang.reflect.Method;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
@ -66,23 +65,21 @@ public class AndroidWebView extends WebView implements CordovaWebView {
private HashSet<Integer> boundKeyCodes = new HashSet<Integer>(); private HashSet<Integer> boundKeyCodes = new HashSet<Integer>();
PluginManager pluginManager; PluginManager pluginManager;
private boolean paused;
private BroadcastReceiver receiver; private BroadcastReceiver receiver;
/** Activities and other important classes **/ /** Activities and other important classes **/
private CordovaInterface cordova; private CordovaInterface cordova;
CordovaWebViewClient viewClient; AndroidWebViewClient viewClient;
private CordovaChromeClient chromeClient; private AndroidChromeClient chromeClient;
// Flag to track that a loadUrl timeout occurred // Flag to track that a loadUrl timeout occurred
int loadUrlTimeout = 0; int loadUrlTimeout = 0;
private long lastMenuEventTime = 0; private long lastMenuEventTime = 0;
NativeToJsMessageQueue jsMessageQueue; CordovaBridge bridge;
AndroidExposedJsApi exposedJsApi;
/** custom view created by the browser (a video player for example) */ /** custom view created by the browser (a video player for example) */
private View mCustomView; private View mCustomView;
@ -94,21 +91,6 @@ public class AndroidWebView extends WebView implements CordovaWebView {
// The URL passed to loadUrl(), not necessarily the URL of the current page. // The URL passed to loadUrl(), not necessarily the URL of the current page.
String loadedUrl; String loadedUrl;
class ActivityResult {
int request;
int result;
Intent incoming;
public ActivityResult(int req, int res, Intent intent) {
request = req;
result = res;
incoming = intent;
}
}
static final FrameLayout.LayoutParams COVER_SCREEN_GRAVITY_CENTER = static final FrameLayout.LayoutParams COVER_SCREEN_GRAVITY_CENTER =
new FrameLayout.LayoutParams( new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
@ -127,24 +109,30 @@ public class AndroidWebView extends WebView implements CordovaWebView {
// Use two-phase init so that the control will work with XML layouts. // Use two-phase init so that the control will work with XML layouts.
@Override @Override
public void init(CordovaInterface cordova, CordovaWebViewClient webViewClient, CordovaChromeClient webChromeClient, public void init(CordovaInterface cordova, List<PluginEntry> pluginEntries,
List<PluginEntry> pluginEntries, Whitelist whitelist, CordovaPreferences preferences) { Whitelist whitelist, CordovaPreferences preferences) {
if (this.cordova != null) { if (this.cordova != null) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
this.cordova = cordova; this.cordova = cordova;
setWebChromeClient(webChromeClient);
setWebViewClient(webViewClient);
this.whitelist = whitelist; this.whitelist = whitelist;
this.preferences = preferences; this.preferences = preferences;
pluginManager = new PluginManager(this, this.cordova, pluginEntries); pluginManager = new PluginManager(this, this.cordova, pluginEntries);
jsMessageQueue = new NativeToJsMessageQueue(this, cordova);
exposedJsApi = new AndroidExposedJsApi(pluginManager, jsMessageQueue);
resourceApi = new CordovaResourceApi(this.getContext(), pluginManager); resourceApi = new CordovaResourceApi(this.getContext(), pluginManager);
bridge = new CordovaBridge(pluginManager, new NativeToJsMessageQueue(this, cordova));
pluginManager.addService("App", "org.apache.cordova.CoreAndroid"); pluginManager.addService("App", "org.apache.cordova.CoreAndroid");
initWebViewSettings(); initWebViewSettings();
if (this.viewClient == null) {
setWebViewClient(Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH ?
new AndroidWebViewClient(cordova, this) :
new IceCreamCordovaWebViewClient(cordova, this));
}
if (this.chromeClient == null) {
setWebChromeClient(new AndroidChromeClient(cordova, this));
}
exposeJsInterface(); exposeJsInterface();
} }
@ -253,19 +241,6 @@ public class AndroidWebView extends WebView implements CordovaWebView {
} }
} }
@Override
public CordovaChromeClient makeWebChromeClient(CordovaInterface cordova) {
return new AndroidChromeClient(cordova, this);
}
@Override
public CordovaWebViewClient makeWebViewClient(CordovaInterface cordova) {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
return new AndroidWebViewClient(cordova, this);
}
return new IceCreamCordovaWebViewClient(cordova, this);
}
/** /**
* Override this method to decide whether or not you need to request the * Override this method to decide whether or not you need to request the
* focus when your application start * focus when your application start
@ -284,80 +259,42 @@ public class AndroidWebView extends WebView implements CordovaWebView {
// use the prompt bridge instead. // use the prompt bridge instead.
return; return;
} }
AndroidExposedJsApi exposedJsApi = new AndroidExposedJsApi(bridge);
this.addJavascriptInterface(exposedJsApi, "_cordovaNative"); this.addJavascriptInterface(exposedJsApi, "_cordovaNative");
} }
@Override @Override
public void setWebViewClient(WebViewClient client) { public void setWebViewClient(WebViewClient client) {
this.viewClient = (CordovaWebViewClient)client; this.viewClient = (AndroidWebViewClient)client;
super.setWebViewClient(client); super.setWebViewClient(client);
} }
@Override @Override
public void setWebChromeClient(WebChromeClient client) { public void setWebChromeClient(WebChromeClient client) {
this.chromeClient = (CordovaChromeClient)client; this.chromeClient = (AndroidChromeClient)client;
super.setWebChromeClient(client); super.setWebChromeClient(client);
} }
@Override
public void setWebViewClient(CordovaWebViewClient client) {
setWebViewClient((WebViewClient) client);
}
@Override
public void setWebChromeClient(CordovaChromeClient client) {
setWebChromeClient((WebChromeClient) client);
}
public CordovaChromeClient getWebChromeClient() {
return this.chromeClient;
}
/** /**
* Load the url into the webview. * Load the url into the webview.
*
* @param url
*/ */
@Override @Override
public void loadUrl(String url) { public void loadUrl(String url) {
if (url.equals("about:blank") || url.startsWith("javascript:")) { this.loadUrlIntoView(url, true);
this.loadUrlNow(url);
}
else {
this.loadUrlIntoView(url);
}
}
/**
* Load the url into the webview after waiting for period of time.
* This is used to display the splashscreen for certain amount of time.
*
* @param url
* @param time The number of ms to wait before loading webview
*/
@Deprecated
public void loadUrl(final String url, int time) {
if(url == null)
{
this.loadUrlIntoView(Config.getStartUrl());
}
else
{
this.loadUrlIntoView(url);
}
}
public void loadUrlIntoView(final String url) {
loadUrlIntoView(url, true);
} }
/** /**
* Load the url into the webview. * Load the url into the webview.
*
* @param url
*/ */
@Override
public void loadUrlIntoView(final String url, boolean recreatePlugins) { public void loadUrlIntoView(final String url, boolean recreatePlugins) {
if (url.equals("about:blank") || url.startsWith("javascript:")) {
this.loadUrlNow(url);
return;
}
LOG.d(TAG, ">>> loadUrl(" + url + ")"); LOG.d(TAG, ">>> loadUrl(" + url + ")");
recreatePlugins = recreatePlugins || (loadedUrl == null);
if (recreatePlugins) { if (recreatePlugins) {
this.loadedUrl = url; this.loadedUrl = url;
@ -367,7 +304,7 @@ public class AndroidWebView extends WebView implements CordovaWebView {
// Create a timeout timer for loadUrl // Create a timeout timer for loadUrl
final AndroidWebView me = this; final AndroidWebView me = this;
final int currentLoadUrlTimeout = me.loadUrlTimeout; final int currentLoadUrlTimeout = me.loadUrlTimeout;
final int loadUrlTimeoutValue = Integer.parseInt(this.getProperty("LoadUrlTimeoutValue", "20000")); final int loadUrlTimeoutValue = preferences.getInteger("LoadUrlTimeoutValue", 20000);
// Timeout error method // Timeout error method
final Runnable loadError = new Runnable() { final Runnable loadError = new Runnable() {
@ -375,7 +312,7 @@ public class AndroidWebView extends WebView implements CordovaWebView {
me.stopLoading(); me.stopLoading();
LOG.e(TAG, "CordovaWebView: TIMEOUT ERROR!"); LOG.e(TAG, "CordovaWebView: TIMEOUT ERROR!");
if (viewClient != null) { if (viewClient != null) {
viewClient.onReceivedError(-6, "The connection to the server was unsuccessful.", url); viewClient.onReceivedError(AndroidWebView.this, -6, "The connection to the server was unsuccessful.", url);
} }
} }
}; };
@ -409,10 +346,8 @@ public class AndroidWebView extends WebView implements CordovaWebView {
/** /**
* Load URL in webview. * Load URL in webview.
*
* @param url
*/ */
public void loadUrlNow(String url) { private void loadUrlNow(String url) {
if (LOG.isLoggable(LOG.DEBUG) && !url.startsWith("javascript:")) { if (LOG.isLoggable(LOG.DEBUG) && !url.startsWith("javascript:")) {
LOG.d(TAG, ">>> loadUrlNow()"); LOG.d(TAG, ">>> loadUrlNow()");
} }
@ -421,33 +356,6 @@ public class AndroidWebView extends WebView implements CordovaWebView {
} }
} }
/**
* Load the url into the webview after waiting for period of time.
* This is used to display the splashscreen for certain amount of time.
*
* @param url
* @param time The number of ms to wait before loading webview
*/
public void loadUrlIntoView(final String url, final int time) {
// If not first page of app, then load immediately
// Add support for browser history if we use it.
if ((url.startsWith("javascript:")) || this.canGoBack()) {
}
// If first page, then show splashscreen
else {
LOG.d(TAG, "loadUrlIntoView(%s, %d)", url, time);
// Send message to show splashscreen now if desired
this.postMessage("splashscreen", "show");
}
// Load url
this.loadUrlIntoView(url);
}
@Override @Override
public void stopLoading() { public void stopLoading() {
//viewClient.isCurrentlyLoading = false; //viewClient.isCurrentlyLoading = false;
@ -459,43 +367,24 @@ public class AndroidWebView extends WebView implements CordovaWebView {
super.onScrollChanged(l, t, oldl, oldt); super.onScrollChanged(l, t, oldl, oldt);
//We should post a message that the scroll changed //We should post a message that the scroll changed
ScrollEvent myEvent = new ScrollEvent(l, t, oldl, oldt, this); ScrollEvent myEvent = new ScrollEvent(l, t, oldl, oldt, this);
this.postMessage("onScrollChanged", myEvent); pluginManager.postMessage("onScrollChanged", myEvent);
} }
/** /**
* Send JavaScript statement back to JavaScript. * Send JavaScript statement back to JavaScript.
* (This is a convenience method) * (This is a convenience method)
*
* @param statement
*/ */
public void sendJavascript(String statement) { public void sendJavascript(String statement) {
this.jsMessageQueue.addJavaScript(statement); bridge.getMessageQueue().addJavaScript(statement);
} }
/** /**
* Send a plugin result back to JavaScript. * Send a plugin result back to JavaScript.
* (This is a convenience method)
*
* @param result
* @param callbackId
*/ */
public void sendPluginResult(PluginResult result, String callbackId) { public void sendPluginResult(PluginResult result, String callbackId) {
this.jsMessageQueue.addPluginResult(result, callbackId); bridge.getMessageQueue().addPluginResult(result, callbackId);
} }
/**
* Send a message to all plugins.
*
* @param id The message id
* @param data The message data
*/
public void postMessage(String id, Object data) {
if (this.pluginManager != null) {
this.pluginManager.postMessage(id, data);
}
}
/** /**
* Go to previous page in history. (We manage our own history) * Go to previous page in history. (We manage our own history)
* *
@ -540,7 +429,7 @@ public class AndroidWebView extends WebView implements CordovaWebView {
if (url.startsWith("file://") || whitelist.isUrlWhiteListed(url)) { if (url.startsWith("file://") || whitelist.isUrlWhiteListed(url)) {
// TODO: What about params? // TODO: What about params?
// Load new URL // Load new URL
this.loadUrl(url); loadUrlIntoView(url, true);
return; return;
} }
// Load in default viewer if not // Load in default viewer if not
@ -562,26 +451,6 @@ public class AndroidWebView extends WebView implements CordovaWebView {
} }
} }
/**
* Get string property for activity.
*
* @param name
* @param defaultValue
* @return the String value for the named property
*/
public String getProperty(String name, String defaultValue) {
Bundle bundle = this.cordova.getActivity().getIntent().getExtras();
if (bundle == null) {
return defaultValue;
}
name = name.toLowerCase(Locale.getDefault());
Object p = bundle.get(name);
if (p == null) {
return defaultValue;
}
return p.toString();
}
/* /*
* onKeyDown * onKeyDown
*/ */
@ -705,13 +574,10 @@ public class AndroidWebView extends WebView implements CordovaWebView {
// Pause JavaScript timers (including setInterval) // Pause JavaScript timers (including setInterval)
this.pauseTimers(); this.pauseTimers();
} }
paused = true;
} }
public void handleResume(boolean keepRunning, boolean activityResultKeepRunning) public void handleResume(boolean keepRunning, boolean activityResultKeepRunning)
{ {
this.loadUrl("javascript:try{cordova.fireDocumentEvent('resume');}catch(e){console.log('exception firing resume event from native');};"); this.loadUrl("javascript:try{cordova.fireDocumentEvent('resume');}catch(e){console.log('exception firing resume event from native');};");
// Forward to plugins // Forward to plugins
@ -721,7 +587,6 @@ public class AndroidWebView extends WebView implements CordovaWebView {
// Resume JavaScript timers (including setInterval) // Resume JavaScript timers (including setInterval)
this.resumeTimers(); this.resumeTimers();
paused = false;
} }
public void handleDestroy() public void handleDestroy()
@ -755,11 +620,6 @@ public class AndroidWebView extends WebView implements CordovaWebView {
} }
} }
public boolean isPaused()
{
return paused;
}
// Wrapping these functions in their own class prevents warnings in adb like: // Wrapping these functions in their own class prevents warnings in adb like:
// VFY: unable to resolve virtual method 285: Landroid/webkit/WebSettings;.setAllowUniversalAccessFromFileURLs // VFY: unable to resolve virtual method 285: Landroid/webkit/WebSettings;.setAllowUniversalAccessFromFileURLs
@TargetApi(16) @TargetApi(16)
@ -862,57 +722,17 @@ public class AndroidWebView extends WebView implements CordovaWebView {
return resourceApi; return resourceApi;
} }
@Override
public void setLayoutParams(
android.widget.LinearLayout.LayoutParams layoutParams) {
super.setLayoutParams(layoutParams);
}
@Override
public void setOverScrollMode(int mode) {
super.setOverScrollMode(mode);
}
@Override
public void addJavascript(String statement) {
this.jsMessageQueue.addJavaScript(statement);
}
@Override
public CordovaPlugin getPlugin(String initCallbackClass) {
// TODO Auto-generated method stub
return this.pluginManager.getPlugin(initCallbackClass);
}
@Override
public boolean onOverrideUrlLoading(String url) {
return this.pluginManager.onOverrideUrlLoading(url);
}
void onPageReset() { void onPageReset() {
boundKeyCodes.clear(); boundKeyCodes.clear();
pluginManager.onReset(); pluginManager.onReset();
jsMessageQueue.reset(); bridge.reset(loadedUrl);
exposedJsApi.clearBridgeSecret();
}
@Override
public void incUrlTimeout() {
this.loadUrlTimeout++;
} }
@Override @Override
public PluginManager getPluginManager() { public PluginManager getPluginManager() {
// TODO Auto-generated method stub
return this.pluginManager; return this.pluginManager;
} }
@Override
public void setLayoutParams(
android.widget.FrameLayout.LayoutParams layoutParams) {
super.setLayoutParams(layoutParams);
}
@Override @Override
public View getView() { public View getView() {
return this; return this;
@ -927,4 +747,17 @@ public class AndroidWebView extends WebView implements CordovaWebView {
public CordovaPreferences getPreferences() { public CordovaPreferences getPreferences() {
return preferences; return preferences;
} }
@Override
public void onFilePickerResult(Uri uri) {
if (null == chromeClient.mUploadMessage)
return;
chromeClient.mUploadMessage.onReceiveValue(uri);
chromeClient.mUploadMessage = null;
}
@Override
public Object postMessage(String id, Object data) {
return pluginManager.postMessage(id, data);
}
} }

View File

@ -48,7 +48,7 @@ import android.webkit.WebViewClient;
* @see CordovaChromeClient * @see CordovaChromeClient
* @see CordovaWebView * @see CordovaWebView
*/ */
public class AndroidWebViewClient extends WebViewClient implements CordovaWebViewClient{ public class AndroidWebViewClient extends WebViewClient {
private static final String TAG = "AndroidWebViewClient"; private static final String TAG = "AndroidWebViewClient";
protected final CordovaInterface cordova; protected final CordovaInterface cordova;
@ -60,12 +60,6 @@ public class AndroidWebViewClient extends WebViewClient implements CordovaWebVie
/** The authorization tokens. */ /** The authorization tokens. */
private Hashtable<String, AuthenticationToken> authenticationTokens = new Hashtable<String, AuthenticationToken>(); private Hashtable<String, AuthenticationToken> authenticationTokens = new Hashtable<String, AuthenticationToken>();
/**
* Constructor.
*
* @param cordova
* @param view
*/
public AndroidWebViewClient(CordovaInterface cordova, AndroidWebView view) { public AndroidWebViewClient(CordovaInterface cordova, AndroidWebView view) {
this.cordova = cordova; this.cordova = cordova;
this.appView = view; this.appView = view;
@ -82,17 +76,12 @@ public class AndroidWebViewClient extends WebViewClient implements CordovaWebVie
*/ */
@Override @Override
public boolean shouldOverrideUrlLoading(WebView view, String url) { public boolean shouldOverrideUrlLoading(WebView view, String url) {
return helper.shouldOverrideUrlLoading(view, url); return helper.shouldOverrideUrlLoading(url);
} }
/** /**
* On received http auth request. * On received http auth request.
* The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination * The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination
*
* @param view
* @param handler
* @param host
* @param realm
*/ */
@Override @Override
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) { public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
@ -126,7 +115,7 @@ public class AndroidWebViewClient extends WebViewClient implements CordovaWebVie
this.appView.onPageReset(); this.appView.onPageReset();
// Broadcast message that page has loaded // Broadcast message that page has loaded
this.appView.postMessage("onPageStarted", url); this.appView.getPluginManager().postMessage("onPageStarted", url);
} }
/** /**
@ -159,10 +148,10 @@ public class AndroidWebViewClient extends WebViewClient implements CordovaWebVie
} }
// Clear timeout flag // Clear timeout flag
this.appView.incUrlTimeout(); appView.loadUrlTimeout++;
// Broadcast message that page has loaded // Broadcast message that page has loaded
this.appView.postMessage("onPageFinished", url); this.appView.getPluginManager().postMessage("onPageFinished", url);
// Make app visible after 2 sec in case there was a JS error and Cordova JS never initialized correctly // Make app visible after 2 sec in case there was a JS error and Cordova JS never initialized correctly
if (this.appView.getVisibility() == View.INVISIBLE) { if (this.appView.getVisibility() == View.INVISIBLE) {
@ -172,7 +161,7 @@ public class AndroidWebViewClient extends WebViewClient implements CordovaWebVie
Thread.sleep(2000); Thread.sleep(2000);
cordova.getActivity().runOnUiThread(new Runnable() { cordova.getActivity().runOnUiThread(new Runnable() {
public void run() { public void run() {
appView.postMessage("spinner", "stop"); appView.getPluginManager().postMessage("spinner", "stop");
} }
}); });
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -184,7 +173,7 @@ public class AndroidWebViewClient extends WebViewClient implements CordovaWebVie
// Shutdown if blank loaded // Shutdown if blank loaded
if (url.equals("about:blank")) { if (url.equals("about:blank")) {
appView.postMessage("exit", null); appView.getPluginManager().postMessage("exit", null);
} }
} }
@ -206,7 +195,7 @@ public class AndroidWebViewClient extends WebViewClient implements CordovaWebVie
LOG.d(TAG, "CordovaWebViewClient.onReceivedError: Error code=%s Description=%s URL=%s", errorCode, description, failingUrl); LOG.d(TAG, "CordovaWebViewClient.onReceivedError: Error code=%s Description=%s URL=%s", errorCode, description, failingUrl);
// Clear timeout flag // Clear timeout flag
this.appView.incUrlTimeout(); appView.loadUrlTimeout++;
// Handle error // Handle error
JSONObject data = new JSONObject(); JSONObject data = new JSONObject();
@ -217,7 +206,7 @@ public class AndroidWebViewClient extends WebViewClient implements CordovaWebVie
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
} }
this.appView.postMessage("onReceivedError", data); this.appView.getPluginManager().postMessage("onReceivedError", data);
} }
/** /**
@ -326,10 +315,4 @@ public class AndroidWebViewClient extends WebViewClient implements CordovaWebVie
public void clearAuthenticationTokens() { public void clearAuthenticationTokens() {
this.authenticationTokens.clear(); this.authenticationTokens.clear();
} }
@Override
public void onReceivedError(int errorCode, String description, String url) {
this.onReceivedError(appView, errorCode, description, url);
}
} }

View File

@ -50,7 +50,6 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.Window; import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
import android.webkit.ValueCallback;
import android.webkit.WebViewClient; import android.webkit.WebViewClient;
import android.widget.LinearLayout; import android.widget.LinearLayout;
@ -162,11 +161,10 @@ public class CordovaActivity extends Activity implements CordovaInterface {
} }
appView = makeWebView(); appView = makeWebView();
appView.init(this, makeWebViewClient(appView), makeChromeClient(appView), pluginEntries, whitelist, preferences);
// TODO: Have the views set this themselves. // TODO: Have the views set this themselves.
if (preferences.getBoolean("DisallowOverscroll", false)) { if (preferences.getBoolean("DisallowOverscroll", false)) {
appView.setOverScrollMode(View.OVER_SCROLL_NEVER); appView.getView().setOverScrollMode(View.OVER_SCROLL_NEVER);
} }
createViews(); createViews();
@ -190,7 +188,6 @@ public class CordovaActivity extends Activity implements CordovaInterface {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
protected void createViews() { protected void createViews() {
// This builds the view. We could probably get away with NOT having a LinearLayout, but I like having a bucket!
// This builds the view. We could probably get away with NOT having a LinearLayout, but I like having a bucket! // This builds the view. We could probably get away with NOT having a LinearLayout, but I like having a bucket!
Display display = getWindowManager().getDefaultDisplay(); Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth(); int width = display.getWidth();
@ -201,15 +198,15 @@ public class CordovaActivity extends Activity implements CordovaInterface {
root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT, 0.0F)); ViewGroup.LayoutParams.MATCH_PARENT, 0.0F));
appView.setId(100); appView.getView().setId(100);
appView.setLayoutParams(new LinearLayout.LayoutParams( appView.getView().setLayoutParams(new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
1.0F)); 1.0F));
// Add web view but make it invisible while loading URL // Add web view but make it invisible while loading URL
appView.setVisibility(View.INVISIBLE); appView.getView().setVisibility(View.INVISIBLE);
root.addView((View) appView); root.addView(appView.getView());
setContentView(root); setContentView(root);
// TODO: Setting this on the appView causes it to show when <html style="opacity:0">. // TODO: Setting this on the appView causes it to show when <html style="opacity:0">.
@ -231,63 +228,34 @@ public class CordovaActivity extends Activity implements CordovaInterface {
* require a more specialized web view. * require a more specialized web view.
*/ */
protected CordovaWebView makeWebView() { protected CordovaWebView makeWebView() {
String r = preferences.getString("webView", "org.apache.cordova.AndroidWebView"); String r = preferences.getString("webView", null);
CordovaWebView ret = null;
if (r != null) {
try { try {
Class<?> webViewClass = Class.forName(r); Class<?> webViewClass = Class.forName(r);
Constructor<?>[] webViewConstructors = webViewClass.getConstructors(); Constructor<?> constructor = webViewClass.getConstructor(Context.class);
ret = (CordovaWebView) constructor.newInstance((Context)this);
if(CordovaWebView.class.isAssignableFrom(webViewClass)) {
for (Constructor<?> constructor : webViewConstructors) {
try {
CordovaWebView webView = (CordovaWebView) constructor.newInstance((Context)this);
return webView;
} catch (IllegalArgumentException e) {
LOG.d(TAG, "Illegal arguments; trying next constructor.");
}
}
}
LOG.e(TAG, "The WebView Engine is NOT a proper WebView, defaulting to system WebView");
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
LOG.e(TAG, "The WebView Engine was not found, defaulting to system WebView"); e.printStackTrace();
} catch (InstantiationException e) { } catch (InstantiationException e) {
LOG.e(TAG, "Unable to instantiate the WebView, defaulting to system WebView"); e.printStackTrace();
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
LOG.e(TAG, "Illegal Access to Constructor. This should never happen, defaulting to system WebView"); e.printStackTrace();
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
LOG.e(TAG, "The WebView does not implement the default constructor, defaulting to system WebView"); e.printStackTrace();
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
LOG.e(TAG, "Invocation Target Exception! Reflection is hard, defaulting to system WebView"); e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
} }
if (ret == null) {
// If all else fails, return a default WebView // If all else fails, return a default WebView
return (CordovaWebView) new AndroidWebView(this); ret = new AndroidWebView(this);
} }
ret.init(this, pluginEntries, whitelist, preferences);
/** return ret;
* Construct the client for the default web view object.
*
* This is intended to be overridable by subclasses of CordovaActivity which
* require a more specialized web view. By default, it allows the webView
* to create its own client objects.
*
* @param webView the default constructed web view object
*/
protected CordovaWebViewClient makeWebViewClient(CordovaWebView webView) {
return webView.makeWebViewClient(this);
}
/**
* Construct the chrome client for the default web view object.
*
* This is intended to be overridable by subclasses of CordovaActivity which
* require a more specialized web view. By default, it allows the webView
* to create its own client objects.
*
* @param webView the default constructed web view object
*/
protected CordovaChromeClient makeChromeClient(CordovaWebView webView) {
return webView.makeWebChromeClient(this);
} }
/** /**
@ -309,21 +277,17 @@ public class CordovaActivity extends Activity implements CordovaInterface {
this.keepRunning = preferences.getBoolean("KeepRunning", true); this.keepRunning = preferences.getBoolean("KeepRunning", true);
//Check if the view is attached to anything //Check if the view is attached to anything
if(appView.getParent() != null) if(appView.getView().getParent() != null)
{ {
// Then load the spinner // Then load the spinner
this.loadSpinner(); this.loadSpinner();
} }
//Load the correct splashscreen //Load the correct splashscreen
if(this.splashscreen != 0) if(this.splashscreen != 0)
{ {
this.appView.loadUrl(url, this.splashscreenTime); appView.getPluginManager().postMessage("splashscreen", "show");
}
else
{
this.appView.loadUrl(url);
} }
this.appView.loadUrlIntoView(url, true);
} }
/** /**
@ -458,15 +422,6 @@ public class CordovaActivity extends Activity implements CordovaInterface {
} }
} }
/**
* Send a message to all plugins.
*/
public void postMessage(String id, Object data) {
if (this.appView != null) {
this.appView.postMessage(id, data);
}
}
/** /**
* Show the spinner. Must be called from the UI thread. * Show the spinner. Must be called from the UI thread.
* *
@ -542,21 +497,15 @@ public class CordovaActivity extends Activity implements CordovaInterface {
super.onActivityResult(requestCode, resultCode, intent); super.onActivityResult(requestCode, resultCode, intent);
Log.d(TAG, "Request code = " + requestCode); Log.d(TAG, "Request code = " + requestCode);
if (appView != null && requestCode == AndroidChromeClient.FILECHOOSER_RESULTCODE) { if (appView != null && requestCode == AndroidChromeClient.FILECHOOSER_RESULTCODE) {
ValueCallback<Uri> mUploadMessage = ((CordovaChromeClient) this.appView.getWebChromeClient()).getValueCallback();
Log.d(TAG, "did we get here?");
if (null == mUploadMessage)
return;
Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData(); Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData();
Log.d(TAG, "result = " + result); appView.onFilePickerResult(result);
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
} }
CordovaPlugin callback = this.activityResultCallback; CordovaPlugin callback = this.activityResultCallback;
if(callback == null && initCallbackClass != null) { if(callback == null && initCallbackClass != null) {
// The application was restarted, but had defined an initial callback // The application was restarted, but had defined an initial callback
// before being shut down. // before being shut down.
//this.activityResultCallback = appView.pluginManager.getPlugin(initCallbackClass); //this.activityResultCallback = appView.pluginManager.getPlugin(initCallbackClass);
this.activityResultCallback = appView.getPlugin(initCallbackClass); this.activityResultCallback = appView.getPluginManager().getPlugin(initCallbackClass);
callback = this.activityResultCallback; callback = this.activityResultCallback;
} }
if(callback != null) { if(callback != null) {
@ -598,7 +547,7 @@ public class CordovaActivity extends Activity implements CordovaInterface {
me.runOnUiThread(new Runnable() { me.runOnUiThread(new Runnable() {
public void run() { public void run() {
if (exit) { if (exit) {
me.appView.setVisibility(View.GONE); me.appView.getView().setVisibility(View.GONE);
me.displayError("Application Error", description + " (" + failingUrl + ")", "OK", exit); me.displayError("Application Error", description + " (" + failingUrl + ")", "OK", exit);
} }
} }
@ -636,32 +585,24 @@ public class CordovaActivity extends Activity implements CordovaInterface {
}); });
} }
/**
* Determine if URL is in approved list of URLs to load.
*/
@Deprecated // Use whitelist object directly.
public boolean isUrlWhiteListed(String url) {
return whitelist.isUrlWhiteListed(url);
}
/* /*
* Hook in Cordova for menu plugins * Hook in Cordova for menu plugins
*/ */
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
this.postMessage("onCreateOptionsMenu", menu); appView.getPluginManager().postMessage("onCreateOptionsMenu", menu);
return super.onCreateOptionsMenu(menu); return super.onCreateOptionsMenu(menu);
} }
@Override @Override
public boolean onPrepareOptionsMenu(Menu menu) { public boolean onPrepareOptionsMenu(Menu menu) {
this.postMessage("onPrepareOptionsMenu", menu); appView.getPluginManager().postMessage("onPrepareOptionsMenu", menu);
return true; return true;
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
this.postMessage("onOptionsItemSelected", item); appView.getPluginManager().postMessage("onOptionsItemSelected", item);
return true; return true;
} }
@ -753,7 +694,7 @@ public class CordovaActivity extends Activity implements CordovaInterface {
else if ("spinner".equals(id)) { else if ("spinner".equals(id)) {
if ("stop".equals(data.toString())) { if ("stop".equals(data.toString())) {
this.spinnerStop(); this.spinnerStop();
this.appView.setVisibility(View.VISIBLE); this.appView.getView().setVisibility(View.VISIBLE);
} }
} }
else if ("onReceivedError".equals(id)) { else if ("onReceivedError".equals(id)) {

View File

@ -0,0 +1,167 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.apache.cordova;
import org.apache.cordova.PluginManager;
import org.json.JSONArray;
import org.json.JSONException;
import android.util.Log;
/**
* Contains APIs that the JS can call. All functions in here should also have
* an equivalent entry in CordovaChromeClient.java, and be added to
* cordova-js/lib/android/plugin/android/promptbasednativeapi.js
*/
public class CordovaBridge {
private static final String LOG_TAG = "CordovaBridge";
private PluginManager pluginManager;
private NativeToJsMessageQueue jsMessageQueue;
private volatile int bridgeSecret = -1; // written by UI thread, read by JS thread.
private String loadedUrl;
public CordovaBridge(PluginManager pluginManager, NativeToJsMessageQueue jsMessageQueue) {
this.pluginManager = pluginManager;
this.jsMessageQueue = jsMessageQueue;
}
public String jsExec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException {
verifySecret(bridgeSecret);
// If the arguments weren't received, send a message back to JS. It will switch bridge modes and try again. See CB-2666.
// We send a message meant specifically for this case. It starts with "@" so no other message can be encoded into the same string.
if (arguments == null) {
return "@Null arguments.";
}
jsMessageQueue.setPaused(true);
try {
// Tell the resourceApi what thread the JS is running on.
CordovaResourceApi.jsThread = Thread.currentThread();
pluginManager.exec(service, action, callbackId, arguments);
String ret = "";
if (!NativeToJsMessageQueue.DISABLE_EXEC_CHAINING) {
ret = jsMessageQueue.popAndEncode(false);
}
return ret;
} catch (Throwable e) {
e.printStackTrace();
return "";
} finally {
jsMessageQueue.setPaused(false);
}
}
public void jsSetNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException {
verifySecret(bridgeSecret);
jsMessageQueue.setBridgeMode(value);
}
public String jsRetrieveJsMessages(int bridgeSecret, boolean fromOnlineEvent) throws IllegalAccessException {
verifySecret(bridgeSecret);
return jsMessageQueue.popAndEncode(fromOnlineEvent);
}
private void verifySecret(int value) throws IllegalAccessException {
if (bridgeSecret < 0 || value != bridgeSecret) {
throw new IllegalAccessException();
}
}
/** Called on page transitions */
void clearBridgeSecret() {
bridgeSecret = -1;
}
/** Called by cordova.js to initialize the bridge. */
int generateBridgeSecret() {
bridgeSecret = (int)(Math.random() * Integer.MAX_VALUE);
return bridgeSecret;
}
public void reset(String loadedUrl) {
jsMessageQueue.reset();
clearBridgeSecret();
this.loadedUrl = loadedUrl;
}
public String promptOnJsPrompt(String origin, String message, String defaultValue) {
if (defaultValue != null && defaultValue.length() > 3 && defaultValue.startsWith("gap:")) {
JSONArray array;
try {
array = new JSONArray(defaultValue.substring(4));
int bridgeSecret = array.getInt(0);
String service = array.getString(1);
String action = array.getString(2);
String callbackId = array.getString(3);
String r = jsExec(bridgeSecret, service, action, callbackId, message);
return r == null ? "" : r;
} catch (JSONException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return "";
}
// Sets the native->JS bridge mode.
else if (defaultValue != null && defaultValue.startsWith("gap_bridge_mode:")) {
try {
int bridgeSecret = Integer.parseInt(defaultValue.substring(16));
jsSetNativeToJsBridgeMode(bridgeSecret, Integer.parseInt(message));
} catch (NumberFormatException e){
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return "";
}
// Polling for JavaScript messages
else if (defaultValue != null && defaultValue.startsWith("gap_poll:")) {
int bridgeSecret = Integer.parseInt(defaultValue.substring(9));
try {
String r = jsRetrieveJsMessages(bridgeSecret, "1".equals(message));
return r == null ? "" : r;
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return "";
}
else if (defaultValue != null && defaultValue.startsWith("gap_init:")) {
// Protect against random iframes being able to talk through the bridge.
// Trust only file URLs and the start URL's domain.
// The extra origin.startsWith("http") is to protect against iframes with data: having "" as origin.
if (origin.startsWith("file:") || (origin.startsWith("http") && loadedUrl.startsWith(origin))) {
// Enable the bridge
int bridgeMode = Integer.parseInt(defaultValue.substring(9));
jsMessageQueue.setBridgeMode(bridgeMode);
// Tell JS the bridge secret.
int secret = generateBridgeSecret();
return ""+secret;
} else {
Log.e(LOG_TAG, "gap_init called from restricted origin: " + origin);
}
return "";
}
return null;
}
public NativeToJsMessageQueue getMessageQueue() {
return jsMessageQueue;
}
}

View File

@ -1,26 +0,0 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.apache.cordova;
import android.net.Uri;
import android.webkit.ValueCallback;
public interface CordovaChromeClient {
ValueCallback<Uri> getValueCallback();
}

View File

@ -21,16 +21,15 @@ package org.apache.cordova;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.webkit.WebView;
class CordovaUriHelper { public class CordovaUriHelper {
private static final String TAG = "CordovaUriHelper"; private static final String TAG = "CordovaUriHelper";
private CordovaWebView appView; private CordovaWebView appView;
private CordovaInterface cordova; private CordovaInterface cordova;
CordovaUriHelper(CordovaInterface cdv, CordovaWebView webView) public CordovaUriHelper(CordovaInterface cdv, CordovaWebView webView)
{ {
appView = webView; appView = webView;
cordova = cdv; cordova = cdv;
@ -44,7 +43,7 @@ class CordovaUriHelper {
* @param url The url to be loaded. * @param url The url to be loaded.
* @return true to override, false for default behavior * @return true to override, false for default behavior
*/ */
boolean shouldOverrideUrlLoading(WebView view, String url) { public boolean shouldOverrideUrlLoading(String url) {
// The WebView should support http and https when going on the Internet // The WebView should support http and https when going on the Internet
if(url.startsWith("http:") || url.startsWith("https:")) if(url.startsWith("http:") || url.startsWith("https:"))
{ {
@ -55,7 +54,7 @@ class CordovaUriHelper {
} }
} }
// Give plugins the chance to handle the url // Give plugins the chance to handle the url
else if (this.appView.onOverrideUrlLoading(url)) { else if (this.appView.getPluginManager().onOverrideUrlLoading(url)) {
} }
else if(url.startsWith("file://") | url.startsWith("data:")) else if(url.startsWith("file://") | url.startsWith("data:"))

View File

@ -5,45 +5,19 @@ import java.util.List;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri;
import android.view.View; import android.view.View;
import android.webkit.WebChromeClient.CustomViewCallback; import android.webkit.WebChromeClient.CustomViewCallback;
import android.widget.LinearLayout.LayoutParams;
public interface CordovaWebView { public interface CordovaWebView {
public static final String CORDOVA_VERSION = "4.0.0-dev"; public static final String CORDOVA_VERSION = "4.0.0-dev";
void init(CordovaInterface cordova, CordovaWebViewClient webViewClient, CordovaChromeClient webChromeClient, void init(CordovaInterface cordova, List<PluginEntry> pluginEntries,
List<PluginEntry> pluginEntries, Whitelist whitelist, CordovaPreferences preferences); Whitelist whitelist, CordovaPreferences preferences);
View getView(); View getView();
CordovaWebViewClient makeWebViewClient(CordovaInterface cordova); void loadUrlIntoView(String url, boolean recreatePlugins);
CordovaChromeClient makeWebChromeClient(CordovaInterface cordova);
void setWebViewClient(CordovaWebViewClient webViewClient);
void setWebChromeClient(CordovaChromeClient webChromeClient);
void setId(int i);
void setLayoutParams(LayoutParams layoutParams);
void setVisibility(int invisible);
Object getParent();
void loadUrl(String url);
void loadUrl(String url, int splashscreenTime);
void loadUrlNow(String url);
void loadUrlIntoView(final String url);
void loadUrlIntoView(final String url, boolean recreatePlugins);
void loadUrlIntoView(final String url, final int splashscreenTime);
void stopLoading(); void stopLoading();
@ -63,10 +37,6 @@ public interface CordovaWebView {
void handleDestroy(); void handleDestroy();
void postMessage(String id, Object data);
void addJavascript(String statement);
/** /**
* Send JavaScript statement back to JavaScript. * Send JavaScript statement back to JavaScript.
* (This is a convenience method) * (This is a convenience method)
@ -93,32 +63,14 @@ public interface CordovaWebView {
@Deprecated @Deprecated
void sendJavascript(String statememt); void sendJavascript(String statememt);
CordovaChromeClient getWebChromeClient();
CordovaPlugin getPlugin(String initCallbackClass);
void showWebPage(String errorUrl, boolean b, boolean c, HashMap<String, Object> params); void showWebPage(String errorUrl, boolean b, boolean c, HashMap<String, Object> params);
Object getFocusedChild();
boolean isCustomViewShowing(); boolean isCustomViewShowing();
void showCustomView(View view, CustomViewCallback callback); void showCustomView(View view, CustomViewCallback callback);
void hideCustomView(); void hideCustomView();
Context getContext();
boolean onOverrideUrlLoading(String url);
int getVisibility();
void incUrlTimeout();
void setOverScrollMode(int overScrollNever);
void setNetworkAvailable(boolean online);
CordovaResourceApi getResourceApi(); CordovaResourceApi getResourceApi();
void setButtonPlumbedToJs(int keyCode, boolean override); void setButtonPlumbedToJs(int keyCode, boolean override);
@ -128,12 +80,15 @@ public interface CordovaWebView {
PluginManager getPluginManager(); PluginManager getPluginManager();
void setLayoutParams(android.widget.FrameLayout.LayoutParams layoutParams);
// Required for test
String getUrl();
boolean isPaused();
Whitelist getWhitelist(); Whitelist getWhitelist();
CordovaPreferences getPreferences(); CordovaPreferences getPreferences();
void onFilePickerResult(Uri uri);
void setNetworkAvailable(boolean online);
// TODO: Work on deleting these by removing refs from plugins.
Context getContext();
void loadUrl(String url);
Object postMessage(String id, Object data);
} }

View File

@ -1,5 +0,0 @@
package org.apache.cordova;
public interface CordovaWebViewClient {
void onReceivedError(int errorCode, String description, String url);
}

View File

@ -75,7 +75,7 @@ public class CoreAndroid extends CordovaPlugin {
// indicative of what this actually does (shows the webview). // indicative of what this actually does (shows the webview).
cordova.getActivity().runOnUiThread(new Runnable() { cordova.getActivity().runOnUiThread(new Runnable() {
public void run() { public void run() {
webView.postMessage("spinner", "stop"); webView.getPluginManager().postMessage("spinner", "stop");
} }
}); });
} }
@ -247,7 +247,7 @@ public class CoreAndroid extends CordovaPlugin {
* Exit the Android application. * Exit the Android application.
*/ */
public void exitApp() { public void exitApp() {
this.webView.postMessage("exit", null); this.webView.getPluginManager().postMessage("exit", null);
} }
@ -271,15 +271,15 @@ public class CoreAndroid extends CordovaPlugin {
String extraData = intent.getStringExtra(TelephonyManager.EXTRA_STATE); String extraData = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (extraData.equals(TelephonyManager.EXTRA_STATE_RINGING)) { if (extraData.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
LOG.i(TAG, "Telephone RINGING"); LOG.i(TAG, "Telephone RINGING");
webView.postMessage("telephone", "ringing"); webView.getPluginManager().postMessage("telephone", "ringing");
} }
else if (extraData.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) { else if (extraData.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
LOG.i(TAG, "Telephone OFFHOOK"); LOG.i(TAG, "Telephone OFFHOOK");
webView.postMessage("telephone", "offhook"); webView.getPluginManager().postMessage("telephone", "offhook");
} }
else if (extraData.equals(TelephonyManager.EXTRA_STATE_IDLE)) { else if (extraData.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
LOG.i(TAG, "Telephone IDLE"); LOG.i(TAG, "Telephone IDLE");
webView.postMessage("telephone", "idle"); webView.getPluginManager().postMessage("telephone", "idle");
} }
} }
} }

View File

@ -32,7 +32,7 @@ import android.webkit.WebResourceResponse;
import android.webkit.WebView; import android.webkit.WebView;
@TargetApi(Build.VERSION_CODES.HONEYCOMB) @TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class IceCreamCordovaWebViewClient extends AndroidWebViewClient implements CordovaWebViewClient{ public class IceCreamCordovaWebViewClient extends AndroidWebViewClient {
private static final String TAG = "IceCreamCordovaWebViewClient"; private static final String TAG = "IceCreamCordovaWebViewClient";

View File

@ -294,7 +294,7 @@ public class NativeToJsMessageQueue {
public void run() { public void run() {
String js = popAndEncodeAsJs(); String js = popAndEncodeAsJs();
if (js != null) { if (js != null) {
webView.loadUrlNow("javascript:" + js); webView.loadUrlIntoView("javascript:" + js, false);
} }
} }
}; };

View File

@ -53,17 +53,9 @@ public class PluginManager {
private Set<String> pluginIdWhitelist; private Set<String> pluginIdWhitelist;
PluginManager(CordovaWebView cordovaWebView, CordovaInterface cordova, List<PluginEntry> pluginEntries) { public PluginManager(CordovaWebView cordovaWebView, CordovaInterface cordova, List<PluginEntry> pluginEntries) {
this.ctx = cordova; this.ctx = cordova;
this.app = cordovaWebView; this.app = cordovaWebView;
setPluginEntries(pluginEntries);
}
public void setPluginEntries(List<PluginEntry> pluginEntries) {
this.onPause(false);
this.onDestroy();
this.clearPluginObjects();
entries.clear();
for (PluginEntry entry : pluginEntries) { for (PluginEntry entry : pluginEntries) {
addService(entry); addService(entry);
} }