blob: 5d0e5ce40c3a7272a10ff1053c62d2e13453b544 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.android_webview.test;
import android.os.Bundle;
import android.os.SystemClock;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Pair;
import android.view.MotionEvent;
import android.util.Log;
import org.chromium.android_webview.AwContents;
import org.chromium.android_webview.test.util.CommonResources;
import org.chromium.android_webview.test.util.JSUtils;
import org.chromium.base.test.util.Feature;
import org.chromium.content.browser.NavigationHistory;
import org.chromium.content.browser.LoadUrlParams;
import org.chromium.content.browser.test.util.CallbackHelper;
import org.chromium.content.browser.test.util.Criteria;
import org.chromium.content.browser.test.util.CriteriaHelper;
import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper;
import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageStartedHelper;
import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnReceivedErrorHelper;
import org.chromium.net.test.util.TestWebServer;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
/**
* Tests for the WebViewClient.shouldOverrideUrlLoading() method.
*/
public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase {
private final static String ABOUT_BLANK_URL = "about:blank";
private final static String DATA_URL = "data:text/html,<div/>";
private final static String REDIRECT_TARGET_PATH = "/redirect_target.html";
private final static String TITLE = "TITLE";
private static final long TEST_TIMEOUT = 20000L;
private static final long CHECK_INTERVAL = 100;
private static class TestAwContentsClient
extends org.chromium.android_webview.test.TestAwContentsClient {
public static class ShouldOverrideUrlLoadingHelper extends CallbackHelper {
private String mShouldOverrideUrlLoadingUrl;
private String mPreviousShouldOverrideUrlLoadingUrl;
private boolean mShouldOverrideUrlLoadingReturnValue = false;
void setShouldOverrideUrlLoadingUrl(String url) {
mShouldOverrideUrlLoadingUrl = url;
}
void setPreviousShouldOverrideUrlLoadingUrl(String url) {
mPreviousShouldOverrideUrlLoadingUrl = url;
}
void setShouldOverrideUrlLoadingReturnValue(boolean value) {
mShouldOverrideUrlLoadingReturnValue = value;
}
public String getShouldOverrideUrlLoadingUrl() {
assert getCallCount() > 0;
return mShouldOverrideUrlLoadingUrl;
}
public String getPreviousShouldOverrideUrlLoadingUrl() {
assert getCallCount() > 1;
return mPreviousShouldOverrideUrlLoadingUrl;
}
public boolean getShouldOverrideUrlLoadingReturnValue() {
return mShouldOverrideUrlLoadingReturnValue;
}
public void notifyCalled(String url) {
mPreviousShouldOverrideUrlLoadingUrl = mShouldOverrideUrlLoadingUrl;
mShouldOverrideUrlLoadingUrl = url;
notifyCalled();
}
}
@Override
public boolean shouldOverrideUrlLoading(String url) {
super.shouldOverrideUrlLoading(url);
boolean returnValue =
mShouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingReturnValue();
mShouldOverrideUrlLoadingHelper.notifyCalled(url);
return returnValue;
}
private ShouldOverrideUrlLoadingHelper mShouldOverrideUrlLoadingHelper;
public TestAwContentsClient() {
mShouldOverrideUrlLoadingHelper = new ShouldOverrideUrlLoadingHelper();
}
public ShouldOverrideUrlLoadingHelper getShouldOverrideUrlLoadingHelper() {
return mShouldOverrideUrlLoadingHelper;
}
}
private TestWebServer mWebServer;
@Override
protected void setUp() throws Exception {
super.setUp();
mWebServer = new TestWebServer(false);
}
@Override
protected void tearDown() throws Exception {
mWebServer.shutdown();
super.tearDown();
}
private void clickOnLinkUsingJs(final AwContents awContents,
final TestAwContentsClient contentsClient) throws Throwable {
enableJavaScriptOnUiThread(awContents);
JSUtils.clickOnLinkUsingJs(this, awContents,
contentsClient.getOnEvaluateJavaScriptResultHelper(), "link");
}
// Since this value is read on the UI thread, it's simpler to set it there too.
void setShouldOverrideUrlLoadingReturnValueOnUiThread(
final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideHelper,
final boolean value) throws Throwable {
runTestOnUiThread(new Runnable() {
@Override
public void run() {
shouldOverrideHelper.setShouldOverrideUrlLoadingReturnValue(value);
}
});
}
private String makeHtmlPageFrom(String headers, String body) {
return CommonResources.makeHtmlPageFrom("<title>" + TITLE + "</title> " + headers, body);
}
private String getHtmlForPageWithSimpleLinkTo(String destination) {
return makeHtmlPageFrom("",
"<a href=\"" + destination + "\" id=\"link\">" +
"<img class=\"big\" />" +
"</a>");
}
private String getHtmlForPageWithJsAssignLinkTo(String url) {
return makeHtmlPageFrom("",
"<img onclick=\"location.href='" + url + "'\" class=\"big\" id=\"link\" />");
}
private String getHtmlForPageWithJsReplaceLinkTo(String url) {
return makeHtmlPageFrom("",
"<img onclick=\"location.replace('" + url + "');\" class=\"big\" id=\"link\" />");
}
private String getHtmlForPageWithMetaRefreshRedirectTo(String url) {
return makeHtmlPageFrom("<meta http-equiv=\"refresh\" content=\"0;url=" + url + "\" />",
"<div>Meta refresh redirect</div>");
}
private String getHtmlForPageWithJsRedirectTo(String url, String method, int timeout) {
return makeHtmlPageFrom(
"<script>" +
"function doRedirectAssign() {" +
"location.href = '" + url + "';" +
"} " +
"function doRedirectReplace() {" +
"location.replace('" + url + "');" +
"} "+
"</script>",
String.format("<iframe onLoad=\"setTimeout('doRedirect%s()', %d);\" />",
method, timeout));
}
private String getHtmlForPageWithSimplePostFormTo(String destination) {
return makeHtmlPageFrom("",
"<form action=\"" + destination + "\" method=\"post\">" +
"<input type=\"submit\" value=\"post\" id=\"link\">"+
"</form>");
}
private String addPageToTestServer(TestWebServer webServer, String httpPath, String html) {
List<Pair<String, String>> headers = new ArrayList<Pair<String, String>>();
headers.add(Pair.create("Content-Type", "text/html"));
headers.add(Pair.create("Cache-Control", "no-store"));
return webServer.setResponse(httpPath, html, headers);
}
private String createRedirectTargetPage(TestWebServer webServer) {
return addPageToTestServer(webServer, REDIRECT_TARGET_PATH,
makeHtmlPageFrom("", "<div>This is the end of the redirect chain</div>"));
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testNotCalledOnLoadUrl() throws Throwable {
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false);
assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount());
}
private void waitForNavigationRunnableAndAssertTitleChanged(AwContents awContents,
CallbackHelper onPageFinishedHelper,
Runnable navigationRunnable) throws Exception {
final int callCount = onPageFinishedHelper.getCallCount();
final String oldTitle = getTitleOnUiThread(awContents);
getInstrumentation().runOnMainSync(navigationRunnable);
onPageFinishedHelper.waitForCallback(callCount);
assertFalse(oldTitle.equals(getTitleOnUiThread(awContents)));
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testNotCalledOnBackForwardNavigation() throws Throwable {
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
final String[] pageTitles = new String[] { "page1", "page2", "page3" };
for (String title: pageTitles) {
loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
CommonResources.makeHtmlPageFrom("<title>" + title + "</title>", ""),
"text/html", false);
}
assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount());
waitForNavigationRunnableAndAssertTitleChanged(awContents,
contentsClient.getOnPageFinishedHelper(), new Runnable() {
@Override
public void run() {
awContents.goBack();
}
});
assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount());
waitForNavigationRunnableAndAssertTitleChanged(awContents,
contentsClient.getOnPageFinishedHelper(), new Runnable() {
@Override
public void run() {
awContents.goForward();
}
});
assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount());
waitForNavigationRunnableAndAssertTitleChanged(awContents,
contentsClient.getOnPageFinishedHelper(), new Runnable() {
@Override
public void run() {
awContents.goBackOrForward(-2);
}
});
assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount());
waitForNavigationRunnableAndAssertTitleChanged(awContents,
contentsClient.getOnPageFinishedHelper(), new Runnable() {
@Override
public void run() {
awContents.goBackOrForward(1);
}
});
assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount());
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testCantBlockLoads() throws Throwable {
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, true);
loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false);
assertEquals(TITLE, getTitleOnUiThread(awContents));
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testCalledBeforeOnPageStarted() throws Throwable {
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
OnPageStartedHelper onPageStartedHelper = contentsClient.getOnPageStartedHelper();
loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false);
final int shouldOverrideUrlLoadingCallCount = shouldOverrideUrlLoadingHelper.getCallCount();
final int onPageStartedCallCount = onPageStartedHelper.getCallCount();
setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, true);
clickOnLinkUsingJs(awContents, contentsClient);
shouldOverrideUrlLoadingHelper.waitForCallback(shouldOverrideUrlLoadingCallCount);
assertEquals(onPageStartedCallCount, onPageStartedHelper.getCallCount());
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testDoesNotCauseOnReceivedError() throws Throwable {
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
OnReceivedErrorHelper onReceivedErrorHelper = contentsClient.getOnReceivedErrorHelper();
final int onReceivedErrorCallCount = onReceivedErrorHelper.getCallCount();
loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false);
final int shouldOverrideUrlLoadingCallCount = shouldOverrideUrlLoadingHelper.getCallCount();
setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, true);
clickOnLinkUsingJs(awContents, contentsClient);
shouldOverrideUrlLoadingHelper.waitForCallback(shouldOverrideUrlLoadingCallCount);
setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, false);
// After we load this URL we're certain that any in-flight callbacks for the previous
// navigation have been delivered.
loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), ABOUT_BLANK_URL);
assertEquals(onReceivedErrorCallCount, onReceivedErrorHelper.getCallCount());
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testNotCalledForAnchorNavigations() throws Throwable {
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
final String anchorLinkPath = "/anchor_link.html";
final String anchorLinkUrl = mWebServer.getResponseUrl(anchorLinkPath);
addPageToTestServer(mWebServer, anchorLinkPath,
getHtmlForPageWithSimpleLinkTo(anchorLinkUrl + "#anchor"));
loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), anchorLinkUrl);
final int shouldOverrideUrlLoadingCallCount =
shouldOverrideUrlLoadingHelper.getCallCount();
clickOnLinkUsingJs(awContents, contentsClient);
// After we load this URL we're certain that any in-flight callbacks for the previous
// navigation have been delivered.
loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), ABOUT_BLANK_URL);
assertEquals(shouldOverrideUrlLoadingCallCount,
shouldOverrideUrlLoadingHelper.getCallCount());
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testCalledWhenLinkClicked() throws Throwable {
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
// We can't go to about:blank from here because we'd get a cross-origin error.
loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false);
int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
clickOnLinkUsingJs(awContents, contentsClient);
shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testCalledWhenSelfLinkClicked() throws Throwable {
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
final String httpPath = "/page_with_link_to_self.html";
final String httpPathOnServer = mWebServer.getResponseUrl(httpPath);
addPageToTestServer(mWebServer, httpPath,
getHtmlForPageWithSimpleLinkTo(httpPathOnServer));
loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(),
httpPathOnServer);
int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
clickOnLinkUsingJs(awContents, contentsClient);
shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
assertEquals(httpPathOnServer,
shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testCalledWhenNavigatingFromJavaScriptUsingAssign()
throws Throwable {
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
enableJavaScriptOnUiThread(awContents);
TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
getHtmlForPageWithJsAssignLinkTo(redirectTargetUrl), "text/html", false);
int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
clickOnLinkUsingJs(awContents, contentsClient);
shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testCalledWhenNavigatingFromJavaScriptUsingReplace()
throws Throwable {
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
enableJavaScriptOnUiThread(awContents);
TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
getHtmlForPageWithJsReplaceLinkTo(redirectTargetUrl), "text/html", false);
int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
clickOnLinkUsingJs(awContents, contentsClient);
shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testPassesCorrectUrl() throws Throwable {
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
getHtmlForPageWithSimpleLinkTo(redirectTargetUrl), "text/html", false);
int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
clickOnLinkUsingJs(awContents, contentsClient);
shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
assertEquals(redirectTargetUrl,
shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testCanIgnoreLoading() throws Throwable {
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
final String pageWithLinkToIgnorePath = "/page_with_link_to_ignore.html";
final String pageWithLinkToIgnoreUrl = addPageToTestServer(mWebServer,
pageWithLinkToIgnorePath,
getHtmlForPageWithSimpleLinkTo(redirectTargetUrl));
final String synchronizationPath = "/sync.html";
final String synchronizationUrl = addPageToTestServer(mWebServer,
synchronizationPath,
getHtmlForPageWithSimpleLinkTo(redirectTargetUrl));
loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(),
pageWithLinkToIgnoreUrl);
setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, true);
int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
clickOnLinkUsingJs(awContents, contentsClient);
// Some time around here true should be returned from the shouldOverrideUrlLoading
// callback causing the navigation caused by calling clickOnLinkUsingJs to be ignored.
// We validate this by checking which pages were loaded on the server.
shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, false);
loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), synchronizationUrl);
assertEquals(1, mWebServer.getRequestCount(pageWithLinkToIgnorePath));
assertEquals(1, mWebServer.getRequestCount(synchronizationPath));
assertEquals(0, mWebServer.getRequestCount(REDIRECT_TARGET_PATH));
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testCalledForDataUrl() throws Throwable {
final String dataUrl =
"data:text/html;base64," +
"PGh0bWw+PGhlYWQ+PHRpdGxlPmRhdGFVcmxUZXN0QmFzZTY0PC90aXRsZT48" +
"L2hlYWQ+PC9odG1sPg==";
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
getHtmlForPageWithSimpleLinkTo(dataUrl), "text/html", false);
int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
clickOnLinkUsingJs(awContents, contentsClient);
shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
assertTrue("Expected URL that starts with 'data:' but got: <" +
shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl() + "> instead.",
shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl().startsWith(
"data:"));
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testCalledForUnsupportedSchemes() throws Throwable {
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
final String unsupportedSchemeUrl = "foobar://resource/1";
loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
getHtmlForPageWithSimpleLinkTo(unsupportedSchemeUrl), "text/html", false);
int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
clickOnLinkUsingJs(awContents, contentsClient);
shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
assertEquals(unsupportedSchemeUrl,
shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testNotCalledForPostNavigations() throws Throwable {
// The reason POST requests are excluded is BUG 155250.
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
final String postLinkUrl = addPageToTestServer(mWebServer, "/page_with_post_link.html",
getHtmlForPageWithSimplePostFormTo(redirectTargetUrl));
loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), postLinkUrl);
final int shouldOverrideUrlLoadingCallCount =
shouldOverrideUrlLoadingHelper.getCallCount();
assertEquals(0, mWebServer.getRequestCount(REDIRECT_TARGET_PATH));
clickOnLinkUsingJs(awContents, contentsClient);
// Wait for the target URL to be fetched from the server.
assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
@Override
public boolean isSatisfied() {
return mWebServer.getRequestCount(REDIRECT_TARGET_PATH) == 1;
}
}, WAIT_TIMEOUT_SECONDS * 1000L, CHECK_INTERVAL));
// Since the targetURL was loaded from the test server it means all processing related
// to dispatching a shouldOverrideUrlLoading callback had finished and checking the call
// is stable.
assertEquals(shouldOverrideUrlLoadingCallCount,
shouldOverrideUrlLoadingHelper.getCallCount());
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testCalledFor302AfterPostNavigations() throws Throwable {
// The reason POST requests are excluded is BUG 155250.
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
final String postToGetRedirectUrl = mWebServer.setRedirect("/302.html", redirectTargetUrl);
final String postLinkUrl = addPageToTestServer(mWebServer, "/page_with_post_link.html",
getHtmlForPageWithSimplePostFormTo(postToGetRedirectUrl));
loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), postLinkUrl);
final int shouldOverrideUrlLoadingCallCount =
shouldOverrideUrlLoadingHelper.getCallCount();
clickOnLinkUsingJs(awContents, contentsClient);
shouldOverrideUrlLoadingHelper.waitForCallback(shouldOverrideUrlLoadingCallCount);
// Wait for the target URL to be fetched from the server.
assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
@Override
public boolean isSatisfied() {
return mWebServer.getRequestCount(REDIRECT_TARGET_PATH) == 1;
}
}, WAIT_TIMEOUT_SECONDS * 1000L, CHECK_INTERVAL));
assertEquals(redirectTargetUrl,
shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testNotCalledForIframeHttpNavigations() throws Throwable {
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
final String iframeRedirectTargetUrl = createRedirectTargetPage(mWebServer);
final String iframeRedirectUrl =
mWebServer.setRedirect("/302.html", iframeRedirectTargetUrl);
final String pageWithIframeUrl =
addPageToTestServer(mWebServer, "/iframe_intercept.html",
makeHtmlPageFrom("", "<iframe src=\"" + iframeRedirectUrl + "\" />"));
final int shouldOverrideUrlLoadingCallCount =
shouldOverrideUrlLoadingHelper.getCallCount();
assertEquals(0, mWebServer.getRequestCount(REDIRECT_TARGET_PATH));
loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), pageWithIframeUrl);
// Wait for the redirect target URL to be fetched from the server.
assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
@Override
public boolean isSatisfied() {
return mWebServer.getRequestCount(REDIRECT_TARGET_PATH) == 1;
}
}, WAIT_TIMEOUT_SECONDS * 1000L, CHECK_INTERVAL));
assertEquals(shouldOverrideUrlLoadingCallCount,
shouldOverrideUrlLoadingHelper.getCallCount());
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testCalledForIframeUnsupportedSchemeNavigations() throws Throwable {
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
final String unsupportedSchemeUrl = "foobar://resource/1";
final String pageWithIframeUrl =
addPageToTestServer(mWebServer, "/iframe_intercept.html",
makeHtmlPageFrom("", "<iframe src=\"" + unsupportedSchemeUrl + "\" />"));
final int shouldOverrideUrlLoadingCallCount =
shouldOverrideUrlLoadingHelper.getCallCount();
loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), pageWithIframeUrl);
shouldOverrideUrlLoadingHelper.waitForCallback(shouldOverrideUrlLoadingCallCount);
assertEquals(unsupportedSchemeUrl,
shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
}
/**
* Worker method for the various redirect tests.
*
* Calling this will first load the redirect URL built from redirectFilePath, query and
* locationFilePath and assert that we get a override callback for the destination.
* The second part of the test loads a page that contains a link which points at the redirect
* URL. We expect two callbacks - one for the redirect link and another for the destination.
*/
private void doTestCalledOnRedirect(TestWebServer webServer,
String redirectUrl, String redirectTarget) throws Throwable {
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
final String pageWithLinkToRedirectUrl = addPageToTestServer(webServer,
"/page_with_link_to_redirect.html",
getHtmlForPageWithSimpleLinkTo(redirectUrl));
enableJavaScriptOnUiThread(awContents);
TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
int directLoadCallCount = shouldOverrideUrlLoadingHelper.getCallCount();
loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), redirectUrl);
shouldOverrideUrlLoadingHelper.waitForCallback(directLoadCallCount, 1);
assertEquals(redirectTarget,
shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
// There is a slight difference between navigations caused by calling load and navigations
// caused by clicking on a link:
// * when using load the navigation is treated as if it came from the URL bar (has the
// navigation type TYPED and doesn't have the has_user_gesture flag)
// * when clicking on a link the navigation has the LINK type and has_user_gesture is
// true.
// Both of these should yield the same result which is what we're verifying here.
int indirectLoadCallCount = shouldOverrideUrlLoadingHelper.getCallCount();
loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(),
pageWithLinkToRedirectUrl);
assertEquals(indirectLoadCallCount, shouldOverrideUrlLoadingHelper.getCallCount());
clickOnLinkUsingJs(awContents, contentsClient);
shouldOverrideUrlLoadingHelper.waitForCallback(indirectLoadCallCount, 2);
assertEquals(redirectTarget,
shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
assertEquals(redirectUrl,
shouldOverrideUrlLoadingHelper.getPreviousShouldOverrideUrlLoadingUrl());
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testCalledOn302Redirect() throws Throwable {
final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
final String redirectUrl = mWebServer.setRedirect("/302.html", redirectTargetUrl);
doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl);
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testCalledOnMetaRefreshRedirect() throws Throwable {
final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
final String redirectUrl = addPageToTestServer(mWebServer, "/meta_refresh.html",
getHtmlForPageWithMetaRefreshRedirectTo(redirectTargetUrl));
doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl);
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testCalledOnJavaScriptLocationImmediateAssignRedirect()
throws Throwable {
final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
final String redirectUrl = addPageToTestServer(mWebServer, "/js_immediate_assign.html",
getHtmlForPageWithJsRedirectTo(redirectTargetUrl, "Assign", 0));
doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl);
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testCalledOnJavaScriptLocationImmediateReplaceRedirect()
throws Throwable {
final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
final String redirectUrl = addPageToTestServer(mWebServer, "/js_immediate_replace.html",
getHtmlForPageWithJsRedirectTo(redirectTargetUrl, "Replace", 0));
doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl);
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testCalledOnJavaScriptLocationDelayedAssignRedirect()
throws Throwable {
final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
final String redirectUrl = addPageToTestServer(mWebServer, "/js_delayed_assign.html",
getHtmlForPageWithJsRedirectTo(redirectTargetUrl, "Assign", 100));
doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl);
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testCalledOnJavaScriptLocationDelayedReplaceRedirect()
throws Throwable {
final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
final String redirectUrl = addPageToTestServer(mWebServer, "/js_delayed_replace.html",
getHtmlForPageWithJsRedirectTo(redirectTargetUrl, "Replace", 100));
doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl);
}
@SmallTest
@Feature({"AndroidWebView", "Navigation"})
public void testDoubleNavigateDoesNotSuppressInitialNavigate() throws Throwable {
final String jsUrl = "javascript:try{console.log('processed js loadUrl');}catch(e){};";
final TestAwContentsClient contentsClient = new TestAwContentsClient();
final AwTestContainerView testContainerView =
createAwTestContainerViewOnMainSync(contentsClient);
final AwContents awContents = testContainerView.getAwContents();
TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
contentsClient.getShouldOverrideUrlLoadingHelper();
// Do a double navigagtion, the second being an effective no-op, in quick succession (i.e.
// without yielding the main thread inbetween).
int currentCallCount = contentsClient.getOnPageFinishedHelper().getCallCount();
getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
awContents.loadUrl(LoadUrlParams.createLoadDataParams(
getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false));
awContents.loadUrl(new LoadUrlParams(jsUrl));
}
});
contentsClient.getOnPageFinishedHelper().waitForCallback(currentCallCount, 1,
WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount());
}
}