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 2014/07/09 15:30:46 UTC

android commit: Delete Cordova*Client classes, Create CordovaBridge, Delete more CordovaWebView symbols

Repository: cordova-android
Updated Branches:
  refs/heads/4.0.x 25a7b6629 -> efcedabee


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

Changes made in order to get xwalk working again


Project: http://git-wip-us.apache.org/repos/asf/cordova-android/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-android/commit/efcedabe
Tree: http://git-wip-us.apache.org/repos/asf/cordova-android/tree/efcedabe
Diff: http://git-wip-us.apache.org/repos/asf/cordova-android/diff/efcedabe

Branch: refs/heads/4.0.x
Commit: efcedabee098d28e7c3e87dc3a7414b4a235a5fc
Parents: 25a7b66
Author: Andrew Grieve <ag...@chromium.org>
Authored: Wed Jul 9 09:29:33 2014 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Jul 9 09:29:33 2014 -0400

----------------------------------------------------------------------
 .../org/apache/cordova/AndroidChromeClient.java |  75 +-----
 .../org/apache/cordova/AndroidExposedJsApi.java |  59 +----
 .../src/org/apache/cordova/AndroidWebView.java  | 263 ++++---------------
 .../apache/cordova/AndroidWebViewClient.java    |  35 +--
 .../src/org/apache/cordova/CordovaActivity.java | 141 +++-------
 .../src/org/apache/cordova/CordovaBridge.java   | 167 ++++++++++++
 .../org/apache/cordova/CordovaChromeClient.java |  26 --
 .../org/apache/cordova/CordovaUriHelper.java    |   9 +-
 .../src/org/apache/cordova/CordovaWebView.java  |  71 +----
 .../apache/cordova/CordovaWebViewClient.java    |   5 -
 .../src/org/apache/cordova/CoreAndroid.java     |  10 +-
 .../cordova/IceCreamCordovaWebViewClient.java   |   2 +-
 .../apache/cordova/NativeToJsMessageQueue.java  |   2 +-
 .../src/org/apache/cordova/PluginManager.java   |  12 +-
 14 files changed, 302 insertions(+), 575 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/efcedabe/framework/src/org/apache/cordova/AndroidChromeClient.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/AndroidChromeClient.java b/framework/src/org/apache/cordova/AndroidChromeClient.java
index a683ec6..e4ebe96 100755
--- a/framework/src/org/apache/cordova/AndroidChromeClient.java
+++ b/framework/src/org/apache/cordova/AndroidChromeClient.java
@@ -20,8 +20,6 @@ package org.apache.cordova;
 
 import org.apache.cordova.CordovaInterface;
 import org.apache.cordova.LOG;
-import org.json.JSONArray;
-import org.json.JSONException;
 
 import android.annotation.TargetApi;
 import android.app.AlertDialog;
@@ -44,7 +42,6 @@ import android.widget.EditText;
 import android.widget.LinearLayout;
 import android.widget.ProgressBar;
 import android.widget.RelativeLayout;
-import android.util.Log;
 
 /**
  * This class is the WebChromeClient that implements callbacks for our web view.
@@ -57,7 +54,7 @@ import android.util.Log;
  * @see CordovaWebViewClient
  * @see CordovaWebView
  */
