Merging latest master, including new tests

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

Branch: refs/heads/4.0.x
Commit: a7ccb9243daf3dfaa0f2538492dccaa4d140ba58
Parents: f9b8f9a 320e31b
Author: Joe Bowser <[email protected]>
Authored: Thu Aug 14 14:20:49 2014 -0700
Committer: Joe Bowser <[email protected]>
Committed: Thu Aug 14 14:20:49 2014 -0700

----------------------------------------------------------------------
 .../apache/cordova/AndroidWebViewClient.java    | 14 +++-
 .../src/org/apache/cordova/CordovaActivity.java |  3 +
 .../org/apache/cordova/CordovaUriHelper.java    |  9 +++
 .../apache/cordova/NativeToJsMessageQueue.java  | 13 ++--
 framework/src/org/apache/cordova/Whitelist.java |  8 +--
 test/assets/www/error.html                      |  8 +++
 .../test/CordovaWebViewTestActivity.java        |  9 ++-
 .../apache/cordova/test/SabotagedActivity.java  | 73 ++++++++++++++++++++
 .../test/junit/IntentUriOverrideTest.java       | 73 ++++++++++++++++++++
 9 files changed, 198 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/a7ccb924/framework/src/org/apache/cordova/AndroidWebViewClient.java
----------------------------------------------------------------------
diff --cc framework/src/org/apache/cordova/AndroidWebViewClient.java
index 44862a6,0000000..c017177
mode 100755,000000..100755
--- a/framework/src/org/apache/cordova/AndroidWebViewClient.java
+++ b/framework/src/org/apache/cordova/AndroidWebViewClient.java
@@@ -1,318 -1,0 +1,330 @@@
 +/*
 +       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 java.util.Hashtable;
 +
 +import org.json.JSONException;
 +import org.json.JSONObject;
 +
 +import android.annotation.TargetApi;
 +import android.content.pm.ApplicationInfo;
 +import android.content.pm.PackageManager;
 +import android.content.pm.PackageManager.NameNotFoundException;
 +import android.graphics.Bitmap;
 +import android.net.http.SslError;
 +import android.view.View;
 +import android.webkit.HttpAuthHandler;
 +import android.webkit.SslErrorHandler;
 +import android.webkit.WebView;
 +import android.webkit.WebViewClient;
 +
 +
 +/**
 + * This class is the WebViewClient that implements callbacks for our web view.
 + * The kind of callbacks that happen here are regarding the rendering of the
 + * document instead of the chrome surrounding it, such as onPageStarted(), 
 + * shouldOverrideUrlLoading(), etc. Related to but different than
 + * CordovaChromeClient.
 + *
 + * @see <a 
href="http://developer.android.com/reference/android/webkit/WebViewClient.html";>WebViewClient</a>
 + * @see <a 
href="http://developer.android.com/guide/webapps/webview.html";>WebView guide</a>
 + * @see CordovaChromeClient
 + * @see CordovaWebView
 + */
 +public class AndroidWebViewClient extends WebViewClient {
 +
 +    private static final String TAG = "AndroidWebViewClient";
 +    protected final CordovaInterface cordova;
 +    protected final AndroidWebView appView;
 +    protected final CordovaUriHelper helper;
 +    private boolean doClearHistory = false;
 +    boolean isCurrentlyLoading;
 +
 +    /** The authorization tokens. */
 +    private Hashtable<String, AuthenticationToken> authenticationTokens = new 
Hashtable<String, AuthenticationToken>();
 +
 +    public AndroidWebViewClient(CordovaInterface cordova, AndroidWebView 
view) {
 +        this.cordova = cordova;
 +        this.appView = view;
 +        helper = new CordovaUriHelper(cordova, view);
 +    }
 +
 +    /**
 +     * Give the host application a chance to take over the control when a new 
url
 +     * is about to be loaded in the current WebView.
 +     *
 +     * @param view          The WebView that is initiating the callback.
 +     * @param url           The url to be loaded.
 +     * @return              true to override, false for default behavior
 +     */
 +      @Override
 +    public boolean shouldOverrideUrlLoading(WebView view, String 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
 +     */
 +    @Override
 +    public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler 
handler, String host, String realm) {
 +
 +        // Get the authentication token
 +        AuthenticationToken token = this.getAuthenticationToken(host, realm);
 +        if (token != null) {
 +            handler.proceed(token.getUserName(), token.getPassword());
 +        }
 +        else {
 +            // Handle 401 like we'd normally do!
 +            super.onReceivedHttpAuthRequest(view, handler, host, realm);
 +        }
 +    }
 +
 +    /**
 +     * Notify the host application that a page has started loading.
 +     * This method is called once for each main frame load so a page with 
iframes or framesets will call onPageStarted
 +     * one time for the main frame. This also means that onPageStarted will 
not be called when the contents of an
 +     * embedded frame changes, i.e. clicking a link whose target is an iframe.
 +     *
 +     * @param view          The webview initiating the callback.
 +     * @param url           The url of the page.
 +     */
 +    @Override
 +    public void onPageStarted(WebView view, String url, Bitmap favicon) {
 +        super.onPageStarted(view, url, favicon);
 +        isCurrentlyLoading = true;
 +        LOG.d(TAG, "onPageStarted(" + url + ")");
 +        // Flush stale messages & reset plugins.
 +        this.appView.onPageReset();
 +
 +        // Broadcast message that page has loaded
 +        this.appView.getPluginManager().postMessage("onPageStarted", url);
 +    }
 +
 +    /**
 +     * Notify the host application that a page has finished loading.
 +     * This method is called only for main frame. When onPageFinished() is 
called, the rendering picture may not be updated yet.
 +     *
 +     *
 +     * @param view          The webview initiating the callback.
 +     * @param url           The url of the page.
 +     */
 +    @Override
 +    public void onPageFinished(WebView view, String url) {
 +        super.onPageFinished(view, url);
 +        // Ignore excessive calls.
 +        if (!isCurrentlyLoading) {
 +            return;
 +        }
 +        isCurrentlyLoading = false;
 +        LOG.d(TAG, "onPageFinished(" + url + ")");
 +
 +        /**
 +         * Because of a timing issue we need to clear this history in 
onPageFinished as well as
 +         * onPageStarted. However we only want to do this if the 
doClearHistory boolean is set to
 +         * true. You see when you load a url with a # in it which is common 
in jQuery applications
 +         * onPageStared is not called. Clearing the history at that point 
would break jQuery apps.
 +         */
 +        if (this.doClearHistory) {
 +            view.clearHistory();
 +            this.doClearHistory = false;
 +        }
 +
 +        // Clear timeout flag
 +        appView.loadUrlTimeout++;
 +
 +        // Broadcast message that page has loaded
 +        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) {
 +            Thread t = new Thread(new Runnable() {
 +                public void run() {
 +                    try {
 +                        Thread.sleep(2000);
 +                        cordova.getActivity().runOnUiThread(new Runnable() {
 +                            public void run() {
 +                                
appView.getPluginManager().postMessage("spinner", "stop");
 +                            }
 +                        });
 +                    } catch (InterruptedException e) {
 +                    }
 +                }
 +            });
 +            t.start();
 +        }
 +
 +        // Shutdown if blank loaded
 +        if (url.equals("about:blank")) {
 +            appView.getPluginManager().postMessage("exit", null);
 +        }
 +    }
 +
 +    /**
 +     * Report an error to the host application. These errors are 
unrecoverable (i.e. the main resource is unavailable).
 +     * The errorCode parameter corresponds to one of the ERROR_* constants.
 +     *
 +     * @param view          The WebView that is initiating the callback.
 +     * @param errorCode     The error code corresponding to an ERROR_* value.
 +     * @param description   A String describing the error.
 +     * @param failingUrl    The url that failed to load.
 +     */
 +    @Override
 +    public void onReceivedError(WebView view, int errorCode, String 
description, String failingUrl) {
 +        // Ignore error due to stopLoading().
 +        if (!isCurrentlyLoading) {
 +            return;
 +        }
 +        LOG.d(TAG, "CordovaWebViewClient.onReceivedError: Error code=%s 
Description=%s URL=%s", errorCode, description, failingUrl);
 +
 +        // Clear timeout flag
 +        appView.loadUrlTimeout++;
 +
-         // Handle error
++        // If this is a "Protocol Not Supported" error, then revert to the 
previous
++        // page. If there was no previous page, then punt. The application's 
config
++        // is likely incorrect (start page set to sms: or something like that)
++        if (errorCode == WebViewClient.ERROR_UNSUPPORTED_SCHEME) {
++            if (view.canGoBack()) {
++                view.goBack();
++                return;
++            } else {
++                super.onReceivedError(view, errorCode, description, 
failingUrl);
++            }
++        }
++
++        // Handle other errors by passing them to the webview in JS
 +        JSONObject data = new JSONObject();
 +        try {
 +            data.put("errorCode", errorCode);
 +            data.put("description", description);
 +            data.put("url", failingUrl);
 +        } catch (JSONException e) {
 +            e.printStackTrace();
 +        }
 +        this.appView.getPluginManager().postMessage("onReceivedError", data);
 +    }
 +
 +    /**
 +     * Notify the host application that an SSL error occurred while loading a 
resource.
 +     * The host application must call either handler.cancel() or 
handler.proceed().
 +     * Note that the decision may be retained for use in response to future 
SSL errors.
 +     * The default behavior is to cancel the load.
 +     *
 +     * @param view          The WebView that is initiating the callback.
 +     * @param handler       An SslErrorHandler object that will handle the 
user's response.
 +     * @param error         The SSL error object.
 +     */
 +    @TargetApi(8)
 +    @Override
 +    public void onReceivedSslError(WebView view, SslErrorHandler handler, 
SslError error) {
 +
 +        final String packageName = 
this.cordova.getActivity().getPackageName();
 +        final PackageManager pm = 
this.cordova.getActivity().getPackageManager();
 +
 +        ApplicationInfo appInfo;
 +        try {
 +            appInfo = pm.getApplicationInfo(packageName, 
PackageManager.GET_META_DATA);
 +            if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
 +                // debug = true
 +                handler.proceed();
 +                return;
 +            } else {
 +                // debug = false
 +                super.onReceivedSslError(view, handler, error);
 +            }
 +        } catch (NameNotFoundException e) {
 +            // When it doubt, lock it out!
 +            super.onReceivedSslError(view, handler, error);
 +        }
 +    }
 +
 +
 +    /**
 +     * Sets the authentication token.
 +     *
 +     * @param authenticationToken
 +     * @param host
 +     * @param realm
 +     */
 +    public void setAuthenticationToken(AuthenticationToken 
authenticationToken, String host, String realm) {
 +        if (host == null) {
 +            host = "";
 +        }
 +        if (realm == null) {
 +            realm = "";
 +        }
 +        this.authenticationTokens.put(host.concat(realm), 
authenticationToken);
 +    }
 +
 +    /**
 +     * Removes the authentication token.
 +     *
 +     * @param host
 +     * @param realm
 +     *
 +     * @return the authentication token or null if did not exist
 +     */
 +    public AuthenticationToken removeAuthenticationToken(String host, String 
realm) {
 +        return this.authenticationTokens.remove(host.concat(realm));
 +    }
 +
 +    /**
 +     * Gets the authentication token.
 +     *
 +     * In order it tries:
 +     * 1- host + realm
 +     * 2- host
 +     * 3- realm
 +     * 4- no host, no realm
 +     *
 +     * @param host
 +     * @param realm
 +     *
 +     * @return the authentication token
 +     */
 +    public AuthenticationToken getAuthenticationToken(String host, String 
realm) {
 +        AuthenticationToken token = null;
 +        token = this.authenticationTokens.get(host.concat(realm));
 +
 +        if (token == null) {
 +            // try with just the host
 +            token = this.authenticationTokens.get(host);
 +
 +            // Try the realm
 +            if (token == null) {
 +                token = this.authenticationTokens.get(realm);
 +            }
 +
 +            // if no host found, just query for default
 +            if (token == null) {
 +                token = this.authenticationTokens.get("");
 +            }
 +        }
 +
 +        return token;
 +    }
 +
 +    /**
 +     * Clear all authentication tokens.
 +     */
 +    public void clearAuthenticationTokens() {
 +        this.authenticationTokens.clear();
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/a7ccb924/framework/src/org/apache/cordova/CordovaActivity.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/a7ccb924/framework/src/org/apache/cordova/CordovaUriHelper.java
----------------------------------------------------------------------
diff --cc framework/src/org/apache/cordova/CordovaUriHelper.java
index 077e425,bb78592..f7d22da
--- a/framework/src/org/apache/cordova/CordovaUriHelper.java
+++ b/framework/src/org/apache/cordova/CordovaUriHelper.java
@@@ -19,10 -19,13 +19,13 @@@
  
  package org.apache.cordova;
  
+ import android.annotation.TargetApi;
  import android.content.Intent;
  import android.net.Uri;
+ import android.os.Build;
+ import android.webkit.WebView;
  
 -class CordovaUriHelper {
 +public class CordovaUriHelper {
      
      private static final String TAG = "CordovaUriHelper";
      
@@@ -43,7 -46,8 +46,8 @@@
       * @param url           The url to be loaded.
       * @return              true to override, false for default behavior
       */
+     @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
 -    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:"))
          {

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/a7ccb924/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/a7ccb924/test/assets/www/error.html
----------------------------------------------------------------------
diff --cc test/assets/www/error.html
index 0000000,0000000..aad167d
new file mode 100644
--- /dev/null
+++ b/test/assets/www/error.html
@@@ -1,0 -1,0 +1,8 @@@
++<html>
++    <head>
++        <title>OH NOES!</title>
++    </head>
++    <body>
++        <h1>Things went terribly wrong!</h1>
++    </body>
++</html>

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/a7ccb924/test/src/org/apache/cordova/test/CordovaWebViewTestActivity.java
----------------------------------------------------------------------
diff --cc test/src/org/apache/cordova/test/CordovaWebViewTestActivity.java
index 6f96e83,1c1789e..b143521
--- a/test/src/org/apache/cordova/test/CordovaWebViewTestActivity.java
+++ b/test/src/org/apache/cordova/test/CordovaWebViewTestActivity.java
@@@ -22,7 -22,8 +22,9 @@@ package org.apache.cordova.test
  import java.util.concurrent.ExecutorService;
  import java.util.concurrent.Executors;
  
++import org.apache.cordova.AndroidChromeClient;
++import org.apache.cordova.AndroidWebViewClient;
  import org.apache.cordova.Config;
 -import org.apache.cordova.CordovaChromeClient;
  import org.apache.cordova.CordovaWebView;
  import org.apache.cordova.CordovaInterface;
  import org.apache.cordova.CordovaPlugin;
@@@ -45,10 -47,12 +47,11 @@@ public class CordovaWebViewTestActivit
  
          setContentView(R.layout.main);
  
-         cordovaWebView = (CordovaWebView) findViewById(R.id.cordovaWebView);
+         //CB-7238: This has to be added now, because it got removed from 
somewhere else
          Config.init(this);
-         cordovaWebView.init(this,
-                 Config.getPluginEntries(), Config.getWhitelist(), 
Config.getPreferences());
+         
+         cordovaWebView = (CordovaWebView) findViewById(R.id.cordovaWebView);
 -        cordovaWebView.init(this, new CordovaWebViewClient(this, 
cordovaWebView), new CordovaChromeClient(this, cordovaWebView),
 -                Config.getPluginEntries(), Config.getWhitelist(), 
Config.getPreferences());
++        cordovaWebView.init(this, Config.getPluginEntries(), 
Config.getWhitelist(), Config.getPreferences());
  
          cordovaWebView.loadUrl("file:///android_asset/www/index.html");
  

Reply via email to