- add sources.
[platform/framework/web/crosswalk.git] / src / android_webview / javatests / src / org / chromium / android_webview / test / AwContentsClientShouldOverrideUrlLoadingTest.java
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
5 package org.chromium.android_webview.test;
6
7 import android.os.Bundle;
8 import android.os.SystemClock;
9 import android.test.suitebuilder.annotation.SmallTest;
10 import android.util.Pair;
11 import android.view.MotionEvent;
12 import android.util.Log;
13
14 import org.chromium.android_webview.AwContents;
15 import org.chromium.android_webview.test.util.CommonResources;
16 import org.chromium.android_webview.test.util.JSUtils;
17 import org.chromium.base.test.util.Feature;
18 import org.chromium.content.browser.NavigationHistory;
19 import org.chromium.content.browser.LoadUrlParams;
20 import org.chromium.content.browser.test.util.CallbackHelper;
21 import org.chromium.content.browser.test.util.Criteria;
22 import org.chromium.content.browser.test.util.CriteriaHelper;
23 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper;
24 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageStartedHelper;
25 import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnReceivedErrorHelper;
26 import org.chromium.net.test.util.TestWebServer;
27
28 import java.net.URLEncoder;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.concurrent.Callable;
32 import java.util.concurrent.TimeUnit;
33
34 /**
35  * Tests for the WebViewClient.shouldOverrideUrlLoading() method.
36  */
37 public 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         int onPageFinishedCallCount = contentsClient.getOnPageFinishedHelper().getCallCount();
518         clickOnLinkUsingJs(awContents, contentsClient);
519         // Some time around here true should be returned from the shouldOverrideUrlLoading
520         // callback causing the navigation caused by calling clickOnLinkUsingJs to be ignored.
521         // We validate this by checking which pages were loaded on the server.
522         shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
523
524         setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, false);
525
526         // We need to wait for the navigation to complete before we can initiate another load.
527         contentsClient.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount);
528         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), synchronizationUrl);
529
530         assertEquals(1, mWebServer.getRequestCount(pageWithLinkToIgnorePath));
531         assertEquals(1, mWebServer.getRequestCount(synchronizationPath));
532         assertEquals(0, mWebServer.getRequestCount(REDIRECT_TARGET_PATH));
533     }
534
535     @SmallTest
536     @Feature({"AndroidWebView", "Navigation"})
537     public void testCalledForDataUrl() throws Throwable {
538         final String dataUrl =
539                 "data:text/html;base64," +
540                 "PGh0bWw+PGhlYWQ+PHRpdGxlPmRhdGFVcmxUZXN0QmFzZTY0PC90aXRsZT48" +
541                 "L2hlYWQ+PC9odG1sPg==";
542         final TestAwContentsClient contentsClient = new TestAwContentsClient();
543         final AwTestContainerView testContainerView =
544             createAwTestContainerViewOnMainSync(contentsClient);
545         final AwContents awContents = testContainerView.getAwContents();
546         TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
547                 contentsClient.getShouldOverrideUrlLoadingHelper();
548         loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
549                 getHtmlForPageWithSimpleLinkTo(dataUrl), "text/html", false);
550
551         int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
552         clickOnLinkUsingJs(awContents, contentsClient);
553
554         shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
555         assertTrue("Expected URL that starts with 'data:' but got: <" +
556                    shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl() + "> instead.",
557                    shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl().startsWith(
558                            "data:"));
559     }
560
561     @SmallTest
562     @Feature({"AndroidWebView", "Navigation"})
563     public void testCalledForUnsupportedSchemes() throws Throwable {
564         final TestAwContentsClient contentsClient = new TestAwContentsClient();
565         final AwTestContainerView testContainerView =
566             createAwTestContainerViewOnMainSync(contentsClient);
567         final AwContents awContents = testContainerView.getAwContents();
568         TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
569                 contentsClient.getShouldOverrideUrlLoadingHelper();
570         final String unsupportedSchemeUrl = "foobar://resource/1";
571         loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(),
572                 getHtmlForPageWithSimpleLinkTo(unsupportedSchemeUrl), "text/html", false);
573
574         int callCount = shouldOverrideUrlLoadingHelper.getCallCount();
575         clickOnLinkUsingJs(awContents, contentsClient);
576
577         shouldOverrideUrlLoadingHelper.waitForCallback(callCount);
578         assertEquals(unsupportedSchemeUrl,
579                 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
580     }
581
582     @SmallTest
583     @Feature({"AndroidWebView", "Navigation"})
584     public void testNotCalledForPostNavigations() throws Throwable {
585         // The reason POST requests are excluded is BUG 155250.
586         final TestAwContentsClient contentsClient = new TestAwContentsClient();
587         final AwTestContainerView testContainerView =
588             createAwTestContainerViewOnMainSync(contentsClient);
589         final AwContents awContents = testContainerView.getAwContents();
590         final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
591             contentsClient.getShouldOverrideUrlLoadingHelper();
592
593         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
594         final String postLinkUrl = addPageToTestServer(mWebServer, "/page_with_post_link.html",
595                 getHtmlForPageWithSimplePostFormTo(redirectTargetUrl));
596
597         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), postLinkUrl);
598
599         final int shouldOverrideUrlLoadingCallCount =
600             shouldOverrideUrlLoadingHelper.getCallCount();
601
602         assertEquals(0, mWebServer.getRequestCount(REDIRECT_TARGET_PATH));
603         clickOnLinkUsingJs(awContents, contentsClient);
604
605         // Wait for the target URL to be fetched from the server.
606         assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
607             @Override
608             public boolean isSatisfied() {
609                 return mWebServer.getRequestCount(REDIRECT_TARGET_PATH) == 1;
610             }
611         }, WAIT_TIMEOUT_SECONDS * 1000L, CHECK_INTERVAL));
612
613         // Since the targetURL was loaded from the test server it means all processing related
614         // to dispatching a shouldOverrideUrlLoading callback had finished and checking the call
615         // is stable.
616         assertEquals(shouldOverrideUrlLoadingCallCount,
617                 shouldOverrideUrlLoadingHelper.getCallCount());
618     }
619
620     @SmallTest
621     @Feature({"AndroidWebView", "Navigation"})
622     public void testCalledFor302AfterPostNavigations() throws Throwable {
623         // The reason POST requests are excluded is BUG 155250.
624         final TestAwContentsClient contentsClient = new TestAwContentsClient();
625         final AwTestContainerView testContainerView =
626             createAwTestContainerViewOnMainSync(contentsClient);
627         final AwContents awContents = testContainerView.getAwContents();
628         final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
629             contentsClient.getShouldOverrideUrlLoadingHelper();
630
631         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
632         final String postToGetRedirectUrl = mWebServer.setRedirect("/302.html", redirectTargetUrl);
633         final String postLinkUrl = addPageToTestServer(mWebServer, "/page_with_post_link.html",
634                 getHtmlForPageWithSimplePostFormTo(postToGetRedirectUrl));
635
636         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), postLinkUrl);
637
638         final int shouldOverrideUrlLoadingCallCount =
639             shouldOverrideUrlLoadingHelper.getCallCount();
640
641         clickOnLinkUsingJs(awContents, contentsClient);
642
643         shouldOverrideUrlLoadingHelper.waitForCallback(shouldOverrideUrlLoadingCallCount);
644
645         // Wait for the target URL to be fetched from the server.
646         assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
647             @Override
648             public boolean isSatisfied() {
649                 return mWebServer.getRequestCount(REDIRECT_TARGET_PATH) == 1;
650             }
651         }, WAIT_TIMEOUT_SECONDS * 1000L, CHECK_INTERVAL));
652
653         assertEquals(redirectTargetUrl,
654                 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
655     }
656
657     @SmallTest
658     @Feature({"AndroidWebView", "Navigation"})
659     public void testNotCalledForIframeHttpNavigations() throws Throwable {
660         final TestAwContentsClient contentsClient = new TestAwContentsClient();
661         final AwTestContainerView testContainerView =
662             createAwTestContainerViewOnMainSync(contentsClient);
663         final AwContents awContents = testContainerView.getAwContents();
664         final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
665             contentsClient.getShouldOverrideUrlLoadingHelper();
666
667         final String iframeRedirectTargetUrl = createRedirectTargetPage(mWebServer);
668         final String iframeRedirectUrl =
669             mWebServer.setRedirect("/302.html", iframeRedirectTargetUrl);
670         final String pageWithIframeUrl =
671             addPageToTestServer(mWebServer, "/iframe_intercept.html",
672                 makeHtmlPageFrom("", "<iframe src=\"" + iframeRedirectUrl + "\" />"));
673
674         final int shouldOverrideUrlLoadingCallCount =
675             shouldOverrideUrlLoadingHelper.getCallCount();
676
677         assertEquals(0, mWebServer.getRequestCount(REDIRECT_TARGET_PATH));
678         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), pageWithIframeUrl);
679
680         // Wait for the redirect target URL to be fetched from the server.
681         assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
682             @Override
683             public boolean isSatisfied() {
684                 return mWebServer.getRequestCount(REDIRECT_TARGET_PATH) == 1;
685             }
686         }, WAIT_TIMEOUT_SECONDS * 1000L, CHECK_INTERVAL));
687
688         assertEquals(shouldOverrideUrlLoadingCallCount,
689                 shouldOverrideUrlLoadingHelper.getCallCount());
690     }
691
692     @SmallTest
693     @Feature({"AndroidWebView", "Navigation"})
694     public void testCalledForIframeUnsupportedSchemeNavigations() throws Throwable {
695         final TestAwContentsClient contentsClient = new TestAwContentsClient();
696         final AwTestContainerView testContainerView =
697             createAwTestContainerViewOnMainSync(contentsClient);
698         final AwContents awContents = testContainerView.getAwContents();
699         final TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
700             contentsClient.getShouldOverrideUrlLoadingHelper();
701
702         final String unsupportedSchemeUrl = "foobar://resource/1";
703         final String pageWithIframeUrl =
704             addPageToTestServer(mWebServer, "/iframe_intercept.html",
705                 makeHtmlPageFrom("", "<iframe src=\"" + unsupportedSchemeUrl + "\" />"));
706
707         final int shouldOverrideUrlLoadingCallCount =
708             shouldOverrideUrlLoadingHelper.getCallCount();
709
710         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), pageWithIframeUrl);
711
712         shouldOverrideUrlLoadingHelper.waitForCallback(shouldOverrideUrlLoadingCallCount);
713         assertEquals(unsupportedSchemeUrl,
714                 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
715     }
716
717     /**
718      * Worker method for the various redirect tests.
719      *
720      * Calling this will first load the redirect URL built from redirectFilePath, query and
721      * locationFilePath and assert that we get a override callback for the destination.
722      * The second part of the test loads a page that contains a link which points at the redirect
723      * URL. We expect two callbacks - one for the redirect link and another for the destination.
724      */
725     private void doTestCalledOnRedirect(TestWebServer webServer,
726             String redirectUrl, String redirectTarget) throws Throwable {
727         final TestAwContentsClient contentsClient = new TestAwContentsClient();
728         final AwTestContainerView testContainerView =
729             createAwTestContainerViewOnMainSync(contentsClient);
730         final AwContents awContents = testContainerView.getAwContents();
731         final String pageWithLinkToRedirectUrl = addPageToTestServer(webServer,
732                 "/page_with_link_to_redirect.html",
733                 getHtmlForPageWithSimpleLinkTo(redirectUrl));
734         enableJavaScriptOnUiThread(awContents);
735
736         TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
737                 contentsClient.getShouldOverrideUrlLoadingHelper();
738         int directLoadCallCount = shouldOverrideUrlLoadingHelper.getCallCount();
739         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), redirectUrl);
740
741         shouldOverrideUrlLoadingHelper.waitForCallback(directLoadCallCount, 1);
742         assertEquals(redirectTarget,
743                 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
744
745         // There is a slight difference between navigations caused by calling load and navigations
746         // caused by clicking on a link:
747         //  * when using load the navigation is treated as if it came from the URL bar (has the
748         //    navigation type TYPED and doesn't have the has_user_gesture flag)
749         //  * when clicking on a link the navigation has the LINK type and has_user_gesture is
750         //    true.
751         // Both of these should yield the same result which is what we're verifying here.
752         int indirectLoadCallCount = shouldOverrideUrlLoadingHelper.getCallCount();
753         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(),
754                 pageWithLinkToRedirectUrl);
755
756         assertEquals(indirectLoadCallCount, shouldOverrideUrlLoadingHelper.getCallCount());
757
758         clickOnLinkUsingJs(awContents, contentsClient);
759
760         shouldOverrideUrlLoadingHelper.waitForCallback(indirectLoadCallCount, 2);
761         assertEquals(redirectTarget,
762                 shouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
763         assertEquals(redirectUrl,
764                 shouldOverrideUrlLoadingHelper.getPreviousShouldOverrideUrlLoadingUrl());
765     }
766
767     @SmallTest
768     @Feature({"AndroidWebView", "Navigation"})
769     public void testCalledOn302Redirect() throws Throwable {
770         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
771         final String redirectUrl = mWebServer.setRedirect("/302.html", redirectTargetUrl);
772
773         doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl);
774     }
775
776     @SmallTest
777     @Feature({"AndroidWebView", "Navigation"})
778     public void testCalledOnMetaRefreshRedirect() throws Throwable {
779         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
780         final String redirectUrl = addPageToTestServer(mWebServer, "/meta_refresh.html",
781                 getHtmlForPageWithMetaRefreshRedirectTo(redirectTargetUrl));
782         doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl);
783     }
784
785
786     @SmallTest
787     @Feature({"AndroidWebView", "Navigation"})
788     public void testCalledOnJavaScriptLocationImmediateAssignRedirect()
789             throws Throwable {
790         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
791         final String redirectUrl = addPageToTestServer(mWebServer, "/js_immediate_assign.html",
792                 getHtmlForPageWithJsRedirectTo(redirectTargetUrl, "Assign", 0));
793         doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl);
794     }
795
796     @SmallTest
797     @Feature({"AndroidWebView", "Navigation"})
798     public void testCalledOnJavaScriptLocationImmediateReplaceRedirect()
799             throws Throwable {
800         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
801         final String redirectUrl = addPageToTestServer(mWebServer, "/js_immediate_replace.html",
802                 getHtmlForPageWithJsRedirectTo(redirectTargetUrl, "Replace", 0));
803         doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl);
804     }
805
806     @SmallTest
807     @Feature({"AndroidWebView", "Navigation"})
808     public void testCalledOnJavaScriptLocationDelayedAssignRedirect()
809             throws Throwable {
810         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
811         final String redirectUrl = addPageToTestServer(mWebServer, "/js_delayed_assign.html",
812                 getHtmlForPageWithJsRedirectTo(redirectTargetUrl, "Assign", 100));
813         doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl);
814     }
815
816     @SmallTest
817     @Feature({"AndroidWebView", "Navigation"})
818     public void testCalledOnJavaScriptLocationDelayedReplaceRedirect()
819             throws Throwable {
820         final String redirectTargetUrl = createRedirectTargetPage(mWebServer);
821         final String redirectUrl = addPageToTestServer(mWebServer, "/js_delayed_replace.html",
822                 getHtmlForPageWithJsRedirectTo(redirectTargetUrl, "Replace", 100));
823         doTestCalledOnRedirect(mWebServer, redirectUrl, redirectTargetUrl);
824     }
825
826     @SmallTest
827     @Feature({"AndroidWebView", "Navigation"})
828     public void testDoubleNavigateDoesNotSuppressInitialNavigate() throws Throwable {
829         final String jsUrl = "javascript:try{console.log('processed js loadUrl');}catch(e){};";
830         final TestAwContentsClient contentsClient = new TestAwContentsClient();
831         final AwTestContainerView testContainerView =
832             createAwTestContainerViewOnMainSync(contentsClient);
833         final AwContents awContents = testContainerView.getAwContents();
834         TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper =
835             contentsClient.getShouldOverrideUrlLoadingHelper();
836
837         // Do a double navigagtion, the second being an effective no-op, in quick succession (i.e.
838         // without yielding the main thread inbetween).
839         int currentCallCount = contentsClient.getOnPageFinishedHelper().getCallCount();
840         getInstrumentation().runOnMainSync(new Runnable() {
841             @Override
842             public void run() {
843                 awContents.loadUrl(LoadUrlParams.createLoadDataParams(
844                         getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false));
845                 awContents.loadUrl(new LoadUrlParams(jsUrl));
846             }
847         });
848         contentsClient.getOnPageFinishedHelper().waitForCallback(currentCallCount, 1,
849                 WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
850
851         assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount());
852     }
853 }