-public class AndroidChromeClient extends WebChromeClient implements CordovaChromeClient {
+public class AndroidChromeClient extends WebChromeClient {
 
     public static final int FILECHOOSER_RESULTCODE = 5173;
     private static final String LOG_TAG = "AndroidChromeClient";
@@ -69,7 +66,7 @@ public class AndroidChromeClient extends WebChromeClient implements CordovaChrom
     private View mVideoProgressView;
     
     // File Chooser
-    public ValueCallback<Uri> mUploadMessage;
+    protected ValueCallback<Uri> mUploadMessage;
     
     public AndroidChromeClient(CordovaInterface ctx, AndroidWebView app) {
         this.cordova = ctx;
@@ -182,67 +179,9 @@ public class AndroidChromeClient extends WebChromeClient implements CordovaChrom
     @Override
     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.
-        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 = 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();
-            }
+        String handledRet = appView.bridge.promptOnJsPrompt(origin, message, defaultValue);
+        if (handledRet != null) {
+            result.confirm(handledRet);
         } else {
             // Returning false would also show a dialog, but the default one shows the origin (ugly).
             final JsPromptResult res = result;
@@ -375,8 +314,4 @@ public class AndroidChromeClient extends WebChromeClient implements CordovaChrom
         this.cordova.getActivity().startActivityForResult(Intent.createChooser(i, "File Browser"),
                 FILECHOOSER_RESULTCODE);
     }
-    
-    public ValueCallback<Uri> getValueCallback() {
-        return this.mUploadMessage;
-    }
 }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/efcedabe/framework/src/org/apache/cordova/AndroidExposedJsApi.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/AndroidExposedJsApi.java b/framework/src/org/apache/cordova/AndroidExposedJsApi.java
index 5f53774..5ed4d40 100755
--- a/framework/src/org/apache/cordova/AndroidExposedJsApi.java
+++ b/framework/src/org/apache/cordova/AndroidExposedJsApi.java
@@ -19,7 +19,6 @@
 package org.apache.cordova;
 
 import android.webkit.JavascriptInterface;
-import org.apache.cordova.PluginManager;
 import org.json.JSONException;
 
 /**
@@ -28,70 +27,24 @@ import org.json.JSONException;
  * cordova-js/lib/android/plugin/android/promptbasednativeapi.js
  */
 class AndroidExposedJsApi implements ExposedJsApi {
+    private final CordovaBridge bridge;
 
-    private PluginManager pluginManager;
-    private NativeToJsMessageQueue jsMessageQueue;
-    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;
+    AndroidExposedJsApi(CordovaBridge bridge) {
+        this.bridge = bridge;
     }
 
     @JavascriptInterface
     public String exec(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);
-        }
+        return bridge.jsExec(bridgeSecret, service, action, callbackId, arguments);
     }
 
     @JavascriptInterface
     public void setNativeToJsBridgeMode(int bridgeSecret, int value) throws IllegalAccessException {
-        verifySecret(bridgeSecret);
-        jsMessageQueue.setBridgeMode(value);
+        bridge.jsSetNativeToJsBridgeMode(bridgeSecret, value);
     }
 
     @JavascriptInterface
     public String retrieveJsMessages(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;
+        return bridge.jsRetrieveJsMessages(bridgeSecret, fromOnlineEvent);
     }
 }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/efcedabe/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 8499caf..135920c 100755
--- a/framework/src/org/apache/cordova/AndroidWebView.java
+++ b/framework/src/org/apache/cordova/AndroidWebView.java
@@ -24,7 +24,6 @@ import java.lang.reflect.Method;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Locale;
 
 import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
