Integrate unsubmitted cupcake change 149424:
	   CTS: add test cases for android.webkit.WebChromeClient and WebViewClient

Change-Id: Ibcb44e264cb25272874f9aff1083e15abc123ff4
diff --git a/tests/assets/webkit/jsalert.html b/tests/assets/webkit/jsalert.html
new file mode 100644
index 0000000..c4b35fa
--- /dev/null
+++ b/tests/assets/webkit/jsalert.html
@@ -0,0 +1,29 @@
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed 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.
+-->
+
+<html>
+    <head>
+        <title>javascript alert</title>
+    </head>
+    <script type="text/javascript">
+        function fireAlert() {
+            alert("testOnJsAlert");
+        }
+    </script>
+    <body onload="fireAlert()">
+        javascript alert test
+    </body>
+</html>
+
diff --git a/tests/assets/webkit/jsconfirm.html b/tests/assets/webkit/jsconfirm.html
new file mode 100644
index 0000000..720c5de
--- /dev/null
+++ b/tests/assets/webkit/jsconfirm.html
@@ -0,0 +1,34 @@
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed 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.
+-->
+
+<html>
+    <head>
+        <title>javascript confirm</title>
+    </head>
+    <script type="text/javascript">
+        function fireConfirm() {
+            var res = confirm("testOnJsConfirm");
+            if (res == true) {
+                document.title = "OK";
+            } else {
+                document.title = "Cancel";
+            }
+        }
+    </script>
+    <body onload="fireConfirm()">
+        javascript confirm test
+    </body>
+</html>
+
diff --git a/tests/assets/webkit/jsform.html b/tests/assets/webkit/jsform.html
new file mode 100644
index 0000000..ddf01f8
--- /dev/null
+++ b/tests/assets/webkit/jsform.html
@@ -0,0 +1,34 @@
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed 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.
+-->
+
+<html>
+    <head>
+        <title>javascript form</title>
+    </head>
+    <script type="text/javascript">
+        function fireSubmit() {
+            if (location.hash == "") {
+                document.getElementById("formId").submit();
+            }
+        }
+    </script>
+    <body onload="fireSubmit()">
+        javascript form test
+        <form id="formId" action="test.html#result" method="post">
+            <input type="hidden" name="foo" value="bar" />
+        </form>
+    </body>
+</html>
+
diff --git a/tests/assets/webkit/jsprompt.html b/tests/assets/webkit/jsprompt.html
new file mode 100644
index 0000000..a6b7d57
--- /dev/null
+++ b/tests/assets/webkit/jsprompt.html
@@ -0,0 +1,31 @@
+
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed 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.
+-->
+
+<html>
+    <head>
+        <title>javascript prompt</title>
+    </head>
+    <script type="text/javascript">
+        function firePrompt() {
+            var res = prompt("testOnJsPrompt");
+            document.title = res;
+        }
+    </script>
+    <body onload="firePrompt()">
+        javascript prompt test
+    </body>
+</html>
+
diff --git a/tests/assets/webkit/jsunload.html b/tests/assets/webkit/jsunload.html
new file mode 100644
index 0000000..fb0673e
--- /dev/null
+++ b/tests/assets/webkit/jsunload.html
@@ -0,0 +1,30 @@
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed 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.
+-->
+
+<html>
+    <head>
+        <title>javascript unload</title>
+    </head>
+    <script type="text/javascript">
+        function fireUnload() {
+            return "testOnJsBeforeUnload";
+        }
+        window.onbeforeunload = fireUnload;
+    </script>
+    <body>
+        javascript unload test
+    </body>
+</html>
+
diff --git a/tests/assets/webkit/jswindow.html b/tests/assets/webkit/jswindow.html
new file mode 100644
index 0000000..bc723f7
--- /dev/null
+++ b/tests/assets/webkit/jswindow.html
@@ -0,0 +1,33 @@
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed 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.
+-->
+
+<html>
+    <head>
+        <title>javascript window</title>
+    </head>
+    <script type="text/javascript">
+        function fireOpen() {
+            childWindow = window.open();
+            childWindow.document.title = "javascript child window";
+            childWindow.document.write("javascript child window");
+            childWindow.focus();
+            setTimeout("childWindow.close()", 2000);
+        }
+    </script>
+    <body onload="fireOpen()">
+        javascript window test
+    </body>
+</html>
+
diff --git a/tests/src/android/webkit/cts/CtsTestServer.java b/tests/src/android/webkit/cts/CtsTestServer.java
index a45589d..9ec7ee6 100644
--- a/tests/src/android/webkit/cts/CtsTestServer.java
+++ b/tests/src/android/webkit/cts/CtsTestServer.java
@@ -25,7 +25,6 @@
 import org.apache.http.NameValuePair;
 import org.apache.http.RequestLine;
 import org.apache.http.StatusLine;
-import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.utils.URLEncodedUtils;
 import org.apache.http.entity.ByteArrayEntity;
 import org.apache.http.entity.InputStreamEntity;
