Provides ability to store HTTP authentication credentials supplied to an XHR from JavaScript

This change forwards to the WebViewClient HTTP authentication credentials that
are supplied to an XHR from JavaScript. This allows the client to store these
credentials for use with later requests.

Currently, the browser only stores credentials that have been entered manually
by the user through the authentication dialog.

Bug: 2544330
Change-Id: I913e35d80b7ad41ff75586092408b86ea9f543d8
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 1eb3fa4..92ce4f0 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -111,6 +111,7 @@
     private static final int OPEN_FILE_CHOOSER                   = 134;
     private static final int ADD_HISTORY_ITEM                    = 135;
     private static final int HISTORY_INDEX_CHANGED               = 136;
+    private static final int AUTH_CREDENTIALS                    = 137;
 
     // Message triggered by the client to resume execution
     private static final int NOTIFY                              = 200;
@@ -734,6 +735,16 @@
                             (WebHistoryItem) msg.obj, msg.arg1);
                 }
                 break;
+            case AUTH_CREDENTIALS:
+                if (mWebViewClient != null) {
+                    String host = msg.getData().getString("host");
+                    String realm = msg.getData().getString("realm");
+                    username = msg.getData().getString("username");
+                    password = msg.getData().getString("password");
+                    mWebViewClient.onReceivedHttpAuthCredentials(
+                            mWebView, host, realm, username, password);
+                }
+                break;
         }
     }
 
@@ -917,6 +928,20 @@
         msg.getData().putString("realm", realmName);
         sendMessage(msg);
     }
+
+    public void onReceivedHttpAuthCredentials(String host, String realm,
+            String username, String password) {
+        if (mWebViewClient == null) {
+            return;
+        }
+        Message msg = obtainMessage(AUTH_CREDENTIALS);
+        msg.getData().putString("host", host);
+        msg.getData().putString("realm", realm);
+        msg.getData().putString("username", username);
+        msg.getData().putString("password", password);
+        sendMessage(msg);
+    }
+
     /**
      * @hide - hide this because it contains a parameter of type SslError.
      * SslError is located in a hidden package.
diff --git a/core/java/android/webkit/HttpAuthHandler.java b/core/java/android/webkit/HttpAuthHandler.java
index 6216603..6a8d88d 100644
--- a/core/java/android/webkit/HttpAuthHandler.java
+++ b/core/java/android/webkit/HttpAuthHandler.java
@@ -267,4 +267,14 @@
             proxy.onReceivedHttpAuthRequest(this, hostname, realm);
         }
     }
+
+    /**
+     * Informs the proxy of a new set of credentials.
+     * @hide Pending API council review
+     */
+    public static void onReceivedCredentials(LoadListener loader,
+            String host, String realm, String username, String password) {
+        CallbackProxy proxy = loader.getFrame().getCallbackProxy();
+        proxy.onReceivedHttpAuthCredentials(host, realm, username, password);
+    }
 }
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index 44f5d2b..1dfadde 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -663,6 +663,11 @@
                     // If this is the first attempt to authenticate, try again with the username and
                     // password supplied in the URL, if present.
                     if (!mAuthFailed && mUsername != null && mPassword != null) {
+                        String host = mAuthHeader.isProxy() ?
+                                Network.getInstance(mContext).getProxyHostname() :
+                                mUri.mHost;
+                        HttpAuthHandler.onReceivedCredentials(this, host,
+                                mAuthHeader.getRealm(), mUsername, mPassword);
                         makeAuthResponse(mUsername, mPassword);
                     } else {
                         Network.getInstance(mContext).handleAuthRequest(this);
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 02c7210..4ac660e 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -197,6 +197,22 @@
     }
 
     /**
+     * Notify the host application that authentication credentials have been
+     * supplied from Script.
+     * The default behavior is to do nothing.
+     * @hide Pending API council review
+     *
+     * @param view The WebView that is initiating the callback.
+     * @param host The host requiring authentication.
+     * @param realm A description to help store user credentials for future
+     * @param username The username
+     * @param password The password
+     */
+    public void onReceivedHttpAuthCredentials(WebView view, String host,
+            String realm, String username, String password) {
+    }
+
+    /**
      * Give the host application a chance to handle the key event synchronously.
      * e.g. menu shortcut key events need to be filtered this way. If return
      * true, WebView will not handle the key event. If return false, WebView