@@ -66,23 +65,21 @@ public class AndroidWebView extends WebView implements CordovaWebView {
     private HashSet<Integer> boundKeyCodes = new HashSet<Integer>();
 
     PluginManager pluginManager;
-    private boolean paused;
 
     private BroadcastReceiver receiver;
 
 
     /** Activities and other important classes **/
     private CordovaInterface cordova;
-    CordovaWebViewClient viewClient;
-    private CordovaChromeClient chromeClient;
+    AndroidWebViewClient viewClient;
+    private AndroidChromeClient chromeClient;
 
     // Flag to track that a loadUrl timeout occurred
     int loadUrlTimeout = 0;
 
     private long lastMenuEventTime = 0;
 
-    NativeToJsMessageQueue jsMessageQueue;
-    AndroidExposedJsApi exposedJsApi;
+    CordovaBridge bridge;
 
     /** custom view created by the browser (a video player for example) */
     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.
     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 =
             new FrameLayout.LayoutParams(
             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.
     @Override
-    public void init(CordovaInterface cordova, CordovaWebViewClient webViewClient, CordovaChromeClient webChromeClient,
-                     List<PluginEntry> pluginEntries, Whitelist whitelist, CordovaPreferences preferences) {
+    public void init(CordovaInterface cordova, List<PluginEntry> pluginEntries,
+            Whitelist whitelist, CordovaPreferences preferences) {
         if (this.cordova != null) {
             throw new IllegalStateException();
         }
         this.cordova = cordova;
-        setWebChromeClient(webChromeClient);
-        setWebViewClient(webViewClient);
         this.whitelist = whitelist;
         this.preferences = preferences;
 
         pluginManager = new PluginManager(this, this.cordova, pluginEntries);
-        jsMessageQueue = new NativeToJsMessageQueue(this, cordova);
-        exposedJsApi = new AndroidExposedJsApi(pluginManager, jsMessageQueue);
         resourceApi = new CordovaResourceApi(this.getContext(), pluginManager);
-
+        bridge = new CordovaBridge(pluginManager, new NativeToJsMessageQueue(this, cordova));
         pluginManager.addService("App", "org.apache.cordova.CoreAndroid");
         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();
     }
 
@@ -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
 	 * focus when your application start
@@ -284,80 +259,42 @@ public class AndroidWebView extends WebView implements CordovaWebView {
             // use the prompt bridge instead.
             return;            
         } 
+        AndroidExposedJsApi exposedJsApi = new AndroidExposedJsApi(bridge);
         this.addJavascriptInterface(exposedJsApi, "_cordovaNative");
     }
 
     @Override
     public void setWebViewClient(WebViewClient client) {
-        this.viewClient = (CordovaWebViewClient)client;
+        this.viewClient = (AndroidWebViewClient)client;
         super.setWebViewClient(client);
     }
 
     @Override
     public void setWebChromeClient(WebChromeClient client) {
-        this.chromeClient = (CordovaChromeClient)client;
+        this.chromeClient = (AndroidChromeClient)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.
-     *
-     * @param url
      */
     @Override
     public void loadUrl(String url) {
-        if (url.equals("about:blank") || url.startsWith("javascript:")) {
-            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);
+        this.loadUrlIntoView(url, true);
     }
 
     /**
      * Load the url into the webview.
-     *
-     * @param url
      */
+    @Override
     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 + ")");
+        recreatePlugins = recreatePlugins || (loadedUrl == null);
 
         if (recreatePlugins) {
             this.loadedUrl = url;
@@ -367,7 +304,7 @@ public class AndroidWebView extends WebView implements CordovaWebView {
         // Create a timeout timer for loadUrl
         final AndroidWebView me = this;
         final int currentLoadUrlTimeout = me.loadUrlTimeout;
-        final int loadUrlTimeoutValue = Integer.parseInt(this.getProperty("LoadUrlTimeoutValue", "20000"));
+        final int loadUrlTimeoutValue = preferences.getInteger("LoadUrlTimeoutValue", 20000);
 
         // Timeout error method
         final Runnable loadError = new Runnable() {
@@ -375,7 +312,7 @@ public class AndroidWebView extends WebView implements CordovaWebView {
                 me.stopLoading();
                 LOG.e(TAG, "CordovaWebView: TIMEOUT ERROR!");
                 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.
-     *
-     * @param url
      */
-    public void loadUrlNow(String url) {
+    private void loadUrlNow(String url) {
         if (LOG.isLoggable(LOG.DEBUG) && !url.startsWith("javascript:")) {
             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
     public void stopLoading() {
         //viewClient.isCurrentlyLoading = false;
@@ -459,44 +367,25 @@ public class AndroidWebView extends WebView implements CordovaWebView {
         super.onScrollChanged(l, t, oldl, oldt);
         //We should post a message that the scroll changed
         ScrollEvent myEvent = new ScrollEvent(l, t, oldl, oldt, this);
-        this.postMessage("onScrollChanged", myEvent);
+        pluginManager.postMessage("onScrollChanged", myEvent);
     }
     
     /**
      * Send JavaScript statement back to JavaScript.
      * (This is a convenience method)
-     *
-     * @param statement
      */
     public void sendJavascript(String statement) {
-        this.jsMessageQueue.addJavaScript(statement);
+        bridge.getMessageQueue().addJavaScript(statement);
     }
 
     /**
      * Send a plugin result back to JavaScript.
-     * (This is a convenience method)
-     *
-     * @param result
-     * @param 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)
      *
      * @return true if we went back, false if we are already at top
@@ -540,7 +429,7 @@ public class AndroidWebView extends WebView implements CordovaWebView {
             if (url.startsWith("file://") || whitelist.isUrlWhiteListed(url)) {
                 // TODO: What about params?
                 // Load new URL
-                this.loadUrl(url);
+                loadUrlIntoView(url, true);
                 return;
             }
             // 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
      */
@@ -705,13 +574,10 @@ public class AndroidWebView extends WebView implements CordovaWebView {
             // Pause JavaScript timers (including setInterval)
             this.pauseTimers();
         }
-        paused = true;
-   
     }
     
     public void handleResume(boolean keepRunning, boolean activityResultKeepRunning)
     {
-
         this.loadUrl("javascript:try{cordova.fireDocumentEvent('resume');}catch(e){console.log('exception firing resume event from native');};");
         
         // Forward to plugins
@@ -721,7 +587,6 @@ public class AndroidWebView extends WebView implements CordovaWebView {
 
         // Resume JavaScript timers (including setInterval)
         this.resumeTimers();
-        paused = false;
     }
     
     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:
     // VFY: unable to resolve virtual method 285: Landroid/webkit/WebSettings;.setAllowUniversalAccessFromFileURLs
     @TargetApi(16)
@@ -862,58 +722,18 @@ public class AndroidWebView extends WebView implements CordovaWebView {
         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() {
         boundKeyCodes.clear();
         pluginManager.onReset();
-        jsMessageQueue.reset();
-        exposedJsApi.clearBridgeSecret();
-    }
-
-    @Override
-    public void incUrlTimeout() {
-        this.loadUrlTimeout++;
+        bridge.reset(loadedUrl);
     }
 
     @Override
     public PluginManager getPluginManager() {
-        // TODO Auto-generated method stub
         return this.pluginManager;
     }
 
     @Override
-    public void setLayoutParams(
-            android.widget.FrameLayout.LayoutParams layoutParams) {
-        super.setLayoutParams(layoutParams);
-    }
-
-    @Override
     public View getView() {
         return this;
     }
@@ -927,4 +747,17 @@ public class AndroidWebView extends WebView implements CordovaWebView {
     public CordovaPreferences getPreferences() {
         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);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/efcedabe/framework/src/org/apache/cordova/AndroidWebViewClient.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/AndroidWebViewClient.java b/framework/src/org/apache/cordova/AndroidWebViewClient.java
index 047e1af..44862a6 100755
--- a/framework/src/org/apache/cordova/AndroidWebViewClient.java
+++ b/framework/src/org/apache/cordova/AndroidWebViewClient.java
@@ -48,7 +48,7 @@ import android.webkit.WebViewClient;
  * @see CordovaChromeClient
  * @see CordovaWebView
  */
-public class AndroidWebViewClient extends WebViewClient implements CordovaWebViewClient{
+public class AndroidWebViewClient extends WebViewClient {
 
     private static final String TAG = "AndroidWebViewClient";
     protected final CordovaInterface cordova;
@@ -60,12 +60,6 @@ public class AndroidWebViewClient extends WebViewClient implements CordovaWebVie
     /** The authorization tokens. */
     private Hashtable<String, AuthenticationToken> authenticationTokens = new Hashtable<String, AuthenticationToken>();
 
-    /**
-     * Constructor.
-     *
-     * @param cordova
-     * @param view
-     */
     public AndroidWebViewClient(CordovaInterface cordova, AndroidWebView view) {
         this.cordova = cordova;
         this.appView = view;
@@ -82,17 +76,12 @@ public class AndroidWebViewClient extends WebViewClient implements CordovaWebVie
      */
 	@Override
     public boolean shouldOverrideUrlLoading(WebView view, String url) {
-        return helper.shouldOverrideUrlLoading(view, url);
+        return helper.shouldOverrideUrlLoading(url);
     }
     
     /**
      * 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
-     *
-     * @param view
-     * @param handler
-     * @param host
-     * @param realm
      */
     @Override
     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();
 
         // 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
-        this.appView.incUrlTimeout();
+        appView.loadUrlTimeout++;
 
         // 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
         if (this.appView.getVisibility() == View.INVISIBLE) {
@@ -172,7 +161,7 @@ public class AndroidWebViewClient extends WebViewClient implements CordovaWebVie
                         Thread.sleep(2000);
                         cordova.getActivity().runOnUiThread(new Runnable() {
                             public void run() {
-                                appView.postMessage("spinner", "stop");
+                                appView.getPluginManager().postMessage("spinner", "stop");
                             }
                         });
                     } catch (InterruptedException e) {
@@ -184,7 +173,7 @@ public class AndroidWebViewClient extends WebViewClient implements CordovaWebVie
 
         // Shutdown if blank loaded
         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);
 
         // Clear timeout flag
-        this.appView.incUrlTimeout();
+        appView.loadUrlTimeout++;
 
         // Handle error
         JSONObject data = new JSONObject();
@@ -217,7 +206,7 @@ public class AndroidWebViewClient extends WebViewClient implements CordovaWebVie
         } catch (JSONException e) {
             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() {
         this.authenticationTokens.clear();
     }
-
-    @Override
-    public void onReceivedError(int errorCode, String description, String url) {
-        this.onReceivedError(appView, errorCode, description, url);
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/efcedabe/framework/src/org/apache/cordova/CordovaActivity.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaActivity.java b/framework/src/org/apache/cordova/CordovaActivity.java
index dbb6fee..4bf65fd 100755
--- a/framework/src/org/apache/cordova/CordovaActivity.java
+++ b/framework/src/org/apache/cordova/CordovaActivity.java
@@ -50,7 +50,6 @@ import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowManager;
-import android.webkit.ValueCallback;
 import android.webkit.WebViewClient;
 import android.widget.LinearLayout;
 
@@ -162,11 +161,10 @@ public class CordovaActivity extends Activity implements CordovaInterface {
         }
 
         appView = makeWebView();
-        appView.init(this, makeWebViewClient(appView), makeChromeClient(appView), pluginEntries, whitelist, preferences);
 
         // TODO: Have the views set this themselves.
         if (preferences.getBoolean("DisallowOverscroll", false)) {
-            appView.setOverScrollMode(View.OVER_SCROLL_NEVER);
+            appView.getView().setOverScrollMode(View.OVER_SCROLL_NEVER);
         }
         createViews();
 
@@ -191,7 +189,6 @@ public class CordovaActivity extends Activity implements CordovaInterface {
     @SuppressWarnings("deprecation")
     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!
         Display display = getWindowManager().getDefaultDisplay();
         int width = display.getWidth();
         int height = display.getHeight();
@@ -201,15 +198,15 @@ public class CordovaActivity extends Activity implements CordovaInterface {
         root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.MATCH_PARENT, 0.0F));
 
-        appView.setId(100);
-        appView.setLayoutParams(new LinearLayout.LayoutParams(
+        appView.getView().setId(100);
+        appView.getView().setLayoutParams(new LinearLayout.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 1.0F));
 
         // Add web view but make it invisible while loading URL
-        appView.setVisibility(View.INVISIBLE);
-        root.addView((View) appView);
+        appView.getView().setVisibility(View.INVISIBLE);
+        root.addView(appView.getView());
         setContentView(root);
 
         // 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.
      */
     protected CordovaWebView makeWebView() {
-        String r = preferences.getString("webView", "org.apache.cordova.AndroidWebView");
-
-        try {
-            Class<?> webViewClass = Class.forName(r);
-            Constructor<?>[] webViewConstructors = webViewClass.getConstructors();
-
-            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.");
-                    }
-                }
+        String r = preferences.getString("webView", null);
+        CordovaWebView ret = null;
+        if (r != null) {
+            try {
+                Class<?> webViewClass = Class.forName(r);
+                Constructor<?> constructor = webViewClass.getConstructor(Context.class);
+                ret = (CordovaWebView) constructor.newInstance((Context)this);
+            } catch (ClassNotFoundException e) {
+                e.printStackTrace();
+            } catch (InstantiationException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (InvocationTargetException e) {
+                e.printStackTrace();
+            } catch (NoSuchMethodException e) {
+                e.printStackTrace();
             }
-            LOG.e(TAG, "The WebView Engine is NOT a proper WebView, defaulting to system WebView");
-        } catch (ClassNotFoundException e) {
-            LOG.e(TAG, "The WebView Engine was not found, defaulting to system WebView");
-        } catch (InstantiationException e) {
-            LOG.e(TAG, "Unable to instantiate the WebView, defaulting to system WebView");
-        } catch (IllegalAccessException e) {
-            LOG.e(TAG, "Illegal Access to Constructor.  This should never happen, defaulting to system WebView");
-        } catch (IllegalArgumentException e) {
-            LOG.e(TAG, "The WebView does not implement the default constructor, defaulting to system WebView");
-        } catch (InvocationTargetException e) {
-            LOG.e(TAG, "Invocation Target Exception! Reflection is hard, defaulting to system WebView");
         }
-        
-        // If all else fails, return a default WebView
-        return (CordovaWebView) new AndroidWebView(this);
-    }
-
-    /**
-     * 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);
+            
+        if (ret == null) {
+            // If all else fails, return a default WebView
+            ret = new AndroidWebView(this);
+        }
+        ret.init(this, pluginEntries, whitelist, preferences);
+        return ret;
     }
 
     /**
@@ -309,21 +277,17 @@ public class CordovaActivity extends Activity implements CordovaInterface {
         this.keepRunning = preferences.getBoolean("KeepRunning", true);
 
         //Check if the view is attached to anything
-        if(appView.getParent() != null)
+        if(appView.getView().getParent() != null)
         {
             // Then load the spinner
             this.loadSpinner();
         }
         //Load the correct splashscreen
-        
         if(this.splashscreen != 0)
         {
-            this.appView.loadUrl(url, this.splashscreenTime);
-        }
-        else
-        {
-            this.appView.loadUrl(url);
+            appView.getPluginManager().postMessage("splashscreen", "show");
         }
+        this.appView.loadUrlIntoView(url, true);
     }
 
     /**
@@ -459,15 +423,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.
      *
      * @param title         Title of the dialog
@@ -542,21 +497,15 @@ public class CordovaActivity extends Activity implements CordovaInterface {
         super.onActivityResult(requestCode, resultCode, intent);
         Log.d(TAG, "Request code = " + requestCode);
         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();
-            Log.d(TAG, "result = " + result);
-            mUploadMessage.onReceiveValue(result);
-            mUploadMessage = null;
+            appView.onFilePickerResult(result);
         }
         CordovaPlugin callback = this.activityResultCallback;
         if(callback == null && initCallbackClass != null) {
             // The application was restarted, but had defined an initial callback
             // before being shut down.
             //this.activityResultCallback = appView.pluginManager.getPlugin(initCallbackClass);
-            this.activityResultCallback = appView.getPlugin(initCallbackClass);
+            this.activityResultCallback = appView.getPluginManager().getPlugin(initCallbackClass);
             callback = this.activityResultCallback;
         }
         if(callback != null) {
@@ -598,7 +547,7 @@ public class CordovaActivity extends Activity implements CordovaInterface {
             me.runOnUiThread(new Runnable() {
                 public void run() {
                     if (exit) {
-                        me.appView.setVisibility(View.GONE);
+                        me.appView.getView().setVisibility(View.GONE);
                         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
      */
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
-        this.postMessage("onCreateOptionsMenu", menu);
+        appView.getPluginManager().postMessage("onCreateOptionsMenu", menu);
         return super.onCreateOptionsMenu(menu);
     }
 
     @Override
     public boolean onPrepareOptionsMenu(Menu menu) {
-        this.postMessage("onPrepareOptionsMenu", menu);
+        appView.getPluginManager().postMessage("onPrepareOptionsMenu", menu);
         return true;
     }
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-        this.postMessage("onOptionsItemSelected", item);
+        appView.getPluginManager().postMessage("onOptionsItemSelected", item);
         return true;
     }
 
@@ -753,7 +694,7 @@ public class CordovaActivity extends Activity implements CordovaInterface {
         else if ("spinner".equals(id)) {
             if ("stop".equals(data.toString())) {
                 this.spinnerStop();
-                this.appView.setVisibility(View.VISIBLE);
+                this.appView.getView().setVisibility(View.VISIBLE);
             }
         }
         else if ("onReceivedError".equals(id)) {

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/efcedabe/framework/src/org/apache/cordova/CordovaBridge.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaBridge.java b/framework/src/org/apache/cordova/CordovaBridge.java
new file mode 100644
index 0000000..d9efb3b
--- /dev/null
+++ b/framework/src/org/apache/cordova/CordovaBridge.java
@@ -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;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/efcedabe/framework/src/org/apache/cordova/CordovaChromeClient.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaChromeClient.java b/framework/src/org/apache/cordova/CordovaChromeClient.java
deleted file mode 100644
index f5f470f..0000000
--- a/framework/src/org/apache/cordova/CordovaChromeClient.java
+++ /dev/null
@@ -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();
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/efcedabe/framework/src/org/apache/cordova/CordovaUriHelper.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaUriHelper.java b/framework/src/org/apache/cordova/CordovaUriHelper.java
index 2d3f3d8..077e425 100644
--- a/framework/src/org/apache/cordova/CordovaUriHelper.java
+++ b/framework/src/org/apache/cordova/CordovaUriHelper.java
@@ -21,16 +21,15 @@ package org.apache.cordova;
 
 import android.content.Intent;
 import android.net.Uri;
-import android.webkit.WebView;
 
-class CordovaUriHelper {
+public class CordovaUriHelper {
     
     private static final String TAG = "CordovaUriHelper";
     
     private CordovaWebView appView;
     private CordovaInterface cordova;
     
-    CordovaUriHelper(CordovaInterface cdv, CordovaWebView webView)
+    public CordovaUriHelper(CordovaInterface cdv, CordovaWebView webView)
     {
         appView = webView;
         cordova = cdv;
@@ -44,7 +43,7 @@ class CordovaUriHelper {
      * @param url           The url to be loaded.
      * @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
         if(url.startsWith("http:") || url.startsWith("https:"))
         {
@@ -55,7 +54,7 @@ class CordovaUriHelper {
             }
         }
         // 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:"))

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/efcedabe/framework/src/org/apache/cordova/CordovaWebView.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaWebView.java b/framework/src/org/apache/cordova/CordovaWebView.java
index 977ad4d..366acff 100644
--- a/framework/src/org/apache/cordova/CordovaWebView.java
+++ b/framework/src/org/apache/cordova/CordovaWebView.java
@@ -5,45 +5,19 @@ import java.util.List;
 
 import android.content.Context;
 import android.content.Intent;
+import android.net.Uri;
 import android.view.View;
 import android.webkit.WebChromeClient.CustomViewCallback;
-import android.widget.LinearLayout.LayoutParams;
 
 public interface CordovaWebView {
     public static final String CORDOVA_VERSION = "4.0.0-dev";
 
-    void init(CordovaInterface cordova, CordovaWebViewClient webViewClient, CordovaChromeClient webChromeClient,
-              List<PluginEntry> pluginEntries, Whitelist whitelist, CordovaPreferences preferences);
+    void init(CordovaInterface cordova, List<PluginEntry> pluginEntries,
+            Whitelist whitelist, CordovaPreferences preferences);
 
     View getView();
 
-    CordovaWebViewClient makeWebViewClient(CordovaInterface cordova);
-
-    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 loadUrlIntoView(String url, boolean recreatePlugins);
 
     void stopLoading();
 
@@ -63,10 +37,6 @@ public interface CordovaWebView {
 
     void handleDestroy();
 
-    void postMessage(String id, Object data);
-
-    void addJavascript(String statement);
-
     /**
      * Send JavaScript statement back to JavaScript.
      * (This is a convenience method)
@@ -93,32 +63,14 @@ public interface CordovaWebView {
     @Deprecated
     void sendJavascript(String statememt);
 
-    CordovaChromeClient getWebChromeClient();
-
-    CordovaPlugin getPlugin(String initCallbackClass);
-
     void showWebPage(String errorUrl, boolean b, boolean c, HashMap<String, Object> params);
 
-    Object getFocusedChild();
-
     boolean isCustomViewShowing();
 
     void showCustomView(View view, CustomViewCallback callback);
 
     void hideCustomView();
 
-    Context getContext();
-
-    boolean onOverrideUrlLoading(String url);
-
-    int getVisibility();
-
-    void incUrlTimeout();
-
-    void setOverScrollMode(int overScrollNever);
-
-    void setNetworkAvailable(boolean online);
-
     CordovaResourceApi getResourceApi();
 
     void setButtonPlumbedToJs(int keyCode, boolean override);
@@ -128,12 +80,15 @@ public interface CordovaWebView {
 
     PluginManager getPluginManager();
 
-    void setLayoutParams(android.widget.FrameLayout.LayoutParams layoutParams);
-    
-    // Required for test
-    String getUrl();
-    boolean isPaused();
-    
     Whitelist getWhitelist();
     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);
 }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/efcedabe/framework/src/org/apache/cordova/CordovaWebViewClient.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaWebViewClient.java b/framework/src/org/apache/cordova/CordovaWebViewClient.java
deleted file mode 100644
index 671e227..0000000
--- a/framework/src/org/apache/cordova/CordovaWebViewClient.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package org.apache.cordova;
-
-public interface CordovaWebViewClient {
-    void onReceivedError(int errorCode, String description, String url);
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/efcedabe/framework/src/org/apache/cordova/CoreAndroid.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CoreAndroid.java b/framework/src/org/apache/cordova/CoreAndroid.java
index 6403673..55cf9fb 100755
--- a/framework/src/org/apache/cordova/CoreAndroid.java
+++ b/framework/src/org/apache/cordova/CoreAndroid.java
@@ -75,7 +75,7 @@ public class CoreAndroid extends CordovaPlugin {
                 // indicative of what this actually does (shows the webview).
                 cordova.getActivity().runOnUiThread(new Runnable() {
                     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.
      */
     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);
                         if (extraData.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
                             LOG.i(TAG, "Telephone RINGING");
-                            webView.postMessage("telephone", "ringing");
+                            webView.getPluginManager().postMessage("telephone", "ringing");
                         }
                         else if (extraData.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
                             LOG.i(TAG, "Telephone OFFHOOK");
-                            webView.postMessage("telephone", "offhook");
+                            webView.getPluginManager().postMessage("telephone", "offhook");
                         }
                         else if (extraData.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
                             LOG.i(TAG, "Telephone IDLE");
-                            webView.postMessage("telephone", "idle");
+                            webView.getPluginManager().postMessage("telephone", "idle");
                         }
                     }
                 }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/efcedabe/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
index 4938091..68f8741 100644
--- a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
+++ b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
@@ -32,7 +32,7 @@ import android.webkit.WebResourceResponse;
 import android.webkit.WebView;
 
 @TargetApi(Build.VERSION_CODES.HONEYCOMB)
-public class IceCreamCordovaWebViewClient extends AndroidWebViewClient implements CordovaWebViewClient{
+public class IceCreamCordovaWebViewClient extends AndroidWebViewClient {
 
     private static final String TAG = "IceCreamCordovaWebViewClient";
 

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/efcedabe/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 b822800..08ca00e 100755
--- a/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
+++ b/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
@@ -294,7 +294,7 @@ public class NativeToJsMessageQueue {
             public void run() {
                 String js = popAndEncodeAsJs();
                 if (js != null) {
-                    webView.loadUrlNow("javascript:" + js);
+                    webView.loadUrlIntoView("javascript:" + js, false);
                 }
             }
         };

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/efcedabe/framework/src/org/apache/cordova/PluginManager.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/PluginManager.java b/framework/src/org/apache/cordova/PluginManager.java
index 9a28361..699f7cb 100755
--- a/framework/src/org/apache/cordova/PluginManager.java
+++ b/framework/src/org/apache/cordova/PluginManager.java
@@ -53,22 +53,14 @@ public class PluginManager {
 
     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.app = cordovaWebView;
-        setPluginEntries(pluginEntries);
-    }
-
-    public void setPluginEntries(List<PluginEntry> pluginEntries) {
-        this.onPause(false);
-        this.onDestroy();
-        this.clearPluginObjects();
-        entries.clear();
         for (PluginEntry entry : pluginEntries) {
             addService(entry);
         }
     }
-    
+
     public void setPluginIdWhitelist(Set<String> pluginIdWhitelist) {
         this.pluginIdWhitelist = pluginIdWhitelist;
     }