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