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