AwContentsClientShouldOverrideUrlLoadingTest.java revision f2477e01787aa58f445919b809d89e252beef54f
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5package org.chromium.android_webview.test; 6 7import android.os.Bundle; 8import android.os.SystemClock; 9import android.test.suitebuilder.annotation.SmallTest; 10import android.util.Pair; 11import android.view.MotionEvent; 12import android.util.Log; 13 14import org.chromium.android_webview.AwContents; 15import org.chromium.android_webview.test.util.CommonResources; 16import org.chromium.android_webview.test.util.JSUtils; 17import org.chromium.base.test.util.Feature; 18import org.chromium.content.browser.NavigationHistory; 19import org.chromium.content.browser.LoadUrlParams; 20import org.chromium.content.browser.test.util.CallbackHelper; 21import org.chromium.content.browser.test.util.Criteria; 22import org.chromium.content.browser.test.util.CriteriaHelper; 23import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper; 24import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageStartedHelper; 25import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnReceivedErrorHelper; 26import org.chromium.net.test.util.TestWebServer; 27 28import java.net.URLEncoder; 29import java.util.ArrayList; 30import java.util.List; 31import java.util.concurrent.Callable; 32import java.util.concurrent.TimeUnit; 33 34/** 35 * Tests for the WebViewClient.shouldOverrideUrlLoading() method. 36 */ 37public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { 38 private final static String ABOUT_BLANK_URL = "about:blank"; 39 private final static String DATA_URL = "data:text/html,<div/>"; 40 private final static String REDIRECT_TARGET_PATH = "/redirect_target.html"; 41 private final static String TITLE = "TITLE"; 42 43 private static final long TEST_TIMEOUT = 20000L; 44 private static final long CHECK_INTERVAL = 100; 45 46 private static class TestAwContentsClient 47 extends org.chromium.android_webview.test.TestAwContentsClient { 48 49 public static class ShouldOverrideUrlLoadingHelper extends CallbackHelper { 50 private String mShouldOverrideUrlLoadingUrl; 51 private String mPreviousShouldOverrideUrlLoadingUrl; 52 private boolean mShouldOverrideUrlLoadingReturnValue = false; 53 void setShouldOverrideUrlLoadingUrl(String url) { 54 mShouldOverrideUrlLoadingUrl = url; 55 } 56 void setPreviousShouldOverrideUrlLoadingUrl(String url) { 57 mPreviousShouldOverrideUrlLoadingUrl = url; 58 } 59 void setShouldOverrideUrlLoadingReturnValue(boolean value) { 60 mShouldOverrideUrlLoadingReturnValue = value; 61 } 62 public String getShouldOverrideUrlLoadingUrl() { 63 assert getCallCount() > 0; 64 return mShouldOverrideUrlLoadingUrl; 65 } 66 public String getPreviousShouldOverrideUrlLoadingUrl() { 67 assert getCallCount() > 1; 68 return mPreviousShouldOverrideUrlLoadingUrl; 69 } 70 public boolean getShouldOverrideUrlLoadingReturnValue() { 71 return mShouldOverrideUrlLoadingReturnValue; 72 } 73 public void notifyCalled(String url) { 74 mPreviousShouldOverrideUrlLoadingUrl = mShouldOverrideUrlLoadingUrl; 75 mShouldOverrideUrlLoadingUrl = url; 76 notifyCalled(); 77 } 78 } 79 80 @Override 81 public boolean shouldOverrideUrlLoading(String url) { 82 super.shouldOverrideUrlLoading(url); 83 boolean returnValue = 84 mShouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingReturnValue(); 85 mShouldOverrideUrlLoadingHelper.notifyCalled(url); 86 return returnValue; 87 } 88 89 private ShouldOverrideUrlLoadingHelper mShouldOverrideUrlLoadingHelper; 90 91 public TestAwContentsClient() { 92 mShouldOverrideUrlLoadingHelper = new ShouldOverrideUrlLoadingHelper(); 93 } 94 95 public ShouldOverrideUrlLoadingHelper getShouldOverrideUrlLoadingHelper() { 96 return mShouldOverrideUrlLoadingHelper; 97 } 98 } 99 100 private TestWebServer mWebServer; 101 102 @Override 103 protected void setUp() throws Exception { 104 super.setUp(); 105 mWebServer = new TestWebServer(false); 106 } 107 108 @Override 109 protected void tearDown() throws Exception { 110 mWebServer.shutdown(); 111 super.tearDown(); 112 } 113 114 private void clickOnLinkUsingJs(final AwContents awContents, 115 final TestAwContentsClient contentsClient) throws Throwable { 116 enableJavaScriptOnUiThread(awContents); 117 JSUtils.clickOnLinkUsingJs(this, awContents, 118 contentsClient.getOnEvaluateJavaScriptResultHelper(), "link"); 119 } 120 121 // Since this value is read on the UI thread, it's simpler to set it there too. 122 void setShouldOverrideUrlLoadingReturnValueOnUiThread( 123 final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideHelper, 124 final boolean value) throws Throwable { 125 runTestOnUiThread(new Runnable() { 126 @Override 127 public void run() { 128 shouldOverrideHelper.setShouldOverrideUrlLoadingReturnValue(value); 129 } 130 }); 131 } 132 133 private String makeHtmlPageFrom(String headers, String body) { 134 return CommonResources.makeHtmlPageFrom("<title>" + TITLE + "</title> " + headers, body); 135 } 136 137 private String getHtmlForPageWithSimpleLinkTo(String destination) { 138 return makeHtmlPageFrom("", 139 "<a href=\"" + destination + "\" id=\"link\">" + 140 "<img class=\"big\" />" + 141 "</a>"); 142 } 143 144 private String getHtmlForPageWithJsAssignLinkTo(String url) { 145 return makeHtmlPageFrom("", 146 "<img onclick=\"location.href='" + url + "'\" class=\"big\" id=\"link\" />"); 147 } 148 149 private String getHtmlForPageWithJsReplaceLinkTo(String url) { 150 return makeHtmlPageFrom("", 151 "<img onclick=\"location.replace('" + url + "');\" class=\"big\" id=\"link\" />"); 152 } 153 154 private String getHtmlForPageWithMetaRefreshRedirectTo(String url) { 155 return makeHtmlPageFrom("<meta http-equiv=\"refresh\" content=\"0;url=" + url + "\" />", 156 "<div>Meta refresh redirect</div>"); 157 } 158 159 private String getHtmlForPageWithJsRedirectTo(String url, String method, int timeout) { 160 return makeHtmlPageFrom( 161 "<script>" + 162 "function doRedirectAssign() {" + 163 "location.href = '" + url + "';" + 164 "} " + 165 "function doRedirectReplace() {" + 166 "location.replace('" + url + "');" + 167 "} "+ 168 "</script>", 169 String.format("<iframe onLoad=\"setTimeout('doRedirect%s()', %d);\" />", 170 method, timeout)); 171 } 172 173 private String getHtmlForPageWithSimplePostFormTo(String destination) { 174 return makeHtmlPageFrom("", 175 "<form action=\"" + destination + "\" method=\"post\">" + 176 "<input type=\"submit\" value=\"post\" id=\"link\">"+ 177 "</form>"); 178 } 179 180 private String addPageToTestServer(TestWebServer webServer, String httpPath, String html) { 181 List<Pair<String, String>> headers = new ArrayList<Pair<String, String>>(); 182 headers.add(Pair.create("Content-Type", "text/html")); 183 headers.add(Pair.create("Cache-Control", "no-store")); 184 return webServer.setResponse(httpPath, html, headers); 185 } 186 187 private String createRedirectTargetPage(TestWebServer webServer) { 188 return addPageToTestServer(webServer, REDIRECT_TARGET_PATH, 189 makeHtmlPageFrom("", "<div>This is the end of the redirect chain</div>")); 190 } 191 192 @SmallTest 193 @Feature({"AndroidWebView", "Navigation"}) 194 public void testNotCalledOnLoadUrl() throws Throwable { 195 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 196 final AwTestContainerView testContainerView = 197 createAwTestContainerViewOnMainSync(contentsClient); 198 final AwContents awContents = testContainerView.getAwContents(); 199 TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 200 contentsClient.getShouldOverrideUrlLoadingHelper(); 201 202 loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), 203 getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false); 204 205 assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount()); 206 } 207 208 private void waitForNavigationRunnableAndAssertTitleChanged(AwContents awContents, 209 CallbackHelper onPageFinishedHelper, 210 Runnable navigationRunnable) throws Exception { 211 final int callCount = onPageFinishedHelper.getCallCount(); 212 final String oldTitle = getTitleOnUiThread(awContents); 213 getInstrumentation().runOnMainSync(navigationRunnable); 214 onPageFinishedHelper.waitForCallback(callCount); 215 assertFalse(oldTitle.equals(getTitleOnUiThread(awContents))); 216 } 217 218 @SmallTest 219 @Feature({"AndroidWebView", "Navigation"}) 220 public void testNotCalledOnBackForwardNavigation() throws Throwable { 221 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 222 final AwTestContainerView testContainerView = 223 createAwTestContainerViewOnMainSync(contentsClient); 224 final AwContents awContents = testContainerView.getAwContents(); 225 TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 226 contentsClient.getShouldOverrideUrlLoadingHelper(); 227 final String[] pageTitles = new String[] { "page1", "page2", "page3" }; 228 229 for (String title: pageTitles) { 230 loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), 231 CommonResources.makeHtmlPageFrom("<title>" + title + "</title>", ""), 232 "text/html", false); 233 } 234 assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount()); 235 236 waitForNavigationRunnableAndAssertTitleChanged(awContents, 237 contentsClient.getOnPageFinishedHelper(), new Runnable() { 238 @Override 239 public void run() { 240 awContents.goBack(); 241 } 242 }); 243 assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount()); 244 245 waitForNavigationRunnableAndAssertTitleChanged(awContents, 246 contentsClient.getOnPageFinishedHelper(), new Runnable() { 247 @Override 248 public void run() { 249 awContents.goForward(); 250 } 251 }); 252 assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount()); 253 254 waitForNavigationRunnableAndAssertTitleChanged(awContents, 255 contentsClient.getOnPageFinishedHelper(), new Runnable() { 256 @Override 257 public void run() { 258 awContents.goBackOrForward(-2); 259 } 260 }); 261 assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount()); 262 263 waitForNavigationRunnableAndAssertTitleChanged(awContents, 264 contentsClient.getOnPageFinishedHelper(), new Runnable() { 265 @Override 266 public void run() { 267 awContents.goBackOrForward(1); 268 } 269 }); 270 assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount()); 271 } 272 273 @SmallTest 274 @Feature({"AndroidWebView", "Navigation"}) 275 public void testCantBlockLoads() throws Throwable { 276 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 277 final AwTestContainerView testContainerView = 278 createAwTestContainerViewOnMainSync(contentsClient); 279 final AwContents awContents = testContainerView.getAwContents(); 280 TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 281 contentsClient.getShouldOverrideUrlLoadingHelper(); 282 283 setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, true); 284 285 loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), 286 getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false); 287 288 assertEquals(TITLE, getTitleOnUiThread(awContents)); 289 } 290 291 @SmallTest 292 @Feature({"AndroidWebView", "Navigation"}) 293 public void testCalledBeforeOnPageStarted() throws Throwable { 294 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 295 final AwTestContainerView testContainerView = 296 createAwTestContainerViewOnMainSync(contentsClient); 297 final AwContents awContents = testContainerView.getAwContents(); 298 TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 299 contentsClient.getShouldOverrideUrlLoadingHelper(); 300 OnPageStartedHelper onPageStartedHelper = contentsClient.getOnPageStartedHelper(); 301 302 loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), 303 getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false); 304 305 final int shouldOverrideUrlLoadingCallCount = shouldOverrideUrlLoadingHelper.getCallCount(); 306 final int onPageStartedCallCount = onPageStartedHelper.getCallCount(); 307 setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, true); 308 clickOnLinkUsingJs(awContents, contentsClient); 309 310 shouldOverrideUrlLoadingHelper.waitForCallback(shouldOverrideUrlLoadingCallCount); 311 assertEquals(onPageStartedCallCount, onPageStartedHelper.getCallCount()); 312 } 313 314 315 @SmallTest 316 @Feature({"AndroidWebView", "Navigation"}) 317 public void testDoesNotCauseOnReceivedError() throws Throwable { 318 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 319 final AwTestContainerView testContainerView = 320 createAwTestContainerViewOnMainSync(contentsClient); 321 final AwContents awContents = testContainerView.getAwContents(); 322 final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 323 contentsClient.getShouldOverrideUrlLoadingHelper(); 324 OnReceivedErrorHelper onReceivedErrorHelper = contentsClient.getOnReceivedErrorHelper(); 325 final int onReceivedErrorCallCount = onReceivedErrorHelper.getCallCount(); 326 327 loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), 328 getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false); 329 330 final int shouldOverrideUrlLoadingCallCount = shouldOverrideUrlLoadingHelper.getCallCount(); 331 332 setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, true); 333 334 clickOnLinkUsingJs(awContents, contentsClient); 335 336 shouldOverrideUrlLoadingHelper.waitForCallback(shouldOverrideUrlLoadingCallCount); 337 338 setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, false); 339 340 // After we load this URL we're certain that any in-flight callbacks for the previous 341 // navigation have been delivered. 342 loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), ABOUT_BLANK_URL); 343 344 assertEquals(onReceivedErrorCallCount, onReceivedErrorHelper.getCallCount()); 345 } 346 347 @SmallTest 348 @Feature({"AndroidWebView", "Navigation"}) 349 public void testNotCalledForAnchorNavigations() throws Throwable { 350 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 351 final AwTestContainerView testContainerView = 352 createAwTestContainerViewOnMainSync(contentsClient); 353 final AwContents awContents = testContainerView.getAwContents(); 354 final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 355 contentsClient.getShouldOverrideUrlLoadingHelper(); 356 357 final String anchorLinkPath = "/anchor_link.html"; 358 final String anchorLinkUrl = mWebServer.getResponseUrl(anchorLinkPath); 359 addPageToTestServer(mWebServer, anchorLinkPath, 360 getHtmlForPageWithSimpleLinkTo(anchorLinkUrl + "#anchor")); 361 362 loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), anchorLinkUrl); 363 364 final int shouldOverrideUrlLoadingCallCount = 365 shouldOverrideUrlLoadingHelper.getCallCount(); 366 367 clickOnLinkUsingJs(awContents, contentsClient); 368 369 // After we load this URL we're certain that any in-flight callbacks for the previous 370 // navigation have been delivered. 371 loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), ABOUT_BLANK_URL); 372 373 assertEquals(shouldOverrideUrlLoadingCallCount, 374 shouldOverrideUrlLoadingHelper.getCallCount()); 375 } 376 377 @SmallTest 378 @Feature({"AndroidWebView", "Navigation"}) 379 public void testCalledWhenLinkClicked() throws Throwable { 380 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 381 final AwTestContainerView testContainerView = 382 createAwTestContainerViewOnMainSync(contentsClient); 383 final AwContents awContents = testContainerView.getAwContents(); 384 TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 385 contentsClient.getShouldOverrideUrlLoadingHelper(); 386 387 // We can't go to about:blank from here because we'd get a cross-origin error. 388 loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), 389 getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false); 390 391 int callCount = shouldOverrideUrlLoadingHelper.getCallCount(); 392 393 clickOnLinkUsingJs(awContents, contentsClient); 394 395 shouldOverrideUrlLoadingHelper.waitForCallback(callCount); 396 } 397 398 399 @SmallTest 400 @Feature({"AndroidWebView", "Navigation"}) 401 public void testCalledWhenSelfLinkClicked() throws Throwable { 402 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 403 final AwTestContainerView testContainerView = 404 createAwTestContainerViewOnMainSync(contentsClient); 405 final AwContents awContents = testContainerView.getAwContents(); 406 TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 407 contentsClient.getShouldOverrideUrlLoadingHelper(); 408 409 final String httpPath = "/page_with_link_to_self.html"; 410 final String httpPathOnServer = mWebServer.getResponseUrl(httpPath); 411 addPageToTestServer(mWebServer, httpPath, 412 getHtmlForPageWithSimpleLinkTo(httpPathOnServer)); 413 414 loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), 415 httpPathOnServer); 416 417 int callCount = shouldOverrideUrlLoadingHelper.getCallCount(); 418 419 clickOnLinkUsingJs(awContents, contentsClient); 420 421 shouldOverrideUrlLoadingHelper.waitForCallback(callCount); 422 assertEquals(httpPathOnServer, 423 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl()); 424 } 425 426 @SmallTest 427 @Feature({"AndroidWebView", "Navigation"}) 428 public void testCalledWhenNavigatingFromJavaScriptUsingAssign() 429 throws Throwable { 430 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 431 final AwTestContainerView testContainerView = 432 createAwTestContainerViewOnMainSync(contentsClient); 433 final AwContents awContents = testContainerView.getAwContents(); 434 enableJavaScriptOnUiThread(awContents); 435 TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 436 contentsClient.getShouldOverrideUrlLoadingHelper(); 437 438 final String redirectTargetUrl = createRedirectTargetPage(mWebServer); 439 loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), 440 getHtmlForPageWithJsAssignLinkTo(redirectTargetUrl), "text/html", false); 441 442 int callCount = shouldOverrideUrlLoadingHelper.getCallCount(); 443 444 clickOnLinkUsingJs(awContents, contentsClient); 445 446 shouldOverrideUrlLoadingHelper.waitForCallback(callCount); 447 } 448 449 @SmallTest 450 @Feature({"AndroidWebView", "Navigation"}) 451 public void testCalledWhenNavigatingFromJavaScriptUsingReplace() 452 throws Throwable { 453 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 454 final AwTestContainerView testContainerView = 455 createAwTestContainerViewOnMainSync(contentsClient); 456 final AwContents awContents = testContainerView.getAwContents(); 457 enableJavaScriptOnUiThread(awContents); 458 TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 459 contentsClient.getShouldOverrideUrlLoadingHelper(); 460 461 final String redirectTargetUrl = createRedirectTargetPage(mWebServer); 462 loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), 463 getHtmlForPageWithJsReplaceLinkTo(redirectTargetUrl), "text/html", false); 464 465 int callCount = shouldOverrideUrlLoadingHelper.getCallCount(); 466 clickOnLinkUsingJs(awContents, contentsClient); 467 shouldOverrideUrlLoadingHelper.waitForCallback(callCount); 468 } 469 470 @SmallTest 471 @Feature({"AndroidWebView", "Navigation"}) 472 public void testPassesCorrectUrl() throws Throwable { 473 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 474 final AwTestContainerView testContainerView = 475 createAwTestContainerViewOnMainSync(contentsClient); 476 final AwContents awContents = testContainerView.getAwContents(); 477 TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 478 contentsClient.getShouldOverrideUrlLoadingHelper(); 479 480 final String redirectTargetUrl = createRedirectTargetPage(mWebServer); 481 loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), 482 getHtmlForPageWithSimpleLinkTo(redirectTargetUrl), "text/html", false); 483 484 int callCount = shouldOverrideUrlLoadingHelper.getCallCount(); 485 clickOnLinkUsingJs(awContents, contentsClient); 486 shouldOverrideUrlLoadingHelper.waitForCallback(callCount); 487 assertEquals(redirectTargetUrl, 488 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl()); 489 } 490 491 @SmallTest 492 @Feature({"AndroidWebView", "Navigation"}) 493 public void testCanIgnoreLoading() throws Throwable { 494 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 495 final AwTestContainerView testContainerView = 496 createAwTestContainerViewOnMainSync(contentsClient); 497 final AwContents awContents = testContainerView.getAwContents(); 498 final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 499 contentsClient.getShouldOverrideUrlLoadingHelper(); 500 501 final String redirectTargetUrl = createRedirectTargetPage(mWebServer); 502 final String pageWithLinkToIgnorePath = "/page_with_link_to_ignore.html"; 503 final String pageWithLinkToIgnoreUrl = addPageToTestServer(mWebServer, 504 pageWithLinkToIgnorePath, 505 getHtmlForPageWithSimpleLinkTo(redirectTargetUrl)); 506 final String synchronizationPath = "/sync.html"; 507 final String synchronizationUrl = addPageToTestServer(mWebServer, 508 synchronizationPath, 509 getHtmlForPageWithSimpleLinkTo(redirectTargetUrl)); 510 511 loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), 512 pageWithLinkToIgnoreUrl); 513 514 setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, true); 515 516 int callCount = shouldOverrideUrlLoadingHelper.getCallCount(); 517 clickOnLinkUsingJs(awContents, contentsClient); 518 // Some time around here true should be returned from the shouldOverrideUrlLoading 519 // callback causing the navigation caused by calling clickOnLinkUsingJs to be ignored. 520 // We validate this by checking which pages were loaded on the server. 521 shouldOverrideUrlLoadingHelper.waitForCallback(callCount); 522 523 setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, false); 524 525 loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), synchronizationUrl); 526 527 assertEquals(1, mWebServer.getRequestCount(pageWithLinkToIgnorePath)); 528 assertEquals(1, mWebServer.getRequestCount(synchronizationPath)); 529 assertEquals(0, mWebServer.getRequestCount(REDIRECT_TARGET_PATH)); 530 } 531 532 @SmallTest 533 @Feature({"AndroidWebView", "Navigation"}) 534 public void testCalledForDataUrl() throws Throwable { 535 final String dataUrl = 536 "data:text/html;base64," + 537 "PGh0bWw+PGhlYWQ+PHRpdGxlPmRhdGFVcmxUZXN0QmFzZTY0PC90aXRsZT48" + 538 "L2hlYWQ+PC9odG1sPg=="; 539 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 540 final AwTestContainerView testContainerView = 541 createAwTestContainerViewOnMainSync(contentsClient); 542 final AwContents awContents = testContainerView.getAwContents(); 543 TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 544 contentsClient.getShouldOverrideUrlLoadingHelper(); 545 loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), 546 getHtmlForPageWithSimpleLinkTo(dataUrl), "text/html", false); 547 548 int callCount = shouldOverrideUrlLoadingHelper.getCallCount(); 549 clickOnLinkUsingJs(awContents, contentsClient); 550 551 shouldOverrideUrlLoadingHelper.waitForCallback(callCount); 552 assertTrue("Expected URL that starts with 'data:' but got: <" + 553 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl() + "> instead.", 554 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl().startsWith( 555 "data:")); 556 } 557 558 @SmallTest 559 @Feature({"AndroidWebView", "Navigation"}) 560 public void testCalledForUnsupportedSchemes() throws Throwable { 561 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 562 final AwTestContainerView testContainerView = 563 createAwTestContainerViewOnMainSync(contentsClient); 564 final AwContents awContents = testContainerView.getAwContents(); 565 TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 566 contentsClient.getShouldOverrideUrlLoadingHelper(); 567 final String unsupportedSchemeUrl = "foobar://resource/1"; 568 loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), 569 getHtmlForPageWithSimpleLinkTo(unsupportedSchemeUrl), "text/html", false); 570 571 int callCount = shouldOverrideUrlLoadingHelper.getCallCount(); 572 clickOnLinkUsingJs(awContents, contentsClient); 573 574 shouldOverrideUrlLoadingHelper.waitForCallback(callCount); 575 assertEquals(unsupportedSchemeUrl, 576 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl()); 577 } 578 579 @SmallTest 580 @Feature({"AndroidWebView", "Navigation"}) 581 public void testNotCalledForPostNavigations() throws Throwable { 582 // The reason POST requests are excluded is BUG 155250. 583 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 584 final AwTestContainerView testContainerView = 585 createAwTestContainerViewOnMainSync(contentsClient); 586 final AwContents awContents = testContainerView.getAwContents(); 587 final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 588 contentsClient.getShouldOverrideUrlLoadingHelper(); 589 590 final String redirectTargetUrl = createRedirectTargetPage(mWebServer); 591 final String postLinkUrl = addPageToTestServer(mWebServer, "/page_with_post_link.html", 592 getHtmlForPageWithSimplePostFormTo(redirectTargetUrl)); 593 594 loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), postLinkUrl); 595 596 final int shouldOverrideUrlLoadingCallCount = 597 shouldOverrideUrlLoadingHelper.getCallCount(); 598 599 assertEquals(0, mWebServer.getRequestCount(REDIRECT_TARGET_PATH)); 600 clickOnLinkUsingJs(awContents, contentsClient); 601 602 // Wait for the target URL to be fetched from the server. 603 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { 604 @Override 605 public boolean isSatisfied() { 606 return mWebServer.getRequestCount(REDIRECT_TARGET_PATH) == 1; 607 } 608 }, WAIT_TIMEOUT_SECONDS * 1000L, CHECK_INTERVAL)); 609 610 // Since the targetURL was loaded from the test server it means all processing related 611 // to dispatching a shouldOverrideUrlLoading callback had finished and checking the call 612 // is stable. 613 assertEquals(shouldOverrideUrlLoadingCallCount, 614 shouldOverrideUrlLoadingHelper.getCallCount()); 615 } 616 617 @SmallTest 618 @Feature({"AndroidWebView", "Navigation"}) 619 public void testCalledFor302AfterPostNavigations() throws Throwable { 620 // The reason POST requests are excluded is BUG 155250. 621 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 622 final AwTestContainerView testContainerView = 623 createAwTestContainerViewOnMainSync(contentsClient); 624 final AwContents awContents = testContainerView.getAwContents(); 625 final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 626 contentsClient.getShouldOverrideUrlLoadingHelper(); 627 628 final String redirectTargetUrl = createRedirectTargetPage(mWebServer); 629 final String postToGetRedirectUrl = mWebServer.setRedirect("/302.html", redirectTargetUrl); 630 final String postLinkUrl = addPageToTestServer(mWebServer, "/page_with_post_link.html", 631 getHtmlForPageWithSimplePostFormTo(postToGetRedirectUrl)); 632 633 loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), postLinkUrl); 634 635 final int shouldOverrideUrlLoadingCallCount = 636 shouldOverrideUrlLoadingHelper.getCallCount(); 637 638 clickOnLinkUsingJs(awContents, contentsClient); 639 640 shouldOverrideUrlLoadingHelper.waitForCallback(shouldOverrideUrlLoadingCallCount); 641 642 // Wait for the target URL to be fetched from the server. 643 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { 644 @Override 645 public boolean isSatisfied() { 646 return mWebServer.getRequestCount(REDIRECT_TARGET_PATH) == 1; 647 } 648 }, WAIT_TIMEOUT_SECONDS * 1000L, CHECK_INTERVAL)); 649 650 assertEquals(redirectTargetUrl, 651 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl()); 652 } 653 654 @SmallTest 655 @Feature({"AndroidWebView", "Navigation"}) 656 public void testNotCalledForIframeHttpNavigations() throws Throwable { 657 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 658 final AwTestContainerView testContainerView = 659 createAwTestContainerViewOnMainSync(contentsClient); 660 final AwContents awContents = testContainerView.getAwContents(); 661 final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 662 contentsClient.getShouldOverrideUrlLoadingHelper(); 663 664 final String iframeRedirectTargetUrl = createRedirectTargetPage(mWebServer); 665 final String iframeRedirectUrl = 666 mWebServer.setRedirect("/302.html", iframeRedirectTargetUrl); 667 final String pageWithIframeUrl = 668 addPageToTestServer(mWebServer, "/iframe_intercept.html", 669 makeHtmlPageFrom("", "<iframe src=\"" + iframeRedirectUrl + "\" />")); 670 671 final int shouldOverrideUrlLoadingCallCount = 672 shouldOverrideUrlLoadingHelper.getCallCount(); 673 674 assertEquals(0, mWebServer.getRequestCount(REDIRECT_TARGET_PATH)); 675 loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), pageWithIframeUrl); 676 677 // Wait for the redirect target URL to be fetched from the server. 678 assertTrue(CriteriaHelper.pollForCriteria(new Criteria() { 679 @Override 680 public boolean isSatisfied() { 681 return mWebServer.getRequestCount(REDIRECT_TARGET_PATH) == 1; 682 } 683 }, WAIT_TIMEOUT_SECONDS * 1000L, CHECK_INTERVAL)); 684 685 assertEquals(shouldOverrideUrlLoadingCallCount, 686 shouldOverrideUrlLoadingHelper.getCallCount()); 687 } 688 689 @SmallTest 690 @Feature({"AndroidWebView", "Navigation"}) 691 public void testCalledForIframeUnsupportedSchemeNavigations() throws Throwable { 692 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 693 final AwTestContainerView testContainerView = 694 createAwTestContainerViewOnMainSync(contentsClient); 695 final AwContents awContents = testContainerView.getAwContents(); 696 final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 697 contentsClient.getShouldOverrideUrlLoadingHelper(); 698 699 final String unsupportedSchemeUrl = "foobar://resource/1"; 700 final String pageWithIframeUrl = 701 addPageToTestServer(mWebServer, "/iframe_intercept.html", 702 makeHtmlPageFrom("", "<iframe src=\"" + unsupportedSchemeUrl + "\" />")); 703 704 final int shouldOverrideUrlLoadingCallCount = 705 shouldOverrideUrlLoadingHelper.getCallCount(); 706 707 loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), pageWithIframeUrl); 708 709 shouldOverrideUrlLoadingHelper.waitForCallback(shouldOverrideUrlLoadingCallCount); 710 assertEquals(unsupportedSchemeUrl, 711 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl()); 712 } 713 714 /** 715 * Worker method for the various redirect tests. 716 * 717 * Calling this will first load the redirect URL built from redirectFilePath, query and 718 * locationFilePath and assert that we get a override callback for the destination. 719 * The second part of the test loads a page that contains a link which points at the redirect 720 * URL. We expect two callbacks - one for the redirect link and another for the destination. 721 */ 722 private void doTestCalledOnRedirect(TestWebServer webServer, 723 String redirectUrl, String redirectTarget) throws Throwable { 724 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 725 final AwTestContainerView testContainerView = 726 createAwTestContainerViewOnMainSync(contentsClient); 727 final AwContents awContents = testContainerView.getAwContents(); 728 final String pageWithLinkToRedirectUrl = addPageToTestServer(webServer, 729 "/page_with_link_to_redirect.html", 730 getHtmlForPageWithSimpleLinkTo(redirectUrl)); 731 enableJavaScriptOnUiThread(awContents); 732 733 TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 734 contentsClient.getShouldOverrideUrlLoadingHelper(); 735 int directLoadCallCount = shouldOverrideUrlLoadingHelper.getCallCount(); 736 loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), redirectUrl); 737 738 shouldOverrideUrlLoadingHelper.waitForCallback(directLoadCallCount, 1); 739 assertEquals(redirectTarget, 740 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl()); 741 742 // There is a slight difference between navigations caused by calling load and navigations 743 // caused by clicking on a link: 744 // * when using load the navigation is treated as if it came from the URL bar (has the 745 // navigation type TYPED and doesn't have the has_user_gesture flag) 746 // * when clicking on a link the navigation has the LINK type and has_user_gesture is 747 // true. 748 // Both of these should yield the same result which is what we're verifying here. 749 int indirectLoadCallCount = shouldOverrideUrlLoadingHelper.getCallCount(); 750 loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), 751 pageWithLinkToRedirectUrl); 752 753 assertEquals(indirectLoadCallCount, shouldOverrideUrlLoadingHelper.getCallCount()); 754 755 clickOnLinkUsingJs(awContents, contentsClient); 756 757 shouldOverrideUrlLoadingHelper.waitForCallback(indirectLoadCallCount, 2); 758 assertEquals(redirectTarget, 759 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl()); 760 assertEquals(redirectUrl, 761 shouldOverrideUrlLoadingHelper.getPreviousShouldOverrideUrlLoadingUrl()); 762 } 763 764 @SmallTest 765 @Feature({"AndroidWebView", "Navigation"}) 766 public void testCalledOn302Redirect() throws Throwable { 767 final String redirectTargetUrl = createRedirectTargetPage(mWebServer); 768 final String redirectUrl = mWebServer.setRedirect("/302.html", redirectTargetUrl); 769 770 doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl); 771 } 772 773 @SmallTest 774 @Feature({"AndroidWebView", "Navigation"}) 775 public void testCalledOnMetaRefreshRedirect() throws Throwable { 776 final String redirectTargetUrl = createRedirectTargetPage(mWebServer); 777 final String redirectUrl = addPageToTestServer(mWebServer, "/meta_refresh.html", 778 getHtmlForPageWithMetaRefreshRedirectTo(redirectTargetUrl)); 779 doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl); 780 } 781 782 783 @SmallTest 784 @Feature({"AndroidWebView", "Navigation"}) 785 public void testCalledOnJavaScriptLocationImmediateAssignRedirect() 786 throws Throwable { 787 final String redirectTargetUrl = createRedirectTargetPage(mWebServer); 788 final String redirectUrl = addPageToTestServer(mWebServer, "/js_immediate_assign.html", 789 getHtmlForPageWithJsRedirectTo(redirectTargetUrl, "Assign", 0)); 790 doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl); 791 } 792 793 @SmallTest 794 @Feature({"AndroidWebView", "Navigation"}) 795 public void testCalledOnJavaScriptLocationImmediateReplaceRedirect() 796 throws Throwable { 797 final String redirectTargetUrl = createRedirectTargetPage(mWebServer); 798 final String redirectUrl = addPageToTestServer(mWebServer, "/js_immediate_replace.html", 799 getHtmlForPageWithJsRedirectTo(redirectTargetUrl, "Replace", 0)); 800 doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl); 801 } 802 803 @SmallTest 804 @Feature({"AndroidWebView", "Navigation"}) 805 public void testCalledOnJavaScriptLocationDelayedAssignRedirect() 806 throws Throwable { 807 final String redirectTargetUrl = createRedirectTargetPage(mWebServer); 808 final String redirectUrl = addPageToTestServer(mWebServer, "/js_delayed_assign.html", 809 getHtmlForPageWithJsRedirectTo(redirectTargetUrl, "Assign", 100)); 810 doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl); 811 } 812 813 @SmallTest 814 @Feature({"AndroidWebView", "Navigation"}) 815 public void testCalledOnJavaScriptLocationDelayedReplaceRedirect() 816 throws Throwable { 817 final String redirectTargetUrl = createRedirectTargetPage(mWebServer); 818 final String redirectUrl = addPageToTestServer(mWebServer, "/js_delayed_replace.html", 819 getHtmlForPageWithJsRedirectTo(redirectTargetUrl, "Replace", 100)); 820 doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl); 821 } 822 823 @SmallTest 824 @Feature({"AndroidWebView", "Navigation"}) 825 public void testDoubleNavigateDoesNotSuppressInitialNavigate() throws Throwable { 826 final String jsUrl = "javascript:try{console.log('processed js loadUrl');}catch(e){};"; 827 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 828 final AwTestContainerView testContainerView = 829 createAwTestContainerViewOnMainSync(contentsClient); 830 final AwContents awContents = testContainerView.getAwContents(); 831 TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = 832 contentsClient.getShouldOverrideUrlLoadingHelper(); 833 834 // Do a double navigagtion, the second being an effective no-op, in quick succession (i.e. 835 // without yielding the main thread inbetween). 836 int currentCallCount = contentsClient.getOnPageFinishedHelper().getCallCount(); 837 getInstrumentation().runOnMainSync(new Runnable() { 838 @Override 839 public void run() { 840 awContents.loadUrl(LoadUrlParams.createLoadDataParams( 841 getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false)); 842 awContents.loadUrl(new LoadUrlParams(jsUrl)); 843 } 844 }); 845 contentsClient.getOnPageFinishedHelper().waitForCallback(currentCallCount, 1, 846 WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS); 847 848 assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount()); 849 } 850} 851