• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.webkit.cts;
18 
19 import android.cts.util.EvaluateJsResultPollingCheck;
20 import android.cts.util.NullWebViewUtils;
21 import android.cts.util.PollingCheck;
22 import android.graphics.Bitmap;
23 import android.os.Message;
24 import android.test.ActivityInstrumentationTestCase2;
25 import android.view.KeyEvent;
26 import android.view.ViewGroup;
27 import android.webkit.HttpAuthHandler;
28 import android.webkit.ValueCallback;
29 import android.webkit.WebChromeClient;
30 import android.webkit.WebResourceRequest;
31 import android.webkit.WebResourceResponse;
32 import android.webkit.WebSettings;
33 import android.webkit.WebView;
34 import android.webkit.WebViewClient;
35 import android.webkit.cts.WebViewOnUiThread.WaitForLoadedClient;
36 
37 import java.io.ByteArrayInputStream;
38 import java.nio.charset.StandardCharsets;
39 import java.util.HashMap;
40 import java.util.Map;
41 
42 public class WebViewClientTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
43     private static final long TEST_TIMEOUT = 5000;
44     private static final String TEST_URL = "http://foo.com/";
45 
46     private WebViewOnUiThread mOnUiThread;
47     private CtsTestServer mWebServer;
48 
WebViewClientTest()49     public WebViewClientTest() {
50         super("com.android.cts.webkit", WebViewCtsActivity.class);
51     }
52 
53     @Override
setUp()54     protected void setUp() throws Exception {
55         super.setUp();
56         final WebViewCtsActivity activity = getActivity();
57         WebView webview = activity.getWebView();
58         if (webview != null) {
59             new PollingCheck(TEST_TIMEOUT) {
60                 @Override
61                     protected boolean check() {
62                     return activity.hasWindowFocus();
63                 }
64             }.run();
65 
66             mOnUiThread = new WebViewOnUiThread(this, webview);
67         }
68     }
69 
70     @Override
tearDown()71     protected void tearDown() throws Exception {
72         if (mOnUiThread != null) {
73             mOnUiThread.cleanUp();
74         }
75         if (mWebServer != null) {
76             mWebServer.shutdown();
77         }
78         super.tearDown();
79     }
80 
81     // Verify that the shouldoverrideurlloading is false by default
testShouldOverrideUrlLoadingDefault()82     public void testShouldOverrideUrlLoadingDefault() {
83         if (!NullWebViewUtils.isWebViewAvailable()) {
84             return;
85         }
86         final WebViewClient webViewClient = new WebViewClient();
87         assertFalse(webViewClient.shouldOverrideUrlLoading(mOnUiThread.getWebView(), null));
88     }
89 
90     // Verify shouldoverrideurlloading called on top level navigation
testShouldOverrideUrlLoading()91     public void testShouldOverrideUrlLoading() {
92         if (!NullWebViewUtils.isWebViewAvailable()) {
93             return;
94         }
95         final MockWebViewClient webViewClient = new MockWebViewClient();
96         mOnUiThread.setWebViewClient(webViewClient);
97         mOnUiThread.getSettings().setJavaScriptEnabled(true);
98         String data = "<html><body>" +
99                 "<a href=\"" + TEST_URL + "\" id=\"link\">new page</a>" +
100                 "</body></html>";
101         mOnUiThread.loadDataAndWaitForCompletion(data, "text/html", null);
102         clickOnLinkUsingJs("link", mOnUiThread);
103         assertEquals(TEST_URL, webViewClient.getLastShouldOverrideUrl());
104     }
105 
106     // Verify shouldoverrideurlloading called on webview called via onCreateWindow
107     // TODO(sgurun) upstream this test to Aw.
testShouldOverrideUrlLoadingOnCreateWindow()108     public void testShouldOverrideUrlLoadingOnCreateWindow() throws Exception {
109         if (!NullWebViewUtils.isWebViewAvailable()) {
110             return;
111         }
112         mWebServer = new CtsTestServer(getActivity());
113         // WebViewClient for main window
114         final MockWebViewClient mainWebViewClient = new MockWebViewClient();
115         // WebViewClient for child window
116         final MockWebViewClient childWebViewClient = new MockWebViewClient();
117         mOnUiThread.setWebViewClient(mainWebViewClient);
118         mOnUiThread.getSettings().setJavaScriptEnabled(true);
119         mOnUiThread.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
120         mOnUiThread.getSettings().setSupportMultipleWindows(true);
121 
122         final WebView childWebView = mOnUiThread.createWebView();
123 
124         mOnUiThread.setWebChromeClient(new WebChromeClient() {
125             @Override
126             public boolean onCreateWindow(
127                 WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
128                 WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
129                 childWebView.setWebViewClient(childWebViewClient);
130                 childWebView.getSettings().setJavaScriptEnabled(true);
131                 transport.setWebView(childWebView);
132                 getActivity().addContentView(childWebView, new ViewGroup.LayoutParams(
133                             ViewGroup.LayoutParams.FILL_PARENT,
134                             ViewGroup.LayoutParams.WRAP_CONTENT));
135                 resultMsg.sendToTarget();
136                 return true;
137             }
138         });
139         mOnUiThread.loadUrl(mWebServer.getAssetUrl(TestHtmlConstants.BLANK_TAG_URL));
140 
141         new PollingCheck(TEST_TIMEOUT) {
142             @Override
143             protected boolean check() {
144                 return childWebViewClient.hasOnPageFinishedCalled();
145             }
146         }.run();
147         assertEquals(mWebServer.getAssetUrl(TestHtmlConstants.PAGE_WITH_LINK_URL),
148                 childWebViewClient.getLastShouldOverrideUrl());
149 
150         // Now test a navigation within the page
151         //TODO(hush) Enable this portion when b/12804986 is fixed.
152         /*
153         WebViewOnUiThread childWebViewOnUiThread = new WebViewOnUiThread(this, childWebView);
154         final int childCallCount = childWebViewClient.getShouldOverrideUrlLoadingCallCount();
155         final int mainCallCount = mainWebViewClient.getShouldOverrideUrlLoadingCallCount();
156         clickOnLinkUsingJs("link", childWebViewOnUiThread);
157         new PollingCheck(TEST_TIMEOUT) {
158             @Override
159             protected boolean check() {
160                 return childWebViewClient.getShouldOverrideUrlLoadingCallCount() > childCallCount;
161             }
162         }.run();
163         assertEquals(mainCallCount, mainWebViewClient.getShouldOverrideUrlLoadingCallCount());
164         assertEquals(TEST_URL, childWebViewClient.getLastShouldOverrideUrl());
165         */
166     }
167 
clickOnLinkUsingJs(final String linkId, WebViewOnUiThread webViewOnUiThread)168     private void clickOnLinkUsingJs(final String linkId, WebViewOnUiThread webViewOnUiThread) {
169         EvaluateJsResultPollingCheck jsResult = new EvaluateJsResultPollingCheck("null");
170         webViewOnUiThread.evaluateJavascript(
171                 "document.getElementById('" + linkId + "').click();" +
172                 "console.log('element with id [" + linkId + "] clicked');", jsResult);
173         jsResult.run();
174     }
175 
testLoadPage()176     public void testLoadPage() throws Exception {
177         if (!NullWebViewUtils.isWebViewAvailable()) {
178             return;
179         }
180         final MockWebViewClient webViewClient = new MockWebViewClient();
181         mOnUiThread.setWebViewClient(webViewClient);
182         mWebServer = new CtsTestServer(getActivity());
183         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
184 
185         assertFalse(webViewClient.hasOnPageStartedCalled());
186         assertFalse(webViewClient.hasOnLoadResourceCalled());
187         assertFalse(webViewClient.hasOnPageFinishedCalled());
188         mOnUiThread.loadUrlAndWaitForCompletion(url);
189 
190         new PollingCheck(TEST_TIMEOUT) {
191             @Override
192             protected boolean check() {
193                 return webViewClient.hasOnPageStartedCalled();
194             }
195         }.run();
196 
197         new PollingCheck(TEST_TIMEOUT) {
198             @Override
199             protected boolean check() {
200                 return webViewClient.hasOnLoadResourceCalled();
201             }
202         }.run();
203 
204         new PollingCheck(TEST_TIMEOUT) {
205             @Override
206             protected boolean check() {
207                 return webViewClient.hasOnPageFinishedCalled();
208             }
209         }.run();
210     }
211 
testOnReceivedError()212     public void testOnReceivedError() throws Exception {
213         if (!NullWebViewUtils.isWebViewAvailable()) {
214             return;
215         }
216         final MockWebViewClient webViewClient = new MockWebViewClient();
217         mOnUiThread.setWebViewClient(webViewClient);
218 
219         String wrongUri = "invalidscheme://some/resource";
220         assertEquals(0, webViewClient.hasOnReceivedErrorCode());
221         mOnUiThread.loadUrlAndWaitForCompletion(wrongUri);
222         assertEquals(WebViewClient.ERROR_UNSUPPORTED_SCHEME,
223                 webViewClient.hasOnReceivedErrorCode());
224     }
225 
testOnFormResubmission()226     public void testOnFormResubmission() throws Exception {
227         if (!NullWebViewUtils.isWebViewAvailable()) {
228             return;
229         }
230         final MockWebViewClient webViewClient = new MockWebViewClient();
231         mOnUiThread.setWebViewClient(webViewClient);
232         final WebSettings settings = mOnUiThread.getSettings();
233         settings.setJavaScriptEnabled(true);
234         mWebServer = new CtsTestServer(getActivity());
235 
236         assertFalse(webViewClient.hasOnFormResubmissionCalled());
237         String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_FORM_URL);
238         // this loads a form, which automatically posts itself
239         mOnUiThread.loadUrlAndWaitForCompletion(url);
240         // wait for JavaScript to post the form
241         mOnUiThread.waitForLoadCompletion();
242         // the URL should have changed when the form was posted
243         assertFalse(url.equals(mOnUiThread.getUrl()));
244         // reloading the current URL should trigger the callback
245         mOnUiThread.reload();
246         new PollingCheck(TEST_TIMEOUT) {
247             @Override
248             protected boolean check() {
249                 return webViewClient.hasOnFormResubmissionCalled();
250             }
251         }.run();
252     }
253 
testDoUpdateVisitedHistory()254     public void testDoUpdateVisitedHistory() throws Exception {
255         if (!NullWebViewUtils.isWebViewAvailable()) {
256             return;
257         }
258         final MockWebViewClient webViewClient = new MockWebViewClient();
259         mOnUiThread.setWebViewClient(webViewClient);
260         mWebServer = new CtsTestServer(getActivity());
261 
262         assertFalse(webViewClient.hasDoUpdateVisitedHistoryCalled());
263         String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
264         String url2 = mWebServer.getAssetUrl(TestHtmlConstants.BR_TAG_URL);
265         mOnUiThread.loadUrlAndWaitForCompletion(url1);
266         mOnUiThread.loadUrlAndWaitForCompletion(url2);
267         new PollingCheck(TEST_TIMEOUT) {
268             @Override
269             protected boolean check() {
270                 return webViewClient.hasDoUpdateVisitedHistoryCalled();
271             }
272         }.run();
273     }
274 
testOnReceivedHttpAuthRequest()275     public void testOnReceivedHttpAuthRequest() throws Exception {
276         if (!NullWebViewUtils.isWebViewAvailable()) {
277             return;
278         }
279         final MockWebViewClient webViewClient = new MockWebViewClient();
280         mOnUiThread.setWebViewClient(webViewClient);
281         mWebServer = new CtsTestServer(getActivity());
282 
283         assertFalse(webViewClient.hasOnReceivedHttpAuthRequestCalled());
284         String url = mWebServer.getAuthAssetUrl(TestHtmlConstants.EMBEDDED_IMG_URL);
285         mOnUiThread.loadUrlAndWaitForCompletion(url);
286         assertTrue(webViewClient.hasOnReceivedHttpAuthRequestCalled());
287     }
288 
testShouldOverrideKeyEvent()289     public void testShouldOverrideKeyEvent() {
290         if (!NullWebViewUtils.isWebViewAvailable()) {
291             return;
292         }
293         final MockWebViewClient webViewClient = new MockWebViewClient();
294         mOnUiThread.setWebViewClient(webViewClient);
295 
296         assertFalse(webViewClient.shouldOverrideKeyEvent(mOnUiThread.getWebView(), null));
297     }
298 
testOnUnhandledKeyEvent()299     public void testOnUnhandledKeyEvent() throws Throwable {
300         if (!NullWebViewUtils.isWebViewAvailable()) {
301             return;
302         }
303         requireLoadedPage();
304         final MockWebViewClient webViewClient = new MockWebViewClient();
305         mOnUiThread.setWebViewClient(webViewClient);
306 
307         mOnUiThread.requestFocus();
308         getInstrumentation().waitForIdleSync();
309 
310         assertFalse(webViewClient.hasOnUnhandledKeyEventCalled());
311         sendKeys(KeyEvent.KEYCODE_1);
312 
313         new PollingCheck(TEST_TIMEOUT) {
314             @Override
315             protected boolean check() {
316                 return webViewClient.hasOnUnhandledKeyEventCalled();
317             }
318         }.run();
319     }
320 
testOnScaleChanged()321     public void testOnScaleChanged() throws Throwable {
322         if (!NullWebViewUtils.isWebViewAvailable()) {
323             return;
324         }
325         final MockWebViewClient webViewClient = new MockWebViewClient();
326         mOnUiThread.setWebViewClient(webViewClient);
327         mWebServer = new CtsTestServer(getActivity());
328 
329         assertFalse(webViewClient.hasOnScaleChangedCalled());
330         String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
331         mOnUiThread.loadUrlAndWaitForCompletion(url1);
332 
333         new PollingCheck(TEST_TIMEOUT) {
334             @Override
335             protected boolean check() {
336                 return mOnUiThread.canZoomIn();
337             }
338         }.run();
339 
340         assertTrue(mOnUiThread.zoomIn());
341         new PollingCheck(TEST_TIMEOUT) {
342             @Override
343             protected boolean check() {
344                 return webViewClient.hasOnScaleChangedCalled();
345             }
346         }.run();
347     }
348 
349     // Test that shouldInterceptRequest is called with the correct parameters
testShouldInterceptRequestParams()350     public void testShouldInterceptRequestParams() throws Throwable {
351         if (!NullWebViewUtils.isWebViewAvailable()) {
352             return;
353         }
354 
355         final String mainPath = "/main";
356         final String mainPage = "<head></head><body>test page</body>";
357         final String headerName = "x-test-header-name";
358         final String headerValue = "testheadervalue";
359         HashMap<String, String> headers = new HashMap<String, String>(1);
360         headers.put(headerName, headerValue);
361 
362         // A client which saves the WebResourceRequest as interceptRequest
363         final class TestClient extends WaitForLoadedClient {
364             public TestClient() {
365                 super(mOnUiThread);
366             }
367 
368             @Override
369             public WebResourceResponse shouldInterceptRequest(WebView view,
370                     WebResourceRequest request) {
371                 assertNotNull(view);
372                 assertNotNull(request);
373 
374                 assertEquals(view, mOnUiThread.getWebView());
375 
376                 // Save the main page request; discard any other requests (e.g. for favicon.ico)
377                 if (request.getUrl().getPath().equals(mainPath)) {
378                     assertNull(interceptRequest);
379                     interceptRequest = request;
380                 }
381 
382                 return null;
383             }
384 
385             public volatile WebResourceRequest interceptRequest;
386         }
387 
388         TestClient client = new TestClient();
389         mOnUiThread.setWebViewClient(client);
390 
391         TestWebServer server = new TestWebServer(false);
392         try {
393             String mainUrl = server.setResponse(mainPath, mainPage, null);
394 
395             mOnUiThread.loadUrlAndWaitForCompletion(mainUrl, headers);
396 
397             // Inspect the fields of the saved WebResourceRequest
398             assertNotNull(client.interceptRequest);
399             assertEquals(mainUrl, client.interceptRequest.getUrl().toString());
400             assertTrue(client.interceptRequest.isForMainFrame());
401             assertEquals(server.getLastRequest(mainPath).getRequestLine().getMethod(),
402                 client.interceptRequest.getMethod());
403 
404             // Web request headers are case-insensitive. We provided lower-case headerName and
405             // headerValue. This will pass implementations which either do not mangle case,
406             // convert to lowercase, or convert to uppercase but return a case-insensitive map.
407             Map<String, String> interceptHeaders = client.interceptRequest.getRequestHeaders();
408             assertTrue(interceptHeaders.containsKey(headerName));
409             assertEquals(headerValue, interceptHeaders.get(headerName));
410         } finally {
411             server.shutdown();
412         }
413     }
414 
415     // Test that the WebResourceResponse returned by shouldInterceptRequest is handled correctly
testShouldInterceptRequestResponse()416     public void testShouldInterceptRequestResponse() throws Throwable {
417         if (!NullWebViewUtils.isWebViewAvailable()) {
418             return;
419         }
420 
421         final String mainPath = "/main";
422         final String mainPage = "<head></head><body>test page</body>";
423         final String interceptPath = "/intercept_me";
424 
425         // A client which responds to requests for interceptPath with a saved interceptResponse
426         final class TestClient extends WaitForLoadedClient {
427             public TestClient() {
428                 super(mOnUiThread);
429             }
430 
431             @Override
432             public WebResourceResponse shouldInterceptRequest(WebView view,
433                     WebResourceRequest request) {
434                 if (request.getUrl().toString().contains(interceptPath)) {
435                     assertNotNull(interceptResponse);
436                     return interceptResponse;
437                 }
438 
439                 return null;
440             }
441 
442             volatile public WebResourceResponse interceptResponse;
443         }
444 
445         mOnUiThread.getSettings().setJavaScriptEnabled(true);
446 
447         TestClient client = new TestClient();
448         mOnUiThread.setWebViewClient(client);
449 
450         TestWebServer server = new TestWebServer(false);
451         try {
452             String interceptUrl = server.getResponseUrl(interceptPath);
453 
454             // JavaScript which makes a synchronous AJAX request and logs and returns the status
455             String js =
456                 "(function() {" +
457                 "  var xhr = new XMLHttpRequest();" +
458                 "  xhr.open('GET', '" + interceptUrl + "', false);" +
459                 "  xhr.send(null);" +
460                 "  console.info('xhr.status = ' + xhr.status);" +
461                 "  console.info('xhr.statusText = ' + xhr.statusText);" +
462                 "  return '[' + xhr.status + '][' + xhr.statusText + ']';" +
463                 "})();";
464 
465             String mainUrl = server.setResponse(mainPath, mainPage, null);
466             mOnUiThread.loadUrlAndWaitForCompletion(mainUrl, null);
467 
468             EvaluateJsResultPollingCheck jsResult;
469 
470             // Test a nonexistent page
471             client.interceptResponse = new WebResourceResponse("text/html", "UTF-8", null);
472             jsResult = new EvaluateJsResultPollingCheck("\"[404][Not Found]\"");
473             mOnUiThread.evaluateJavascript(js, jsResult);
474             jsResult.run();
475 
476             // Test an empty page
477             client.interceptResponse = new WebResourceResponse("text/html", "UTF-8",
478                 new ByteArrayInputStream(new byte[0]));
479             jsResult = new EvaluateJsResultPollingCheck("\"[200][OK]\"");
480             mOnUiThread.evaluateJavascript(js, jsResult);
481             jsResult.run();
482 
483             // Test a nonempty page with unusual response code/text
484             client.interceptResponse =
485                 new WebResourceResponse("text/html", "UTF-8", 123, "unusual", null,
486                     new ByteArrayInputStream("nonempty page".getBytes(StandardCharsets.UTF_8)));
487             jsResult = new EvaluateJsResultPollingCheck("\"[123][unusual]\"");
488             mOnUiThread.evaluateJavascript(js, jsResult);
489             jsResult.run();
490         } finally {
491             server.shutdown();
492         }
493     }
494 
requireLoadedPage()495     private void requireLoadedPage() throws Throwable {
496         if (!NullWebViewUtils.isWebViewAvailable()) {
497             return;
498         }
499         mOnUiThread.loadUrlAndWaitForCompletion("about:blank");
500     }
501 
502     private class MockWebViewClient extends WaitForLoadedClient {
503         private boolean mOnPageStartedCalled;
504         private boolean mOnPageFinishedCalled;
505         private boolean mOnLoadResourceCalled;
506         private int mOnReceivedErrorCode;
507         private boolean mOnFormResubmissionCalled;
508         private boolean mDoUpdateVisitedHistoryCalled;
509         private boolean mOnReceivedHttpAuthRequestCalled;
510         private boolean mOnUnhandledKeyEventCalled;
511         private boolean mOnScaleChangedCalled;
512         private int mShouldOverrideUrlLoadingCallCount;
513         private String mLastShouldOverrideUrl;
514 
MockWebViewClient()515         public MockWebViewClient() {
516             super(mOnUiThread);
517         }
518 
hasOnPageStartedCalled()519         public boolean hasOnPageStartedCalled() {
520             return mOnPageStartedCalled;
521         }
522 
hasOnPageFinishedCalled()523         public boolean hasOnPageFinishedCalled() {
524             return mOnPageFinishedCalled;
525         }
526 
hasOnLoadResourceCalled()527         public boolean hasOnLoadResourceCalled() {
528             return mOnLoadResourceCalled;
529         }
530 
hasOnReceivedErrorCode()531         public int hasOnReceivedErrorCode() {
532             return mOnReceivedErrorCode;
533         }
534 
hasOnFormResubmissionCalled()535         public boolean hasOnFormResubmissionCalled() {
536             return mOnFormResubmissionCalled;
537         }
538 
hasDoUpdateVisitedHistoryCalled()539         public boolean hasDoUpdateVisitedHistoryCalled() {
540             return mDoUpdateVisitedHistoryCalled;
541         }
542 
hasOnReceivedHttpAuthRequestCalled()543         public boolean hasOnReceivedHttpAuthRequestCalled() {
544             return mOnReceivedHttpAuthRequestCalled;
545         }
546 
hasOnUnhandledKeyEventCalled()547         public boolean hasOnUnhandledKeyEventCalled() {
548             return mOnUnhandledKeyEventCalled;
549         }
550 
hasOnScaleChangedCalled()551         public boolean hasOnScaleChangedCalled() {
552             return mOnScaleChangedCalled;
553         }
554 
getShouldOverrideUrlLoadingCallCount()555         public int getShouldOverrideUrlLoadingCallCount() {
556             return mShouldOverrideUrlLoadingCallCount;
557         }
558 
getLastShouldOverrideUrl()559         public String getLastShouldOverrideUrl() {
560             return mLastShouldOverrideUrl;
561         }
562 
563         @Override
onPageStarted(WebView view, String url, Bitmap favicon)564         public void onPageStarted(WebView view, String url, Bitmap favicon) {
565             super.onPageStarted(view, url, favicon);
566             mOnPageStartedCalled = true;
567         }
568 
569         @Override
onPageFinished(WebView view, String url)570         public void onPageFinished(WebView view, String url) {
571             super.onPageFinished(view, url);
572             assertTrue(mOnPageStartedCalled);
573             assertTrue(mOnLoadResourceCalled);
574             mOnPageFinishedCalled = true;
575         }
576 
577         @Override
onLoadResource(WebView view, String url)578         public void onLoadResource(WebView view, String url) {
579             super.onLoadResource(view, url);
580             assertTrue(mOnPageStartedCalled);
581             mOnLoadResourceCalled = true;
582         }
583 
584         @Override
onReceivedError(WebView view, int errorCode, String description, String failingUrl)585         public void onReceivedError(WebView view, int errorCode,
586                 String description, String failingUrl) {
587             super.onReceivedError(view, errorCode, description, failingUrl);
588             mOnReceivedErrorCode = errorCode;
589         }
590 
591         @Override
onFormResubmission(WebView view, Message dontResend, Message resend)592         public void onFormResubmission(WebView view, Message dontResend, Message resend) {
593             mOnFormResubmissionCalled = true;
594             dontResend.sendToTarget();
595         }
596 
597         @Override
doUpdateVisitedHistory(WebView view, String url, boolean isReload)598         public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
599             super.doUpdateVisitedHistory(view, url, isReload);
600             mDoUpdateVisitedHistoryCalled = true;
601         }
602 
603         @Override
onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm)604         public void onReceivedHttpAuthRequest(WebView view,
605                 HttpAuthHandler handler, String host, String realm) {
606             super.onReceivedHttpAuthRequest(view, handler, host, realm);
607             mOnReceivedHttpAuthRequestCalled = true;
608         }
609 
610         @Override
onUnhandledKeyEvent(WebView view, KeyEvent event)611         public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
612             super.onUnhandledKeyEvent(view, event);
613             mOnUnhandledKeyEventCalled = true;
614         }
615 
616         @Override
onScaleChanged(WebView view, float oldScale, float newScale)617         public void onScaleChanged(WebView view, float oldScale, float newScale) {
618             super.onScaleChanged(view, oldScale, newScale);
619             mOnScaleChangedCalled = true;
620         }
621 
622         @Override
shouldOverrideUrlLoading(WebView view, String url)623         public boolean shouldOverrideUrlLoading(WebView view, String url) {
624             mLastShouldOverrideUrl = url;
625             mShouldOverrideUrlLoadingCallCount++;
626             return false;
627         }
628     }
629 }
630