@@ -207,8 +206,21 @@
      * @param path The path of the asset. See {@link AssetManager#open(String)}
      */
     public String getRedirectingAssetUrl(String path) {
+        return getRedirectingAssetUrl(path, 1);
+    }
+
+    /**
+     * Return an absolute URL that indirectly refers to the given asset.
+     * When a client fetches this URL, the server will respond with a temporary redirect (302)
+     * referring to the absolute URL of the given asset.
+     * @param path The path of the asset. See {@link AssetManager#open(String)}
+     * @param numRedirects The number of redirects required to reach the given asset.
+     */
+    public String getRedirectingAssetUrl(String path, int numRedirects) {
         StringBuilder sb = new StringBuilder(getBaseUri());
-        sb.append(REDIRECT_PREFIX);
+        for (int i = 0; i < numRedirects; i++) {
+            sb.append(REDIRECT_PREFIX);
+        }
         sb.append(ASSET_PREFIX);
         sb.append(path);
         return sb.toString();
@@ -271,126 +283,124 @@
         RequestLine requestLine = request.getRequestLine();
         HttpResponse response = null;
         mRequestCount += 1;
-        if (requestLine.getMethod().equals(HttpGet.METHOD_NAME)) {
-            Log.i(TAG, "GET: " + requestLine.getUri());
-            String uriString = requestLine.getUri();
-            mLastQuery = uriString;
-            URI uri = URI.create(uriString);
-            String path = uri.getPath();
-            if (path.equals(FAVICON_PATH)) {
-                path = FAVICON_ASSET_PATH;
+        Log.i(TAG, requestLine.getMethod() + ": " + requestLine.getUri());
+        String uriString = requestLine.getUri();
+        mLastQuery = uriString;
+        URI uri = URI.create(uriString);
+        String path = uri.getPath();
+        if (path.equals(FAVICON_PATH)) {
+            path = FAVICON_ASSET_PATH;
+        }
+        if (path.startsWith(DELAY_PREFIX)) {
+            try {
+                Thread.sleep(DELAY_MILLIS);
+            } catch (InterruptedException ignored) {
+                // ignore
             }
-            if (path.startsWith(DELAY_PREFIX)) {
-                try {
-                    Thread.sleep(DELAY_MILLIS);
-                } catch (InterruptedException ignored) {
-                    // ignore
-                }
-                path = path.substring(DELAY_PREFIX.length());
-            }
-            if (path.startsWith(AUTH_PREFIX)) {
-                // authentication required
-                Header[] auth = request.getHeaders("Authorization");
-                if (auth.length > 0) {
-                    if (auth[0].getValue().equals(AUTH_CREDENTIALS)) {
-                        // fall through and serve content
-                        path = path.substring(AUTH_PREFIX.length());
-                    } else {
-                        // incorrect password
-                        response = createResponse(HttpStatus.SC_FORBIDDEN);
-                    }
+            path = path.substring(DELAY_PREFIX.length());
+        }
+        if (path.startsWith(AUTH_PREFIX)) {
+            // authentication required
+            Header[] auth = request.getHeaders("Authorization");
+            if (auth.length > 0) {
+                if (auth[0].getValue().equals(AUTH_CREDENTIALS)) {
+                    // fall through and serve content
+                    path = path.substring(AUTH_PREFIX.length());
                 } else {
-                    // request authorization
-                    response = createResponse(HttpStatus.SC_UNAUTHORIZED);
-                    response.addHeader("WWW-Authenticate", "Basic realm=\"" + AUTH_REALM + "\"");
+                    // incorrect password
+                    response = createResponse(HttpStatus.SC_FORBIDDEN);
                 }
+            } else {
+                // request authorization
+                response = createResponse(HttpStatus.SC_UNAUTHORIZED);
+                response.addHeader("WWW-Authenticate", "Basic realm=\"" + AUTH_REALM + "\"");
             }
-            if (path.startsWith(BINARY_PREFIX)) {
-                List <NameValuePair> args = URLEncodedUtils.parse(uri, "UTF-8");
-                int length = 0;
-                String mimeType = null;
-                try {
-                    for (NameValuePair pair : args) {
-                        String name = pair.getName();
-                        if (name.equals("type")) {
-                            mimeType = pair.getValue();
-                        } else if (name.equals("length")) {
-                            length = Integer.parseInt(pair.getValue());
-                        }
+        }
+        if (path.startsWith(BINARY_PREFIX)) {
+            List <NameValuePair> args = URLEncodedUtils.parse(uri, "UTF-8");
+            int length = 0;
+            String mimeType = null;
+            try {
+                for (NameValuePair pair : args) {
+                    String name = pair.getName();
+                    if (name.equals("type")) {
+                        mimeType = pair.getValue();
+                    } else if (name.equals("length")) {
+                        length = Integer.parseInt(pair.getValue());
                     }
-                    if (length > 0 && mimeType != null) {
-                        ByteArrayEntity entity = new ByteArrayEntity(new byte[length]);
-                        entity.setContentType(mimeType);
-                        response = createResponse(HttpStatus.SC_OK);
-                        response.setEntity(entity);
-                        response.addHeader("Content-Disposition", "attachment; filename=test.bin");
-                    } else {
-                        // fall through, return 404 at the end
-                    }
-                } catch (Exception e) {
-                    // fall through, return 404 at the end
-                    Log.w(TAG, e);
                 }
-            } else if (path.startsWith(ASSET_PREFIX)) {
-                path = path.substring(ASSET_PREFIX.length());
-                // request for an asset file
-                try {
-                    InputStream in = mAssets.open(path);
-                    response = createResponse(HttpStatus.SC_OK);
-                    InputStreamEntity entity = new InputStreamEntity(in, in.available());
-                    String mimeType =
-                        mMap.getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(path));
-                    if (mimeType == null) {
-                        mimeType = "text/html";
-                    }
+                if (length > 0 && mimeType != null) {
+                    ByteArrayEntity entity = new ByteArrayEntity(new byte[length]);
                     entity.setContentType(mimeType);
+                    response = createResponse(HttpStatus.SC_OK);
                     response.setEntity(entity);
-                } catch (IOException e) {
-                    response = null;
+                    response.addHeader("Content-Disposition", "attachment; filename=test.bin");
+                } else {
                     // fall through, return 404 at the end
                 }
-            } else if (path.startsWith(REDIRECT_PREFIX)) {
-                response = createResponse(HttpStatus.SC_MOVED_TEMPORARILY);
-                String location = getBaseUri() + path.substring(REDIRECT_PREFIX.length());
-                Log.i(TAG, "Redirecting to: " + location);
-                response.addHeader("Location", location);
-            } else if (path.startsWith(COOKIE_PREFIX)) {
-                /*
-                 * Return a page with a title containing a list of all incoming cookies,
-                 * separated by '|' characters. If a numeric 'count' value is passed in a cookie,
-                 * return a cookie with the value incremented by 1. Otherwise, return a cookie
-                 * setting 'count' to 0.
-                 */
-                response = createResponse(HttpStatus.SC_OK);
-                Header[] cookies = request.getHeaders("Cookie");
-                Pattern p = Pattern.compile("count=(\\d+)");
-                StringBuilder cookieString = new StringBuilder(100);
-                int count = 0;
-                for (Header cookie : cookies) {
-                    String value = cookie.getValue();
-                    if (cookieString.length() > 0) {
-                        cookieString.append("|");
-                    }
-                    cookieString.append(value);
-                    Matcher m = p.matcher(value);
-                    if (m.find()) {
-                        count = Integer.parseInt(m.group(1)) + 1;
-                    }
-                }
-
-                response.addHeader("Set-Cookie", "count=" + count + "; path=" + COOKIE_PREFIX);
-                response.setEntity(createEntity("<html><head><title>" + cookieString +
-                        "</title></head><body>" + cookieString + "</body></html>"));
-            } else if (path.equals(USERAGENT_PATH)) {
-                response = createResponse(HttpStatus.SC_OK);
-                Header agentHeader = request.getFirstHeader("User-Agent");
-                String agent = "";
-                if (agentHeader != null) {
-                    agent = agentHeader.getValue();
-                }
-                response.setEntity(createEntity("<html><head><title>" + agent + "</title></head>" +
-                        "<body>" + agent + "</body></html>"));
+            } catch (Exception e) {
+                // fall through, return 404 at the end
+                Log.w(TAG, e);
             }
+        } else if (path.startsWith(ASSET_PREFIX)) {
+            path = path.substring(ASSET_PREFIX.length());
+            // request for an asset file
+            try {
+                InputStream in = mAssets.open(path);
+                response = createResponse(HttpStatus.SC_OK);
+                InputStreamEntity entity = new InputStreamEntity(in, in.available());
+                String mimeType =
+                    mMap.getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(path));
+                if (mimeType == null) {
+                    mimeType = "text/html";
+                }
+                entity.setContentType(mimeType);
+                response.setEntity(entity);
+            } catch (IOException e) {
+                response = null;
+                // fall through, return 404 at the end
+            }
+        } else if (path.startsWith(REDIRECT_PREFIX)) {
+            response = createResponse(HttpStatus.SC_MOVED_TEMPORARILY);
+            String location = getBaseUri() + path.substring(REDIRECT_PREFIX.length());
+            Log.i(TAG, "Redirecting to: " + location);
+            response.addHeader("Location", location);
+        } else if (path.startsWith(COOKIE_PREFIX)) {
+            /*
+             * Return a page with a title containing a list of all incoming cookies,
+             * separated by '|' characters. If a numeric 'count' value is passed in a cookie,
+             * return a cookie with the value incremented by 1. Otherwise, return a cookie
+             * setting 'count' to 0.
+             */
+            response = createResponse(HttpStatus.SC_OK);
+            Header[] cookies = request.getHeaders("Cookie");
+            Pattern p = Pattern.compile("count=(\\d+)");
+            StringBuilder cookieString = new StringBuilder(100);
+            int count = 0;
+            for (Header cookie : cookies) {
+                String value = cookie.getValue();
+                if (cookieString.length() > 0) {
+                    cookieString.append("|");
+                }
+                cookieString.append(value);
+                Matcher m = p.matcher(value);
+                if (m.find()) {
+                    count = Integer.parseInt(m.group(1)) + 1;
+                }
+            }
+
+            response.addHeader("Set-Cookie", "count=" + count + "; path=" + COOKIE_PREFIX);
+            response.setEntity(createEntity("<html><head><title>" + cookieString +
+                    "</title></head><body>" + cookieString + "</body></html>"));
+        } else if (path.equals(USERAGENT_PATH)) {
+            response = createResponse(HttpStatus.SC_OK);
+            Header agentHeader = request.getFirstHeader("User-Agent");
+            String agent = "";
+            if (agentHeader != null) {
+                agent = agentHeader.getValue();
+            }
+            response.setEntity(createEntity("<html><head><title>" + agent + "</title></head>" +
+                    "<body>" + agent + "</body></html>"));
         }
         if (response == null) {
             response = createResponse(HttpStatus.SC_NOT_FOUND);
diff --git a/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java b/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java
index cc2939b..b2bdfc8 100644
--- a/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java
+++ b/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java
@@ -34,6 +34,13 @@
     public static final String EMBEDDED_IMG_URL = "webkit/embedded_image.html";
     public static final String POPUP_URL = "webkit/popup_base.html";
     public static final String JAVASCRIPT_URL = "webkit/javascript.html";
+    public static final String JS_ALERT_URL = "webkit/jsalert.html";
+    public static final String JS_CONFIRM_URL = "webkit/jsconfirm.html";
+    public static final String JS_PROMPT_URL = "webkit/jsprompt.html";
+    public static final String JS_UNLOAD_URL = "webkit/jsunload.html";
+    public static final String JS_WINDOW_URL = "webkit/jswindow.html";
+    public static final String JS_TIMEOUT_URL = "webkit/jstimeout.html";
+    public static final String JS_FORM_URL = "webkit/jsform.html";
 
     public static final String FONT_URL = "webkit/fonts.html";
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
new file mode 100644
index 0000000..7c1f850
--- /dev/null
+++ b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
@@ -0,0 +1,470 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed 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 android.webkit.cts;
+
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+
+import android.graphics.Bitmap;
+import android.os.Message;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.animation.cts.DelayedCheck;
+import android.webkit.JsPromptResult;
+import android.webkit.JsResult;
+import android.webkit.WebChromeClient;
+import android.webkit.WebIconDatabase;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+
+@TestTargetClass(android.webkit.WebChromeClient.class)
+public class WebChromeClientTest extends ActivityInstrumentationTestCase2<WebViewStubActivity> {
+    private static final long TEST_TIMEOUT = 5000L;
+
+    private WebView mWebView;
+    private CtsTestServer mWebServer;
+    private WebIconDatabase mIconDb;
+
+    public WebChromeClientTest() {
+        super("com.android.cts.stub", WebViewStubActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mWebView = getActivity().getWebView();
+        mWebServer = new CtsTestServer(getActivity());
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mWebView.clearHistory();
+        mWebView.clearCache(true);
+        if (mWebServer != null) {
+            mWebServer.shutdown();
+        }
+        if (mIconDb != null) {
+            mIconDb.removeAllIcons();
+            mIconDb.close();
+        }
+        super.tearDown();
+    }
+
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "onProgressChanged",
+            args = {WebView.class, int.class}
+        )
+    })
+    public void testOnProgressChanged() throws InterruptedException {
+        final MockWebChromeClient webChromeClient = new MockWebChromeClient();
+        mWebView.setWebChromeClient(webChromeClient);
+
+        assertFalse(webChromeClient.hadOnProgressChanged());
+        mWebView.loadUrl(TestHtmlConstants.HELLO_WORLD_URL);
+
+        new DelayedCheck(TEST_TIMEOUT) {
+            @Override
+            protected boolean check() {
+                return webChromeClient.hadOnProgressChanged();
+            }
+        }.run();
+    }
+
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "onReceivedTitle",
+            args = {WebView.class, String.class}
+        )
+    })
+    public void testOnReceivedTitle() throws Exception {
+        final MockWebChromeClient webChromeClient = new MockWebChromeClient();
+        mWebView.setWebChromeClient(webChromeClient);
+
+        assertFalse(webChromeClient.hadOnReceivedTitle());
+        String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+        mWebView.loadUrl(url);
+
+        new DelayedCheck(TEST_TIMEOUT) {
+            @Override
+            protected boolean check() {
+                return webChromeClient.hadOnReceivedTitle();
+            }
+        }.run();
+        assertTrue(webChromeClient.hadOnReceivedTitle());
+        assertEquals(TestHtmlConstants.HELLO_WORLD_TITLE, webChromeClient.getPageTitle());
+    }
+
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "onReceivedIcon",
+            args = {WebView.class, Bitmap.class}
+        )
+    })
+    public void testOnReceivedIcon() {
+        final MockWebChromeClient webChromeClient = new MockWebChromeClient();
+        mWebView.setWebChromeClient(webChromeClient);
+
+        WebIconDatabase mIconDb = WebIconDatabase.getInstance();
+        String dbPath = getActivity().getFilesDir().toString() + "/icons";
+        mIconDb.open(dbPath);
+        mIconDb.removeAllIcons();
+
+        assertFalse(webChromeClient.hadOnReceivedIcon());
+
+        String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+        mWebView.loadUrl(url);
+
+        new DelayedCheck(TEST_TIMEOUT) {
+            @Override
+            protected boolean check() {
+                return webChromeClient.hadOnReceivedIcon();
+            }
+        }.run();
+    }
+
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "onCreateWindow",
+            args = {WebView.class, boolean.class, boolean.class, Message.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "onRequestFocus",
+            args = {WebView.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "onCloseWindow",
+            args = {WebView.class}
+        )
+    })
+    public void testWindows() throws Exception {
+        final MockWebChromeClient webChromeClient = new MockWebChromeClient();
+        mWebView.setWebChromeClient(webChromeClient);
+
+        final WebSettings settings = mWebView.getSettings();
+        settings.setJavaScriptEnabled(true);
+        settings.setJavaScriptCanOpenWindowsAutomatically(true);
+        settings.setSupportMultipleWindows(true);
+
+        assertFalse(webChromeClient.hadOnCreateWindow());
+
+        // load a page that opens a child window, requests focus for the child and sets a timeout
+        // after which the child will be closed
+        loadUrl(mWebServer.getAssetUrl(TestHtmlConstants.JS_WINDOW_URL));
+
+        new DelayedCheck(TEST_TIMEOUT) {
+            @Override
+            protected boolean check() {
+                return webChromeClient.hadOnCreateWindow();
+            }
+        }.run();
+        assertTrue(webChromeClient.hadOnRequestFocus());
+        new DelayedCheck(TEST_TIMEOUT) {
+            @Override
+            protected boolean check() {
+                return webChromeClient.hadOnCloseWindow();
+            }
+        }.run();
+    }
+
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "onJsBeforeUnload",
+            args = {WebView.class, String.class, String.class, JsResult.class}
+        )
+    })
+    public void testOnJsBeforeUnload() throws Exception {
+        final MockWebChromeClient webChromeClient = new MockWebChromeClient();
+        mWebView.setWebChromeClient(webChromeClient);
+
+        final WebSettings settings = mWebView.getSettings();
+        settings.setJavaScriptEnabled(true);
+        settings.setJavaScriptCanOpenWindowsAutomatically(true);
+
+        assertFalse(webChromeClient.hadOnJsBeforeUnload());
+
+        loadUrl(mWebServer.getAssetUrl(TestHtmlConstants.JS_UNLOAD_URL));
+        // unload should trigger when we try to navigate away
+        loadUrl(mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL));
+
+        new DelayedCheck(TEST_TIMEOUT) {
+            @Override
+            protected boolean check() {
+                return webChromeClient.hadOnJsBeforeUnload();
+            }
+        }.run();
+        assertEquals(webChromeClient.getMessage(), "testOnJsBeforeUnload");
+    }
+
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "onJsAlert",
+            args = {WebView.class, String.class, String.class, JsResult.class}
+        )
+    })
+    public void testOnJsAlert() throws Exception {
+        final MockWebChromeClient webChromeClient = new MockWebChromeClient();
+        mWebView.setWebChromeClient(webChromeClient);
+
+        final WebSettings settings = mWebView.getSettings();
+        settings.setJavaScriptEnabled(true);
+        settings.setJavaScriptCanOpenWindowsAutomatically(true);
+
+        assertFalse(webChromeClient.hadOnJsAlert());
+
+        String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_ALERT_URL);
+        mWebView.loadUrl(url);
+
+        new DelayedCheck(TEST_TIMEOUT) {
+            @Override
+            protected boolean check() {
+                return webChromeClient.hadOnJsAlert();
+            }
+        }.run();
+        assertEquals(webChromeClient.getMessage(), "testOnJsAlert");
+    }
+
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "onJsConfirm",
+            args = {WebView.class, String.class, String.class, JsResult.class}
+        )
+    })
+    public void testOnJsConfirm() throws Exception {
+        final MockWebChromeClient webChromeClient = new MockWebChromeClient();
+        mWebView.setWebChromeClient(webChromeClient);
+
+        final WebSettings settings = mWebView.getSettings();
+        settings.setJavaScriptEnabled(true);
+        settings.setJavaScriptCanOpenWindowsAutomatically(true);
+
+        assertFalse(webChromeClient.hadOnJsConfirm());
+
+        String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_CONFIRM_URL);
+        mWebView.loadUrl(url);
+
+        new DelayedCheck(TEST_TIMEOUT) {
+            @Override
+            protected boolean check() {
+                return webChromeClient.hadOnJsConfirm();
+            }
+        }.run();
+        assertEquals(webChromeClient.getMessage(), "testOnJsConfirm");
+    }
+
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "onJsPrompt",
+            args = {WebView.class, String.class, String.class, String.class, JsPromptResult.class}
+        )
+    })
+    public void testOnJsPrompt() throws Exception {
+        final MockWebChromeClient webChromeClient = new MockWebChromeClient();
+        mWebView.setWebChromeClient(webChromeClient);
+
+        final WebSettings settings = mWebView.getSettings();
+        settings.setJavaScriptEnabled(true);
+        settings.setJavaScriptCanOpenWindowsAutomatically(true);
+
+        assertFalse(webChromeClient.hadOnJsPrompt());
+
+        final String promptResult = "CTS";
+        webChromeClient.setPromptResult(promptResult);
+        String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_PROMPT_URL);
+        mWebView.loadUrl(url);
+
+        new DelayedCheck(TEST_TIMEOUT) {
+            @Override
+            protected boolean check() {
+                return webChromeClient.hadOnJsPrompt();
+            }
+        }.run();
+        // the result returned by the client gets set as the page title
+        new DelayedCheck(TEST_TIMEOUT) {
+            protected boolean check() {
+                return mWebView.getTitle().equals(promptResult);
+            }
+        }.run();
+        assertEquals(webChromeClient.getMessage(), "testOnJsPrompt");
+    }
+
+    private void loadUrl(String url) {
+        mWebView.loadUrl(url);
+        new DelayedCheck(TEST_TIMEOUT) {
+            protected boolean check() {
+                return mWebView.getProgress() == 100;
+            }
+        }.run();
+    }
+
+    private class MockWebChromeClient extends WebChromeClient {
+        private boolean mHadOnProgressChanged;
+        private boolean mHadOnReceivedTitle;
+        private String mPageTitle;
+        private boolean mHadOnJsAlert;
+        private boolean mHadOnJsConfirm;
+        private boolean mHadOnJsPrompt;
+        private boolean mHadOnJsBeforeUnload;
+        private String mMessage;
+        private String mPromptResult;
+        private boolean mHadOnCloseWindow;
+        private boolean mHadOnCreateWindow;
+        private boolean mHadOnRequestFocus;
+        private boolean mHadOnReceivedIcon;
+
+        public void setPromptResult(String promptResult) {
+            mPromptResult = promptResult;
+        }
+
+        public boolean hadOnProgressChanged() {
+            return mHadOnProgressChanged;
+        }
+
+        public boolean hadOnReceivedTitle() {
+            return mHadOnReceivedTitle;
+        }
+
+        public String getPageTitle() {
+            return mPageTitle;
+        }
+
+        public boolean hadOnJsAlert() {
+            return mHadOnJsAlert;
+        }
+
+        public boolean hadOnJsConfirm() {
+            return mHadOnJsConfirm;
+        }
+
+        public boolean hadOnJsPrompt() {
+            return mHadOnJsPrompt;
+        }
+
+        public boolean hadOnJsBeforeUnload() {
+            return mHadOnJsBeforeUnload;
+        }
+
+        public boolean hadOnCreateWindow() {
+            return mHadOnCreateWindow;
+        }
+
+        public boolean hadOnCloseWindow() {
+            return mHadOnCloseWindow;
+        }
+
+        public boolean hadOnRequestFocus() {
+            return mHadOnRequestFocus;
+        }
+
+        public boolean hadOnReceivedIcon() {
+            return mHadOnReceivedIcon;
+        }
+
+        public String getMessage() {
+            return mMessage;
+        }
+
+        @Override
+        public void onProgressChanged(WebView view, int newProgress) {
+            super.onProgressChanged(view, newProgress);
+            mHadOnProgressChanged = true;
+        }
+
+        @Override
+        public void onReceivedTitle(WebView view, String title) {
+            super.onReceivedTitle(view, title);
+            mPageTitle = title;
+            mHadOnReceivedTitle = true;
+        }
+
+        @Override
+        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
+            super.onJsAlert(view, url, message, result);
+            mHadOnJsAlert = true;
+            mMessage = message;
+            result.confirm();
+            return true;
+        }
+
+        @Override
+        public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
+            super.onJsConfirm(view, url, message, result);
+            mHadOnJsConfirm = true;
+            mMessage = message;
+            result.confirm();
+            return true;
+        }
+
+        @Override
+        public boolean onJsPrompt(WebView view, String url, String message,
+                String defaultValue, JsPromptResult result) {
+            super.onJsPrompt(view, url, message, defaultValue, result);
+            mHadOnJsPrompt = true;
+            mMessage = message;
+            result.confirm(mPromptResult);
+            return true;
+        }
+
+        @Override
+        public boolean onJsBeforeUnload(WebView view, String url, String message, JsResult result) {
+            super.onJsBeforeUnload(view, url, message, result);
+            mHadOnJsBeforeUnload = true;
+            mMessage = message;
+            result.confirm();
+            return true;
+        }
+
+        @Override
+        public void onCloseWindow(WebView window) {
+            super.onCloseWindow(window);
+            mHadOnCloseWindow = true;
+        }
+
+        @Override
+        public boolean onCreateWindow(WebView view, boolean dialog, boolean userGesture,
+                Message resultMsg) {
+            WebView childView = new WebView(getActivity());
+            childView.setWebChromeClient(this);
+            WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
+            transport.setWebView(childView);
+            resultMsg.sendToTarget();
+            mHadOnCreateWindow = true;
+            return true;
+        }
+
+        @Override
+        public void onRequestFocus(WebView view) {
+            mHadOnRequestFocus = true;
+        }
+
+        @Override
+        public void onReceivedIcon(WebView view, Bitmap icon) {
+            mHadOnReceivedIcon = true;
+        }
+    }
+}
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
new file mode 100644
index 0000000..dffec7e
--- /dev/null
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed 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 android.webkit.cts;
+
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.ToBeFixed;
+
+import android.graphics.Bitmap;
+import android.os.Message;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.KeyEvent;
+import android.view.animation.cts.DelayedCheck;
+import android.webkit.HttpAuthHandler;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+@TestTargetClass(android.webkit.WebViewClient.class)
+public class WebViewClientTest extends ActivityInstrumentationTestCase2<WebViewStubActivity> {
+    private static final long TEST_TIMEOUT = 5000;
+
+    private WebView mWebView;
+    private CtsTestServer mWebServer;
+
+    public WebViewClientTest() {
+        super("com.android.cts.stub", WebViewStubActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mWebView = getActivity().getWebView();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mWebView.clearHistory();
+        mWebView.clearCache(true);
+        if (mWebServer != null) {
+            mWebServer.shutdown();
+        }
+        super.tearDown();
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "shouldOverrideUrlLoading",
+        args = {WebView.class, String.class}
+    )
+    public void testShouldOverrideUrlLoading() {
+        final MockWebViewClient webViewClient = new MockWebViewClient();
+        assertFalse(webViewClient.shouldOverrideUrlLoading(mWebView, null));
+    }
+
+    @TestTargets({
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "onPageStarted",
+            args = {WebView.class, String.class, Bitmap.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "onPageFinished",
+            args = {WebView.class, String.class}
+        ),
+        @TestTargetNew(
+            level = TestLevel.COMPLETE,
+            method = "onLoadResource",
+            args = {WebView.class, String.class}
+        )
+    })
+    public void testLoadPage() throws Exception {
+        final MockWebViewClient webViewClient = new MockWebViewClient();
+        mWebView.setWebViewClient(webViewClient);
+        mWebServer = new CtsTestServer(getActivity());
+        String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+
+        assertFalse(webViewClient.hasOnPageStartedCalled());
+        assertFalse(webViewClient.hasOnLoadResourceCalled());
+        assertFalse(webViewClient.hasOnPageFinishedCalled());
+        mWebView.loadUrl(url);
+
+        new DelayedCheck(TEST_TIMEOUT) {
+            protected boolean check() {
+                return webViewClient.hasOnPageStartedCalled();
+            }
+        }.run();
+
+        new DelayedCheck(TEST_TIMEOUT) {
+            protected boolean check() {
+                return webViewClient.hasOnLoadResourceCalled();
+            }
+        }.run();
+
+        new DelayedCheck(TEST_TIMEOUT) {
+            protected boolean check() {
+                return webViewClient.hasOnPageFinishedCalled();
+            }
+        }.run();
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "onTooManyRedirects",
+        args = {WebView.class, Message.class, Message.class}
+    )
+    @ToBeFixed(explanation="onTooManyRedirects() is never called")
+    public void testOnTooManyRedirects() throws Exception {
+        final MockWebViewClient webViewClient = new MockWebViewClient();
+        mWebView.setWebViewClient(webViewClient);
+        mWebServer = new CtsTestServer(getActivity());
+
+        assertFalse(webViewClient.hasOnTooManyRedirectsCalled());
+        assertEquals(0, webViewClient.hasOnReceivedErrorCode());
+        String url = mWebServer.getRedirectingAssetUrl(TestHtmlConstants.HELLO_WORLD_URL, 100);
+        assertLoadUrlSuccessfully(mWebView, url);
+        // ToBeFixed: onTooManyRedirects() is meant to give the application the choice of continuing
+        // to follow the redirects, but never gets called. onReceivedError() shadows the callback
+        // and aborts unconditionally.
+        assertEquals(WebViewClient.ERROR_REDIRECT_LOOP, webViewClient.hasOnReceivedErrorCode());
+        assertFalse(webViewClient.hasOnTooManyRedirectsCalled());
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "onReceivedError",
+        args = {WebView.class, int.class, String.class, String.class}
+    )
+    public void testOnReceivedError() throws Exception {
+        final MockWebViewClient webViewClient = new MockWebViewClient();
+        mWebView.setWebViewClient(webViewClient);
+
+        String wrongUri = "invalidscheme://some/resource";
+        assertEquals(0, webViewClient.hasOnReceivedErrorCode());
+        assertLoadUrlSuccessfully(mWebView, wrongUri);
+        assertEquals(WebViewClient.ERROR_UNSUPPORTED_SCHEME,
+                webViewClient.hasOnReceivedErrorCode());
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "onFormResubmission",
+        args = {WebView.class, Message.class, Message.class}
+    )
+    public void testOnFormResubmission() throws Exception {
+        final MockWebViewClient webViewClient = new MockWebViewClient();
+        mWebView.setWebViewClient(webViewClient);
+        final WebSettings settings = mWebView.getSettings();
+        settings.setJavaScriptEnabled(true);
+        mWebServer = new CtsTestServer(getActivity());
+
+        assertFalse(webViewClient.hasOnFormResubmissionCalled());
+        String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_FORM_URL);
+        // this loads a form, which automatically posts itself
+        assertLoadUrlSuccessfully(mWebView, url);
+        Thread.sleep(1000); // allow for javascript to post the form
+        // the URL should have changed when the form was posted
+        assertFalse(url.equals(mWebView.getUrl()));
+        // reloading the current URL should trigger the callback
+        mWebView.reload();
+        new DelayedCheck(TEST_TIMEOUT) {
+            protected boolean check() {
+                return webViewClient.hasOnFormResubmissionCalled();
+            }
+        }.run();
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "doUpdateVisitedHistory",
+        args = {WebView.class, String.class, boolean.class}
+    )
+    public void testDoUpdateVisitedHistory() throws Exception {
+        final MockWebViewClient webViewClient = new MockWebViewClient();
+        mWebView.setWebViewClient(webViewClient);
+        mWebServer = new CtsTestServer(getActivity());
+
+        assertFalse(webViewClient.hasDoUpdateVisitedHistoryCalled());
+        String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+        String url2 = mWebServer.getAssetUrl(TestHtmlConstants.BR_TAG_URL);
+        assertLoadUrlSuccessfully(mWebView, url1);
+        assertLoadUrlSuccessfully(mWebView, url2);
+        new DelayedCheck(TEST_TIMEOUT) {
+            protected boolean check() {
+                return webViewClient.hasDoUpdateVisitedHistoryCalled();
+            }
+        }.run();
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "onReceivedHttpAuthRequest",
+        args = {WebView.class, HttpAuthHandler.class, String.class, String.class}
+    )
+    public void testOnReceivedHttpAuthRequest() throws Exception {
+        final MockWebViewClient webViewClient = new MockWebViewClient();
+        mWebView.setWebViewClient(webViewClient);
+        mWebServer = new CtsTestServer(getActivity());
+
+        assertFalse(webViewClient.hasOnReceivedHttpAuthRequestCalled());
+        String url = mWebServer.getAuthAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+        assertLoadUrlSuccessfully(mWebView, url);
+        assertTrue(webViewClient.hasOnReceivedHttpAuthRequestCalled());
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "shouldOverrideKeyEvent",
+        args = {WebView.class, KeyEvent.class}
+    )
+    public void testShouldOverrideKeyEvent() {
+        final MockWebViewClient webViewClient = new MockWebViewClient();
+        mWebView.setWebViewClient(webViewClient);
+
+        assertFalse(webViewClient.shouldOverrideKeyEvent(mWebView, null));
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "onUnhandledKeyEvent",
+        args = {WebView.class, KeyEvent.class}
+    )
+    public void testOnUnhandledKeyEvent() throws Throwable {
+        final MockWebViewClient webViewClient = new MockWebViewClient();
+        mWebView.setWebViewClient(webViewClient);
+
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mWebView.requestFocus();
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+
+        assertFalse(webViewClient.hasOnUnhandledKeyEventCalled());
+        sendKeys(KeyEvent.KEYCODE_1);
+
+        new DelayedCheck(TEST_TIMEOUT) {
+            protected boolean check() {
+                return webViewClient.hasOnUnhandledKeyEventCalled();
+            }
+        }.run();
+    }
+
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        method = "onScaleChanged",
+        args = {WebView.class, float.class, float.class}
+    )
+    public void testOnScaleChanged() throws Throwable {
+        final MockWebViewClient webViewClient = new MockWebViewClient();
+        mWebView.setWebViewClient(webViewClient);
+
+        assertFalse(webViewClient.hasOnScaleChangedCalled());
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                mWebView.zoomIn();
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        assertTrue(webViewClient.hasOnScaleChangedCalled());
+    }
+
+    private void assertLoadUrlSuccessfully(final WebView view, String url) {
+        view.loadUrl(url);
+        // wait until load is complete
+        new DelayedCheck(TEST_TIMEOUT) {
+            @Override
+            protected boolean check() {
+                return view.getProgress() == 100;
+            }
+        }.run();
+    }
+
+    private class MockWebViewClient extends WebViewClient {
+        private boolean mOnPageStartedCalled;
+        private boolean mOnPageFinishedCalled;
+        private boolean mOnLoadResourceCalled;
+        private boolean mOnTooManyRedirectsCalled;
+        private int mOnReceivedErrorCode;
+        private boolean mOnFormResubmissionCalled;
+        private boolean mDoUpdateVisitedHistoryCalled;
+        private boolean mOnReceivedHttpAuthRequestCalled;
+        private boolean mOnUnhandledKeyEventCalled;
+        private boolean mOnScaleChangedCalled;
+
+        public boolean hasOnPageStartedCalled() {
+            return mOnPageStartedCalled;
+        }
+
+        public boolean hasOnPageFinishedCalled() {
+            return mOnPageFinishedCalled;
+        }
+
+        public boolean hasOnLoadResourceCalled() {
+            return mOnLoadResourceCalled;
+        }
+
+        public boolean hasOnTooManyRedirectsCalled() {
+            return mOnTooManyRedirectsCalled;
+        }
+
+        public int hasOnReceivedErrorCode() {
+            return mOnReceivedErrorCode;
+        }
+
+        public boolean hasOnFormResubmissionCalled() {
+            return mOnFormResubmissionCalled;
+        }
+
+        public boolean hasDoUpdateVisitedHistoryCalled() {
+            return mDoUpdateVisitedHistoryCalled;
+        }
+
+        public boolean hasOnReceivedHttpAuthRequestCalled() {
+            return mOnReceivedHttpAuthRequestCalled;
+        }
+
+        public boolean hasOnUnhandledKeyEventCalled() {
+            return mOnUnhandledKeyEventCalled;
+        }
+
+        public boolean hasOnScaleChangedCalled() {
+            return mOnScaleChangedCalled;
+        }
+
+        @Override
+        public void onPageStarted(WebView view, String url, Bitmap favicon) {
+            super.onPageStarted(view, url, favicon);
+            mOnPageStartedCalled = true;
+        }
+
+        @Override
+        public void onPageFinished(WebView view, String url) {
+            super.onPageFinished(view, url);
+            assertTrue(mOnPageStartedCalled);
+            assertTrue(mOnLoadResourceCalled);
+            mOnPageFinishedCalled = true;
+        }
+
+        @Override
+        public void onLoadResource(WebView view, String url) {
+            super.onLoadResource(view, url);
+            assertTrue(mOnPageStartedCalled);
+            mOnLoadResourceCalled = true;
+        }
+
+        @Override
+        public void onTooManyRedirects(WebView view, Message cancelMsg, Message continueMsg) {
+            mOnTooManyRedirectsCalled = true;
+            continueMsg.sendToTarget();
+        }
+
+        @Override
+        public void onReceivedError(WebView view, int errorCode,
+                String description, String failingUrl) {
+            super.onReceivedError(view, errorCode, description, failingUrl);
+            mOnReceivedErrorCode = errorCode;
+        }
+
+        @Override
+        public void onFormResubmission(WebView view, Message dontResend, Message resend) {
+            mOnFormResubmissionCalled = true;
+            dontResend.sendToTarget();
+        }
+
+        @Override
+        public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
+            super.doUpdateVisitedHistory(view, url, isReload);
+            mDoUpdateVisitedHistoryCalled = true;
+        }
+
+        @Override
+        public void onReceivedHttpAuthRequest(WebView view,
+                HttpAuthHandler handler, String host, String realm) {
+            super.onReceivedHttpAuthRequest(view, handler, host, realm);
+            mOnReceivedHttpAuthRequestCalled = true;
+        }
+
+        @Override
+        public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
+            super.onUnhandledKeyEvent(view, event);
+            mOnUnhandledKeyEventCalled = true;
+        }
+
+        @Override
+        public void onScaleChanged(WebView view, float oldScale, float newScale) {
+            super.onScaleChanged(view, oldScale, newScale);
+            mOnScaleChangedCalled = true;
+        }
+    }
+}