AwSettingsTest.java revision 5b236bc719a7be3357af2c4c1cc0ba616b7cd2b5
1// Copyright 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.content.Context;
8import android.graphics.Point;
9import android.net.http.SslError;
10import android.os.Build;
11import android.os.SystemClock;
12import android.test.suitebuilder.annotation.MediumTest;
13import android.test.suitebuilder.annotation.SmallTest;
14import android.view.WindowManager;
15import android.webkit.JavascriptInterface;
16import android.webkit.ValueCallback;
17import android.webkit.WebSettings;
18
19import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
20
21import org.apache.http.Header;
22import org.apache.http.HttpRequest;
23import org.chromium.android_webview.AwContents;
24import org.chromium.android_webview.AwContentsClient.ShouldInterceptRequestParams;
25import org.chromium.android_webview.AwSettings;
26import org.chromium.android_webview.AwSettings.LayoutAlgorithm;
27import org.chromium.android_webview.AwWebResourceResponse;
28import org.chromium.android_webview.test.util.CommonResources;
29import org.chromium.android_webview.test.util.ImagePageGenerator;
30import org.chromium.android_webview.test.util.VideoTestUtil;
31import org.chromium.android_webview.test.util.VideoTestWebServer;
32import org.chromium.base.test.util.DisabledTest;
33import org.chromium.base.test.util.Feature;
34import org.chromium.base.test.util.TestFileUtil;
35import org.chromium.base.test.util.UrlUtils;
36import org.chromium.content.browser.ContentViewCore;
37import org.chromium.content.browser.test.util.CallbackHelper;
38import org.chromium.content.browser.test.util.HistoryUtils;
39import org.chromium.net.test.util.TestWebServer;
40import org.chromium.ui.gfx.DeviceDisplayInfo;
41
42import java.io.File;
43import java.util.concurrent.Callable;
44import java.util.concurrent.TimeUnit;
45import java.util.regex.Matcher;
46import java.util.regex.Pattern;
47
48/**
49 * A test suite for AwSettings class. The key objective is to verify that each
50 * settings applies either to each individual view or to all views of the
51 * application
52 */
53public class AwSettingsTest extends AwTestBase {
54    private static final boolean ENABLED = true;
55    private static final boolean DISABLED = false;
56
57    /**
58     * A helper class for testing a particular preference from AwSettings.
59     * The generic type T is the type of the setting. Usually, to test an
60     * effect of the preference, JS code is executed that sets document's title.
61     * In this case, requiresJsEnabled constructor argument must be set to true.
62     */
63    abstract class AwSettingsTestHelper<T> {
64        protected final AwContents mAwContents;
65        protected final Context mContext;
66        protected final TestAwContentsClient mContentViewClient;
67        protected final AwSettings mAwSettings;
68
69        AwSettingsTestHelper(AwTestContainerView containerView,
70                             TestAwContentsClient contentViewClient,
71                             boolean requiresJsEnabled) throws Throwable {
72            mAwContents = containerView.getAwContents();
73            mContext = containerView.getContext();
74            mContentViewClient = contentViewClient;
75            mAwSettings = AwSettingsTest.this.getAwSettingsOnUiThread(mAwContents);
76            if (requiresJsEnabled) {
77                mAwSettings.setJavaScriptEnabled(true);
78            }
79        }
80
81        void ensureSettingHasAlteredValue() throws Throwable {
82            ensureSettingHasValue(getAlteredValue());
83        }
84
85        void ensureSettingHasInitialValue() throws Throwable {
86            ensureSettingHasValue(getInitialValue());
87        }
88
89        void setAlteredSettingValue() throws Throwable {
90            setCurrentValue(getAlteredValue());
91        }
92
93        void setInitialSettingValue() throws Throwable {
94            setCurrentValue(getInitialValue());
95        }
96
97        protected abstract T getAlteredValue();
98
99        protected abstract T getInitialValue();
100
101        protected abstract T getCurrentValue();
102
103        protected abstract void setCurrentValue(T value) throws Throwable;
104
105        protected abstract void doEnsureSettingHasValue(T value) throws Throwable;
106
107        protected String getTitleOnUiThread() throws Exception {
108            return AwSettingsTest.this.getTitleOnUiThread(mAwContents);
109        }
110
111        protected void loadDataSync(String data) throws Throwable {
112            AwSettingsTest.this.loadDataSync(
113                mAwContents,
114                mContentViewClient.getOnPageFinishedHelper(),
115                data,
116                "text/html",
117                false);
118        }
119
120        protected void loadUrlSync(String url) throws Throwable {
121            AwSettingsTest.this.loadUrlSync(
122                mAwContents,
123                mContentViewClient.getOnPageFinishedHelper(),
124                url);
125        }
126
127        protected void loadUrlSyncAndExpectError(String url) throws Throwable {
128            AwSettingsTest.this.loadUrlSyncAndExpectError(
129                mAwContents,
130                mContentViewClient.getOnPageFinishedHelper(),
131                mContentViewClient.getOnReceivedErrorHelper(),
132                url);
133        }
134
135        protected String executeJavaScriptAndWaitForResult(String script) throws Exception {
136            return AwSettingsTest.this.executeJavaScriptAndWaitForResult(
137                    mAwContents, mContentViewClient, script);
138        }
139
140        private void ensureSettingHasValue(T value) throws Throwable {
141            assertEquals(value, getCurrentValue());
142            doEnsureSettingHasValue(value);
143        }
144    }
145
146    class AwSettingsJavaScriptTestHelper extends AwSettingsTestHelper<Boolean> {
147        private static final String JS_ENABLED_STRING = "JS Enabled";
148        private static final String JS_DISABLED_STRING = "JS Disabled";
149
150        AwSettingsJavaScriptTestHelper(AwTestContainerView containerView,
151                                       TestAwContentsClient contentViewClient) throws Throwable {
152            super(containerView, contentViewClient, false);
153        }
154
155        @Override
156        protected Boolean getAlteredValue() {
157            return ENABLED;
158        }
159
160        @Override
161        protected Boolean getInitialValue() {
162            return DISABLED;
163        }
164
165        @Override
166        protected Boolean getCurrentValue() {
167            return mAwSettings.getJavaScriptEnabled();
168        }
169
170        @Override
171        protected void setCurrentValue(Boolean value) {
172            mAwSettings.setJavaScriptEnabled(value);
173        }
174
175        @Override
176        protected void doEnsureSettingHasValue(Boolean value) throws Throwable {
177            loadDataSync(getData());
178            assertEquals(
179                value == ENABLED ? JS_ENABLED_STRING : JS_DISABLED_STRING,
180                getTitleOnUiThread());
181        }
182
183        private String getData() {
184            return "<html><head><title>" + JS_DISABLED_STRING + "</title>"
185                    + "</head><body onload=\"document.title='" + JS_ENABLED_STRING
186                    + "';\"></body></html>";
187        }
188    }
189
190    // In contrast to AwSettingsJavaScriptTestHelper, doesn't reload the page when testing
191    // JavaScript state.
192    class AwSettingsJavaScriptDynamicTestHelper extends AwSettingsJavaScriptTestHelper {
193        AwSettingsJavaScriptDynamicTestHelper(
194                AwTestContainerView containerView,
195                TestAwContentsClient contentViewClient) throws Throwable {
196            super(containerView, contentViewClient);
197            // Load the page.
198            super.doEnsureSettingHasValue(getInitialValue());
199        }
200
201        @Override
202        protected void doEnsureSettingHasValue(Boolean value) throws Throwable {
203            String oldTitle = getTitleOnUiThread();
204            String newTitle = oldTitle + "_modified";
205            executeJavaScriptAndWaitForResult(getScript(newTitle));
206            assertEquals(value == ENABLED ? newTitle : oldTitle, getTitleOnUiThread());
207        }
208
209        private String getScript(String title) {
210            return "document.title='" + title + "';";
211        }
212    }
213
214    class AwSettingsPluginsTestHelper extends AwSettingsTestHelper<Boolean> {
215        private static final String PLUGINS_ENABLED_STRING = "Embed";
216        private static final String PLUGINS_DISABLED_STRING = "NoEmbed";
217
218        AwSettingsPluginsTestHelper(AwTestContainerView containerView,
219                                    TestAwContentsClient contentViewClient) throws Throwable {
220            super(containerView, contentViewClient, true);
221        }
222
223        @Override
224        protected Boolean getAlteredValue() {
225            return ENABLED;
226        }
227
228        @Override
229        protected Boolean getInitialValue() {
230            return DISABLED;
231        }
232
233        @Override
234        protected Boolean getCurrentValue() {
235            return mAwSettings.getPluginsEnabled();
236        }
237
238        @Override
239        protected void setCurrentValue(Boolean value) {
240            mAwSettings.setPluginsEnabled(value);
241        }
242
243        @Override
244        protected void doEnsureSettingHasValue(Boolean value) throws Throwable {
245            loadDataSync(getData());
246            assertEquals(
247                value == ENABLED ? PLUGINS_ENABLED_STRING : PLUGINS_DISABLED_STRING,
248                getTitleOnUiThread());
249        }
250
251        private String getData() {
252            return "<html><body onload=\"document.title = document.body.innerText;\">"
253                    + "<noembed>No</noembed><span>Embed</span></body></html>";
254        }
255    }
256
257    class AwSettingsStandardFontFamilyTestHelper extends AwSettingsTestHelper<String> {
258        AwSettingsStandardFontFamilyTestHelper(
259                AwTestContainerView containerView,
260                TestAwContentsClient contentViewClient) throws Throwable {
261            super(containerView, contentViewClient, true);
262        }
263
264        @Override
265        protected String getAlteredValue() {
266            return "cursive";
267        }
268
269        @Override
270        protected String getInitialValue() {
271            return "sans-serif";
272        }
273
274        @Override
275        protected String getCurrentValue() {
276            return mAwSettings.getStandardFontFamily();
277        }
278
279        @Override
280        protected void setCurrentValue(String value) {
281            mAwSettings.setStandardFontFamily(value);
282        }
283
284        @Override
285        protected void doEnsureSettingHasValue(String value) throws Throwable {
286            loadDataSync(getData());
287            assertEquals(value, getTitleOnUiThread());
288        }
289
290        private String getData() {
291            return "<html><body onload=\"document.title = " +
292                    "getComputedStyle(document.body).getPropertyValue('font-family');\">"
293                    + "</body></html>";
294        }
295    }
296
297    class AwSettingsDefaultFontSizeTestHelper extends AwSettingsTestHelper<Integer> {
298        AwSettingsDefaultFontSizeTestHelper(
299                AwTestContainerView containerView,
300                TestAwContentsClient contentViewClient) throws Throwable {
301            super(containerView, contentViewClient, true);
302        }
303
304        @Override
305        protected Integer getAlteredValue() {
306            return 42;
307        }
308
309        @Override
310        protected Integer getInitialValue() {
311            return 16;
312        }
313
314        @Override
315        protected Integer getCurrentValue() {
316            return mAwSettings.getDefaultFontSize();
317        }
318
319        @Override
320        protected void setCurrentValue(Integer value) {
321            mAwSettings.setDefaultFontSize(value);
322        }
323
324        @Override
325        protected void doEnsureSettingHasValue(Integer value) throws Throwable {
326            loadDataSync(getData());
327            assertEquals(value.toString() + "px", getTitleOnUiThread());
328        }
329
330        private String getData() {
331            return "<html><body onload=\"document.title = " +
332                    "getComputedStyle(document.body).getPropertyValue('font-size');\">"
333                    + "</body></html>";
334        }
335    }
336
337    class AwSettingsLoadImagesAutomaticallyTestHelper extends AwSettingsTestHelper<Boolean> {
338        private ImagePageGenerator mGenerator;
339
340        AwSettingsLoadImagesAutomaticallyTestHelper(
341                AwTestContainerView containerView,
342                TestAwContentsClient contentViewClient,
343                ImagePageGenerator generator) throws Throwable {
344            super(containerView, contentViewClient, true);
345            mGenerator = generator;
346        }
347
348        @Override
349        protected Boolean getAlteredValue() {
350            return DISABLED;
351        }
352
353        @Override
354        protected Boolean getInitialValue() {
355            return ENABLED;
356        }
357
358        @Override
359        protected Boolean getCurrentValue() {
360            return mAwSettings.getLoadsImagesAutomatically();
361        }
362
363        @Override
364        protected void setCurrentValue(Boolean value) {
365            mAwSettings.setLoadsImagesAutomatically(value);
366        }
367
368        @Override
369        protected void doEnsureSettingHasValue(Boolean value) throws Throwable {
370            loadDataSync(mGenerator.getPageSource());
371            assertEquals(value == ENABLED ?
372                         ImagePageGenerator.IMAGE_LOADED_STRING :
373                         ImagePageGenerator.IMAGE_NOT_LOADED_STRING,
374                         getTitleOnUiThread());
375        }
376    }
377
378
379    class AwSettingsImagesEnabledHelper extends AwSettingsTestHelper<Boolean> {
380
381        AwSettingsImagesEnabledHelper(
382                AwTestContainerView containerView,
383                TestAwContentsClient contentViewClient,
384                TestWebServer webServer,
385                ImagePageGenerator generator) throws Throwable {
386            super(containerView, contentViewClient, true);
387            mWebServer = webServer;
388            mGenerator = generator;
389        }
390
391        @Override
392        protected Boolean getAlteredValue() {
393            return DISABLED;
394        }
395
396        @Override
397        protected Boolean getInitialValue() {
398            return ENABLED;
399        }
400
401        @Override
402        protected Boolean getCurrentValue() {
403            return mAwSettings.getImagesEnabled();
404        }
405
406        @Override
407        protected void setCurrentValue(Boolean value) {
408            mAwSettings.setImagesEnabled(value);
409        }
410
411        @Override
412        protected void doEnsureSettingHasValue(Boolean value) throws Throwable {
413            final String httpImageUrl = mGenerator.getPageUrl(mWebServer);
414            AwSettingsTest.this.loadUrlSync(
415                    mAwContents,
416                    mContentViewClient.getOnPageFinishedHelper(),
417                    httpImageUrl);
418            assertEquals(value == ENABLED ?
419                         ImagePageGenerator.IMAGE_LOADED_STRING :
420                         ImagePageGenerator.IMAGE_NOT_LOADED_STRING,
421                         getTitleOnUiThread());
422        }
423
424        private TestWebServer mWebServer;
425        private ImagePageGenerator mGenerator;
426    }
427
428    class AwSettingsDefaultTextEncodingTestHelper extends AwSettingsTestHelper<String> {
429        AwSettingsDefaultTextEncodingTestHelper(
430                AwTestContainerView containerView,
431                TestAwContentsClient contentViewClient) throws Throwable {
432            super(containerView, contentViewClient, true);
433        }
434
435        @Override
436        protected String getAlteredValue() {
437            return "utf-8";
438        }
439
440        @Override
441        protected String getInitialValue() {
442            return "Latin-1";
443        }
444
445        @Override
446        protected String getCurrentValue() {
447            return mAwSettings.getDefaultTextEncodingName();
448        }
449
450        @Override
451        protected void setCurrentValue(String value) {
452            mAwSettings.setDefaultTextEncodingName(value);
453        }
454
455        @Override
456        protected void doEnsureSettingHasValue(String value) throws Throwable {
457            loadDataSync(getData());
458            assertEquals(value, getTitleOnUiThread());
459        }
460
461        private String getData() {
462            return "<html><body onload='document.title=document.defaultCharset'></body></html>";
463        }
464    }
465
466    class AwSettingsUserAgentStringTestHelper extends AwSettingsTestHelper<String> {
467        private final String mDefaultUa;
468        private static final String DEFAULT_UA = "";
469        private static final String CUSTOM_UA = "ChromeViewTest";
470
471        AwSettingsUserAgentStringTestHelper(
472                AwTestContainerView containerView,
473                TestAwContentsClient contentViewClient) throws Throwable {
474            super(containerView, contentViewClient, true);
475            mDefaultUa = mAwSettings.getUserAgentString();
476        }
477
478        @Override
479        protected String getAlteredValue() {
480            return CUSTOM_UA;
481        }
482
483        @Override
484        protected String getInitialValue() {
485            return DEFAULT_UA;
486        }
487
488        @Override
489        protected String getCurrentValue() {
490            // The test framework expects that getXXX() == Z after setXXX(Z).
491            // But setUserAgentString("" / null) resets the UA string to default,
492            // and getUserAgentString returns the default UA string afterwards.
493            // To align with the framework, we return an empty string instead of
494            // the default UA.
495            String currentUa = mAwSettings.getUserAgentString();
496            return mDefaultUa.equals(currentUa) ? DEFAULT_UA : currentUa;
497        }
498
499        @Override
500        protected void setCurrentValue(String value) {
501            mAwSettings.setUserAgentString(value);
502        }
503
504        @Override
505        protected void doEnsureSettingHasValue(String value) throws Throwable {
506            loadDataSync(getData());
507            assertEquals(
508                DEFAULT_UA.equals(value) ? mDefaultUa : value,
509                getTitleOnUiThread());
510        }
511
512        private String getData() {
513            return "<html><body onload='document.title=navigator.userAgent'></body></html>";
514        }
515    }
516
517    class AwSettingsDomStorageEnabledTestHelper extends AwSettingsTestHelper<Boolean> {
518        private static final String TEST_FILE = "webview/localStorage.html";
519        private static final String NO_LOCAL_STORAGE = "No localStorage";
520        private static final String HAS_LOCAL_STORAGE = "Has localStorage";
521
522        AwSettingsDomStorageEnabledTestHelper(
523                AwTestContainerView containerView,
524                TestAwContentsClient contentViewClient) throws Throwable {
525            super(containerView, contentViewClient, true);
526            AwSettingsTest.assertFileIsReadable(UrlUtils.getTestFilePath(TEST_FILE));
527        }
528
529        @Override
530        protected Boolean getAlteredValue() {
531            return ENABLED;
532        }
533
534        @Override
535        protected Boolean getInitialValue() {
536            return DISABLED;
537        }
538
539        @Override
540        protected Boolean getCurrentValue() {
541            return mAwSettings.getDomStorageEnabled();
542        }
543
544        @Override
545        protected void setCurrentValue(Boolean value) {
546            mAwSettings.setDomStorageEnabled(value);
547        }
548
549        @Override
550        protected void doEnsureSettingHasValue(Boolean value) throws Throwable {
551            // It is not permitted to access localStorage from data URLs in WebKit,
552            // that is why a standalone page must be used.
553            loadUrlSync(UrlUtils.getTestFileUrl(TEST_FILE));
554            assertEquals(
555                value == ENABLED ? HAS_LOCAL_STORAGE : NO_LOCAL_STORAGE,
556                getTitleOnUiThread());
557        }
558    }
559
560    class AwSettingsDatabaseTestHelper extends AwSettingsTestHelper<Boolean> {
561        private static final String TEST_FILE = "webview/database_access.html";
562        private static final String NO_DATABASE = "No database";
563        private static final String HAS_DATABASE = "Has database";
564
565        AwSettingsDatabaseTestHelper(
566                AwTestContainerView containerView,
567                TestAwContentsClient contentViewClient) throws Throwable {
568            super(containerView, contentViewClient, true);
569            AwSettingsTest.assertFileIsReadable(UrlUtils.getTestFilePath(TEST_FILE));
570        }
571
572        @Override
573        protected Boolean getAlteredValue() {
574            return ENABLED;
575        }
576
577        @Override
578        protected Boolean getInitialValue() {
579            return DISABLED;
580        }
581
582        @Override
583        protected Boolean getCurrentValue() {
584            return mAwSettings.getDatabaseEnabled();
585        }
586
587        @Override
588        protected void setCurrentValue(Boolean value) {
589            mAwSettings.setDatabaseEnabled(value);
590        }
591
592        @Override
593        protected void doEnsureSettingHasValue(Boolean value) throws Throwable {
594            // It seems accessing the database through a data scheme is not
595            // supported, and fails with a DOM exception (likely a cross-domain
596            // violation).
597            loadUrlSync(UrlUtils.getTestFileUrl(TEST_FILE));
598            assertEquals(
599                value == ENABLED ? HAS_DATABASE : NO_DATABASE,
600                getTitleOnUiThread());
601        }
602    }
603
604    class AwSettingsUniversalAccessFromFilesTestHelper extends AwSettingsTestHelper<Boolean> {
605        private static final String TEST_CONTAINER_FILE = "webview/iframe_access.html";
606        private static final String TEST_FILE = "webview/hello_world.html";
607        private static final String ACCESS_DENIED_TITLE = "Exception";
608
609        AwSettingsUniversalAccessFromFilesTestHelper(
610                AwTestContainerView containerView,
611                TestAwContentsClient contentViewClient) throws Throwable {
612            super(containerView, contentViewClient, true);
613            AwSettingsTest.assertFileIsReadable(UrlUtils.getTestFilePath(TEST_CONTAINER_FILE));
614            AwSettingsTest.assertFileIsReadable(UrlUtils.getTestFilePath(TEST_FILE));
615            mIframeContainerUrl = UrlUtils.getTestFileUrl(TEST_CONTAINER_FILE);
616            mIframeUrl = UrlUtils.getTestFileUrl(TEST_FILE);
617            // The value of the setting depends on the SDK version.
618            mAwSettings.setAllowUniversalAccessFromFileURLs(false);
619            // If universal access is true, the value of file access doesn't
620            // matter. While if universal access is false, having file access
621            // enabled will allow file loading.
622            mAwSettings.setAllowFileAccessFromFileURLs(false);
623        }
624
625        @Override
626        protected Boolean getAlteredValue() {
627            return ENABLED;
628        }
629
630        @Override
631        protected Boolean getInitialValue() {
632            return DISABLED;
633        }
634
635        @Override
636        protected Boolean getCurrentValue() {
637            return mAwSettings.getAllowUniversalAccessFromFileURLs();
638        }
639
640        @Override
641        protected void setCurrentValue(Boolean value) {
642            mAwSettings.setAllowUniversalAccessFromFileURLs(value);
643        }
644
645        @Override
646        protected void doEnsureSettingHasValue(Boolean value) throws Throwable {
647            loadUrlSync(mIframeContainerUrl);
648            assertEquals(
649                value == ENABLED ? mIframeUrl : ACCESS_DENIED_TITLE,
650                getTitleOnUiThread());
651        }
652
653        private final String mIframeContainerUrl;
654        private final String mIframeUrl;
655    }
656
657    class AwSettingsFileAccessFromFilesIframeTestHelper extends AwSettingsTestHelper<Boolean> {
658        private static final String TEST_CONTAINER_FILE = "webview/iframe_access.html";
659        private static final String TEST_FILE = "webview/hello_world.html";
660        private static final String ACCESS_DENIED_TITLE = "Exception";
661
662        AwSettingsFileAccessFromFilesIframeTestHelper(
663                AwTestContainerView containerView,
664                TestAwContentsClient contentViewClient) throws Throwable {
665            super(containerView, contentViewClient, true);
666            AwSettingsTest.assertFileIsReadable(UrlUtils.getTestFilePath(TEST_CONTAINER_FILE));
667            AwSettingsTest.assertFileIsReadable(UrlUtils.getTestFilePath(TEST_FILE));
668            mIframeContainerUrl = UrlUtils.getTestFileUrl(TEST_CONTAINER_FILE);
669            mIframeUrl = UrlUtils.getTestFileUrl(TEST_FILE);
670            mAwSettings.setAllowUniversalAccessFromFileURLs(false);
671            // The value of the setting depends on the SDK version.
672            mAwSettings.setAllowFileAccessFromFileURLs(false);
673        }
674
675        @Override
676        protected Boolean getAlteredValue() {
677            return ENABLED;
678        }
679
680        @Override
681        protected Boolean getInitialValue() {
682            return DISABLED;
683        }
684
685        @Override
686        protected Boolean getCurrentValue() {
687            return mAwSettings.getAllowFileAccessFromFileURLs();
688        }
689
690        @Override
691        protected void setCurrentValue(Boolean value) {
692            mAwSettings.setAllowFileAccessFromFileURLs(value);
693        }
694
695        @Override
696        protected void doEnsureSettingHasValue(Boolean value) throws Throwable {
697            loadUrlSync(mIframeContainerUrl);
698            assertEquals(
699                value == ENABLED ? mIframeUrl : ACCESS_DENIED_TITLE,
700                getTitleOnUiThread());
701        }
702
703        private final String mIframeContainerUrl;
704        private final String mIframeUrl;
705    }
706
707    class AwSettingsFileAccessFromFilesXhrTestHelper extends AwSettingsTestHelper<Boolean> {
708        private static final String TEST_FILE = "webview/xhr_access.html";
709        private static final String ACCESS_GRANTED_TITLE = "Hello, World!";
710        private static final String ACCESS_DENIED_TITLE = "Exception";
711
712        AwSettingsFileAccessFromFilesXhrTestHelper(
713                AwTestContainerView containerView,
714                TestAwContentsClient contentViewClient) throws Throwable {
715            super(containerView, contentViewClient, true);
716            assertFileIsReadable(UrlUtils.getTestFilePath(TEST_FILE));
717            mXhrContainerUrl = UrlUtils.getTestFileUrl(TEST_FILE);
718            mAwSettings.setAllowUniversalAccessFromFileURLs(false);
719            // The value of the setting depends on the SDK version.
720            mAwSettings.setAllowFileAccessFromFileURLs(false);
721        }
722
723        @Override
724        protected Boolean getAlteredValue() {
725            return ENABLED;
726        }
727
728        @Override
729        protected Boolean getInitialValue() {
730            return DISABLED;
731        }
732
733        @Override
734        protected Boolean getCurrentValue() {
735            return mAwSettings.getAllowFileAccessFromFileURLs();
736        }
737
738        @Override
739        protected void setCurrentValue(Boolean value) {
740            mAwSettings.setAllowFileAccessFromFileURLs(value);
741        }
742
743        @Override
744        protected void doEnsureSettingHasValue(Boolean value) throws Throwable {
745            loadUrlSync(mXhrContainerUrl);
746            assertEquals(
747                value == ENABLED ? ACCESS_GRANTED_TITLE : ACCESS_DENIED_TITLE,
748                getTitleOnUiThread());
749        }
750
751        private final String mXhrContainerUrl;
752    }
753
754    class AwSettingsFileUrlAccessTestHelper extends AwSettingsTestHelper<Boolean> {
755        private static final String TEST_FILE = "webview/hello_world.html";
756        private static final String ACCESS_GRANTED_TITLE = "Hello, World!";
757
758        AwSettingsFileUrlAccessTestHelper(
759                AwTestContainerView containerView,
760                TestAwContentsClient contentViewClient,
761                int startIndex) throws Throwable {
762            super(containerView, contentViewClient, true);
763            mIndex = startIndex;
764            AwSettingsTest.assertFileIsReadable(UrlUtils.getTestFilePath(TEST_FILE));
765        }
766
767        @Override
768        protected Boolean getAlteredValue() {
769            return DISABLED;
770        }
771
772        @Override
773        protected Boolean getInitialValue() {
774            return ENABLED;
775        }
776
777        @Override
778        protected Boolean getCurrentValue() {
779            return mAwSettings.getAllowFileAccess();
780        }
781
782        @Override
783        protected void setCurrentValue(Boolean value) {
784            mAwSettings.setAllowFileAccess(value);
785        }
786
787        @Override
788        protected void doEnsureSettingHasValue(Boolean value) throws Throwable {
789            // Use query parameters to avoid hitting a cached page.
790            String fileUrl = UrlUtils.getTestFileUrl(TEST_FILE + "?id=" + mIndex);
791            mIndex += 2;
792            if (value == ENABLED) {
793                loadUrlSync(fileUrl);
794                assertEquals(ACCESS_GRANTED_TITLE, getTitleOnUiThread());
795            } else {
796                loadUrlSyncAndExpectError(fileUrl);
797            }
798        }
799
800        private int mIndex;
801    }
802
803    class AwSettingsContentUrlAccessTestHelper extends AwSettingsTestHelper<Boolean> {
804
805        AwSettingsContentUrlAccessTestHelper(
806                AwTestContainerView containerView,
807                TestAwContentsClient contentViewClient,
808                int index) throws Throwable {
809            super(containerView, contentViewClient, true);
810            mTarget = "content_access_" + index;
811        }
812
813        @Override
814        protected Boolean getAlteredValue() {
815            return DISABLED;
816        }
817
818        @Override
819        protected Boolean getInitialValue() {
820            return ENABLED;
821        }
822
823        @Override
824        protected Boolean getCurrentValue() {
825            return mAwSettings.getAllowContentAccess();
826        }
827
828        @Override
829        protected void setCurrentValue(Boolean value) {
830            mAwSettings.setAllowContentAccess(value);
831        }
832
833        @Override
834        protected void doEnsureSettingHasValue(Boolean value) throws Throwable {
835            AwSettingsTest.this.resetResourceRequestCountInContentProvider(mTarget);
836            if (value == ENABLED) {
837                loadUrlSync(AwSettingsTest.this.createContentUrl(mTarget));
838                String title = getTitleOnUiThread();
839                assertTrue(title != null);
840                assertTrue("[" + mTarget + "] Actual title: \"" + title + "\"",
841                        title.contains(mTarget));
842                AwSettingsTest.this.ensureResourceRequestCountInContentProvider(mTarget, 1);
843            } else {
844                loadUrlSyncAndExpectError(AwSettingsTest.this.createContentUrl(mTarget));
845                AwSettingsTest.this.ensureResourceRequestCountInContentProvider(mTarget, 0);
846            }
847        }
848
849        private final String mTarget;
850    }
851
852    class AwSettingsContentUrlAccessFromFileTestHelper extends AwSettingsTestHelper<Boolean> {
853        private static final String TARGET = "content_from_file";
854
855        AwSettingsContentUrlAccessFromFileTestHelper(
856                AwTestContainerView containerView,
857                TestAwContentsClient contentViewClient,
858                int index) throws Throwable {
859            super(containerView, contentViewClient, true);
860            mIndex = index;
861            mTempDir = getInstrumentation().getTargetContext().getCacheDir().getPath();
862        }
863
864        @Override
865        protected Boolean getAlteredValue() {
866            return DISABLED;
867        }
868
869        @Override
870        protected Boolean getInitialValue() {
871            return ENABLED;
872        }
873
874        @Override
875        protected Boolean getCurrentValue() {
876            return mAwSettings.getAllowContentAccess();
877        }
878
879        @Override
880        protected void setCurrentValue(Boolean value) {
881            mAwSettings.setAllowContentAccess(value);
882        }
883
884        @Override
885        protected void doEnsureSettingHasValue(Boolean value) throws Throwable {
886            AwSettingsTest.this.resetResourceRequestCountInContentProvider(TARGET);
887            final String fileName = mTempDir + "/" + TARGET + ".html";
888            try {
889                TestFileUtil.createNewHtmlFile(fileName,
890                        TARGET,
891                        "<img src=\"" +
892                        // Adding a query avoids hitting a cached image, and also verifies
893                        // that content URL query parameters are ignored when accessing
894                        // a content provider.
895                        AwSettingsTest.this.createContentUrl(TARGET + "?id=" + mIndex) + "\">");
896                mIndex += 2;
897                loadUrlSync("file://" + fileName);
898                if (value == ENABLED) {
899                    AwSettingsTest.this.ensureResourceRequestCountInContentProvider(TARGET, 1);
900                } else {
901                    AwSettingsTest.this.ensureResourceRequestCountInContentProvider(TARGET, 0);
902                }
903            } finally {
904                TestFileUtil.deleteFile(fileName);
905            }
906        }
907
908        private int mIndex;
909        private String mTempDir;
910    }
911
912    // This class provides helper methods for testing of settings related to
913    // the text autosizing feature.
914    abstract class AwSettingsTextAutosizingTestHelper<T> extends AwSettingsTestHelper<T> {
915        protected static final float PARAGRAPH_FONT_SIZE = 14.0f;
916
917        AwSettingsTextAutosizingTestHelper(
918                AwTestContainerView containerView,
919                TestAwContentsClient contentViewClient) throws Throwable {
920            super(containerView, contentViewClient, true);
921            mNeedToWaitForFontSizeChange = false;
922            loadDataSync(getData());
923        }
924
925        @Override
926        protected void setCurrentValue(T value) throws Throwable {
927            mNeedToWaitForFontSizeChange = false;
928            if (value != getCurrentValue()) {
929                mOldFontSize = getActualFontSize();
930                mNeedToWaitForFontSizeChange = true;
931            }
932        }
933
934        protected float getActualFontSize() throws Throwable {
935            if (!mNeedToWaitForFontSizeChange) {
936                executeJavaScriptAndWaitForResult("setTitleToActualFontSize()");
937            } else {
938                final float oldFontSize = mOldFontSize;
939                poll(new Callable<Boolean>() {
940                    @Override
941                    public Boolean call() throws Exception {
942                        executeJavaScriptAndWaitForResult("setTitleToActualFontSize()");
943                        float newFontSize = Float.parseFloat(getTitleOnUiThread());
944                        return newFontSize != oldFontSize;
945                    }
946                });
947                mNeedToWaitForFontSizeChange = false;
948            }
949            return Float.parseFloat(getTitleOnUiThread());
950        }
951
952        protected String getData() {
953            DeviceDisplayInfo deviceInfo = DeviceDisplayInfo.create(mContext);
954            int displayWidth = (int) (deviceInfo.getDisplayWidth() / deviceInfo.getDIPScale());
955            int layoutWidth = (int) (displayWidth * 2.5f); // Use 2.5 as autosizing layout tests do.
956            StringBuilder sb = new StringBuilder();
957            sb.append("<html>" +
958                    "<head>" +
959                    "<meta name=\"viewport\" content=\"width=" + layoutWidth + "\">" +
960                    "<style>" +
961                    "body { width: " + layoutWidth + "px; margin: 0; overflow-y: hidden; }" +
962                    "</style>" +
963                    "<script>" +
964                    "function setTitleToActualFontSize() {" +
965                    // parseFloat is used to trim out the "px" suffix.
966                    "  document.title = parseFloat(getComputedStyle(" +
967                    "    document.getElementById('par')).getPropertyValue('font-size'));" +
968                    "}</script></head>" +
969                    "<body>" +
970                    "<p id=\"par\" style=\"font-size:");
971            sb.append(PARAGRAPH_FONT_SIZE);
972            sb.append("px;\">");
973            // Make the paragraph wide enough for being processed by the font autosizer.
974            for (int i = 0; i < 500; i++) {
975                sb.append("Hello, World! ");
976            }
977            sb.append("</p></body></html>");
978            return sb.toString();
979        }
980
981        private boolean mNeedToWaitForFontSizeChange;
982        private float mOldFontSize;
983    }
984
985    class AwSettingsLayoutAlgorithmTestHelper extends
986                                              AwSettingsTextAutosizingTestHelper<LayoutAlgorithm> {
987
988        AwSettingsLayoutAlgorithmTestHelper(
989                AwTestContainerView containerView,
990                TestAwContentsClient contentViewClient) throws Throwable {
991            super(containerView, contentViewClient);
992            // Font autosizing doesn't step in for narrow layout widths.
993            mAwSettings.setUseWideViewPort(true);
994        }
995
996        @Override
997        protected LayoutAlgorithm getAlteredValue() {
998            return LayoutAlgorithm.TEXT_AUTOSIZING;
999        }
1000
1001        @Override
1002        protected LayoutAlgorithm getInitialValue() {
1003            return LayoutAlgorithm.NARROW_COLUMNS;
1004        }
1005
1006        @Override
1007        protected LayoutAlgorithm getCurrentValue() {
1008            return mAwSettings.getLayoutAlgorithm();
1009        }
1010
1011        @Override
1012        protected void setCurrentValue(LayoutAlgorithm value) throws Throwable {
1013            super.setCurrentValue(value);
1014            mAwSettings.setLayoutAlgorithm(value);
1015        }
1016
1017        @Override
1018        protected void doEnsureSettingHasValue(LayoutAlgorithm value) throws Throwable {
1019            final float actualFontSize = getActualFontSize();
1020            if (value == LayoutAlgorithm.TEXT_AUTOSIZING) {
1021                assertFalse("Actual font size: " + actualFontSize,
1022                        actualFontSize == PARAGRAPH_FONT_SIZE);
1023            } else {
1024                assertTrue("Actual font size: " + actualFontSize,
1025                        actualFontSize == PARAGRAPH_FONT_SIZE);
1026            }
1027        }
1028    }
1029
1030    class AwSettingsTextZoomTestHelper extends AwSettingsTextAutosizingTestHelper<Integer> {
1031        private static final int INITIAL_TEXT_ZOOM = 100;
1032        private final float mInitialActualFontSize;
1033
1034        AwSettingsTextZoomTestHelper(
1035                AwTestContainerView containerView,
1036                TestAwContentsClient contentViewClient) throws Throwable {
1037            super(containerView, contentViewClient);
1038            mInitialActualFontSize = getActualFontSize();
1039        }
1040
1041        @Override
1042        protected Integer getAlteredValue() {
1043            return INITIAL_TEXT_ZOOM * 2;
1044        }
1045
1046        @Override
1047        protected Integer getInitialValue() {
1048            return INITIAL_TEXT_ZOOM;
1049        }
1050
1051        @Override
1052        protected Integer getCurrentValue() {
1053            return mAwSettings.getTextZoom();
1054        }
1055
1056        @Override
1057        protected void setCurrentValue(Integer value) throws Throwable {
1058            super.setCurrentValue(value);
1059            mAwSettings.setTextZoom(value);
1060        }
1061
1062        @Override
1063        protected void doEnsureSettingHasValue(Integer value) throws Throwable {
1064            final float actualFontSize = getActualFontSize();
1065            // Ensure that actual vs. initial font size ratio is similar to actual vs. initial
1066            // text zoom values ratio.
1067            final float ratiosDelta = Math.abs(
1068                (actualFontSize / mInitialActualFontSize) -
1069                (value / (float) INITIAL_TEXT_ZOOM));
1070            assertTrue(
1071                "|(" + actualFontSize + " / " + mInitialActualFontSize + ") - (" +
1072                value + " / " + INITIAL_TEXT_ZOOM + ")| = " + ratiosDelta,
1073                ratiosDelta <= 0.2f);
1074        }
1075    }
1076
1077    class AwSettingsTextZoomAutosizingTestHelper
1078            extends AwSettingsTextAutosizingTestHelper<Integer> {
1079        private static final int INITIAL_TEXT_ZOOM = 100;
1080        private final float mInitialActualFontSize;
1081
1082        AwSettingsTextZoomAutosizingTestHelper(
1083                AwTestContainerView containerView,
1084                TestAwContentsClient contentViewClient) throws Throwable {
1085            super(containerView, contentViewClient);
1086            mAwSettings.setLayoutAlgorithm(LayoutAlgorithm.TEXT_AUTOSIZING);
1087            // The initial font size can be adjusted by font autosizer depending on the page's
1088            // viewport width.
1089            mInitialActualFontSize = getActualFontSize();
1090        }
1091
1092        @Override
1093        protected Integer getAlteredValue() {
1094            return INITIAL_TEXT_ZOOM * 2;
1095        }
1096
1097        @Override
1098        protected Integer getInitialValue() {
1099            return INITIAL_TEXT_ZOOM;
1100        }
1101
1102        @Override
1103        protected Integer getCurrentValue() {
1104            return mAwSettings.getTextZoom();
1105        }
1106
1107        @Override
1108        protected void setCurrentValue(Integer value) throws Throwable {
1109            super.setCurrentValue(value);
1110            mAwSettings.setTextZoom(value);
1111        }
1112
1113        @Override
1114        protected void doEnsureSettingHasValue(Integer value) throws Throwable {
1115            final float actualFontSize = getActualFontSize();
1116            // Ensure that actual vs. initial font size ratio is similar to actual vs. initial
1117            // text zoom values ratio.
1118            final float ratiosDelta = Math.abs(
1119                (actualFontSize / mInitialActualFontSize) -
1120                (value / (float) INITIAL_TEXT_ZOOM));
1121            assertTrue(
1122                "|(" + actualFontSize + " / " + mInitialActualFontSize + ") - (" +
1123                value + " / " + INITIAL_TEXT_ZOOM + ")| = " + ratiosDelta,
1124                ratiosDelta <= 0.2f);
1125        }
1126    }
1127
1128    class AwSettingsJavaScriptPopupsTestHelper extends AwSettingsTestHelper<Boolean> {
1129        private static final String POPUP_ENABLED = "Popup enabled";
1130        private static final String POPUP_BLOCKED = "Popup blocked";
1131
1132        AwSettingsJavaScriptPopupsTestHelper(
1133                AwTestContainerView containerView,
1134                TestAwContentsClient contentViewClient) throws Throwable {
1135            super(containerView, contentViewClient, true);
1136        }
1137
1138        @Override
1139        protected Boolean getAlteredValue() {
1140            return ENABLED;
1141        }
1142
1143        @Override
1144        protected Boolean getInitialValue() {
1145            return DISABLED;
1146        }
1147
1148        @Override
1149        protected Boolean getCurrentValue() {
1150            return mAwSettings.getJavaScriptCanOpenWindowsAutomatically();
1151        }
1152
1153        @Override
1154        protected void setCurrentValue(Boolean value) {
1155            mAwSettings.setJavaScriptCanOpenWindowsAutomatically(value);
1156        }
1157
1158        @Override
1159        protected void doEnsureSettingHasValue(Boolean value) throws Throwable {
1160            loadDataSync(getData());
1161            final boolean expectPopupEnabled = value;
1162            poll(new Callable<Boolean>() {
1163                @Override
1164                public Boolean call() throws Exception {
1165                    String title = getTitleOnUiThread();
1166                    return expectPopupEnabled ? POPUP_ENABLED.equals(title) :
1167                            POPUP_BLOCKED.equals(title);
1168                }
1169            });
1170            assertEquals(value ? POPUP_ENABLED : POPUP_BLOCKED, getTitleOnUiThread());
1171        }
1172
1173        private String getData() {
1174            return "<html><head>" +
1175                    "<script>" +
1176                    "    function tryOpenWindow() {" +
1177                    "        var newWindow = window.open(" +
1178                    "           'data:text/html;charset=utf-8," +
1179                    "           <html><head><title>" + POPUP_ENABLED + "</title></head></html>');" +
1180                    "        if (!newWindow) document.title = '" + POPUP_BLOCKED + "';" +
1181                    "    }" +
1182                    "</script></head>" +
1183                    "<body onload='tryOpenWindow()'></body></html>";
1184        }
1185    }
1186
1187    class AwSettingsCacheModeTestHelper extends AwSettingsTestHelper<Integer> {
1188
1189        AwSettingsCacheModeTestHelper(
1190                AwTestContainerView containerView,
1191                TestAwContentsClient contentViewClient,
1192                int index,
1193                TestWebServer webServer) throws Throwable {
1194            super(containerView, contentViewClient, true);
1195            mIndex = index;
1196            mWebServer = webServer;
1197        }
1198
1199        @Override
1200        protected Integer getAlteredValue() {
1201            // We use the value that results in a behaviour completely opposite to default.
1202            return WebSettings.LOAD_CACHE_ONLY;
1203        }
1204
1205        @Override
1206        protected Integer getInitialValue() {
1207            return WebSettings.LOAD_DEFAULT;
1208        }
1209
1210        @Override
1211        protected Integer getCurrentValue() {
1212            return mAwSettings.getCacheMode();
1213        }
1214
1215        @Override
1216        protected void setCurrentValue(Integer value) {
1217            mAwSettings.setCacheMode(value);
1218        }
1219
1220        @Override
1221        protected void doEnsureSettingHasValue(Integer value) throws Throwable {
1222            final String htmlPath = "/cache_mode_" + mIndex + ".html";
1223            mIndex += 2;
1224            final String url = mWebServer.setResponse(htmlPath, "response", null);
1225            assertEquals(0, mWebServer.getRequestCount(htmlPath));
1226            if (value == WebSettings.LOAD_DEFAULT) {
1227                loadUrlSync(url);
1228                assertEquals(1, mWebServer.getRequestCount(htmlPath));
1229            } else {
1230                loadUrlSyncAndExpectError(url);
1231                assertEquals(0, mWebServer.getRequestCount(htmlPath));
1232            }
1233        }
1234
1235        private int mIndex;
1236        private TestWebServer mWebServer;
1237    }
1238
1239    // To verify whether UseWideViewport works, we check, if the page width specified
1240    // in the "meta viewport" tag is applied. When UseWideViewport is turned off, the
1241    // "viewport" tag is ignored, and the layout width is set to device width in DIP pixels.
1242    // We specify a very high width value to make sure that it doesn't intersect with
1243    // device screen widths (in DIP pixels).
1244    class AwSettingsUseWideViewportTestHelper extends AwSettingsTestHelper<Boolean> {
1245        private static final String VIEWPORT_TAG_LAYOUT_WIDTH = "3000";
1246
1247        AwSettingsUseWideViewportTestHelper(
1248                AwTestContainerView containerView,
1249                TestAwContentsClient contentViewClient) throws Throwable {
1250            super(containerView, contentViewClient, true);
1251        }
1252
1253        @Override
1254        protected Boolean getAlteredValue() {
1255            return ENABLED;
1256        }
1257
1258        @Override
1259        protected Boolean getInitialValue() {
1260            return DISABLED;
1261        }
1262
1263        @Override
1264        protected Boolean getCurrentValue() {
1265            return mAwSettings.getUseWideViewPort();
1266        }
1267
1268        @Override
1269        protected void setCurrentValue(Boolean value) {
1270            mAwSettings.setUseWideViewPort(value);
1271        }
1272
1273        @Override
1274        protected void doEnsureSettingHasValue(Boolean value) throws Throwable {
1275            loadDataSync(getData());
1276            final String bodyWidth = getTitleOnUiThread();
1277            if (value) {
1278                assertTrue(bodyWidth, VIEWPORT_TAG_LAYOUT_WIDTH.equals(bodyWidth));
1279            } else {
1280                assertFalse(bodyWidth, VIEWPORT_TAG_LAYOUT_WIDTH.equals(bodyWidth));
1281            }
1282        }
1283
1284        private String getData() {
1285            return "<html><head>" +
1286                    "<meta name='viewport' content='width=" + VIEWPORT_TAG_LAYOUT_WIDTH + "' />" +
1287                    "</head>" +
1288                    "<body onload='document.title=document.body.clientWidth'></body></html>";
1289        }
1290    }
1291
1292    class AwSettingsLoadWithOverviewModeTestHelper extends AwSettingsTestHelper<Boolean> {
1293        private static final float DEFAULT_PAGE_SCALE = 1.0f;
1294
1295        AwSettingsLoadWithOverviewModeTestHelper(
1296                AwTestContainerView containerView,
1297                TestAwContentsClient contentViewClient,
1298                boolean withViewPortTag) throws Throwable {
1299            super(containerView, contentViewClient, true);
1300            mWithViewPortTag = withViewPortTag;
1301            mAwSettings.setUseWideViewPort(true);
1302        }
1303
1304        @Override
1305        protected Boolean getAlteredValue() {
1306            return ENABLED;
1307        }
1308
1309        @Override
1310        protected Boolean getInitialValue() {
1311            return DISABLED;
1312        }
1313
1314        @Override
1315        protected Boolean getCurrentValue() {
1316            return mAwSettings.getLoadWithOverviewMode();
1317        }
1318
1319        @Override
1320        protected void setCurrentValue(Boolean value) {
1321            mExpectScaleChange = mAwSettings.getLoadWithOverviewMode() != value;
1322            if (mExpectScaleChange) {
1323                mOnScaleChangedCallCount =
1324                        mContentViewClient.getOnScaleChangedHelper().getCallCount();
1325            }
1326            mAwSettings.setLoadWithOverviewMode(value);
1327        }
1328
1329        @Override
1330        protected void doEnsureSettingHasValue(Boolean value) throws Throwable {
1331            loadDataSync(getData());
1332            if (mExpectScaleChange) {
1333                mContentViewClient.getOnScaleChangedHelper().
1334                        waitForCallback(mOnScaleChangedCallCount);
1335                mExpectScaleChange = false;
1336            }
1337            float currentScale = AwSettingsTest.this.getScaleOnUiThread(mAwContents);
1338            if (value) {
1339                assertTrue("Expected: " + currentScale + " < " + DEFAULT_PAGE_SCALE,
1340                        currentScale < DEFAULT_PAGE_SCALE);
1341            } else {
1342                assertEquals(DEFAULT_PAGE_SCALE, currentScale);
1343            }
1344        }
1345
1346        private String getData() {
1347            return "<html><head>" +
1348                    (mWithViewPortTag ? "<meta name='viewport' content='width=3000' />" : "") +
1349                    "</head>" +
1350                    "<body></body></html>";
1351        }
1352
1353        private final boolean mWithViewPortTag;
1354        private boolean mExpectScaleChange;
1355        private int mOnScaleChangedCallCount;
1356    }
1357
1358    // The test verifies that JavaScript is disabled upon WebView
1359    // creation without accessing AwSettings. If the test passes,
1360    // it means that WebView-specific web preferences configuration
1361    // is applied on WebView creation. JS state is used, because it is
1362    // enabled by default in Chrome, but must be disabled by default
1363    // in WebView.
1364    @SmallTest
1365    @Feature({"AndroidWebView", "Preferences"})
1366    public void testJavaScriptDisabledByDefault() throws Throwable {
1367        final String JS_ENABLED_STRING = "JS has run";
1368        final String JS_DISABLED_STRING = "JS has not run";
1369        final String TEST_PAGE_HTML =
1370                "<html><head><title>" + JS_DISABLED_STRING + "</title>"
1371                + "</head><body onload=\"document.title='" + JS_ENABLED_STRING
1372                + "';\"></body></html>";
1373        final TestAwContentsClient contentClient = new TestAwContentsClient();
1374        final AwTestContainerView testContainerView =
1375                createAwTestContainerViewOnMainSync(contentClient);
1376        final AwContents awContents = testContainerView.getAwContents();
1377        loadDataSync(
1378            awContents,
1379            contentClient.getOnPageFinishedHelper(),
1380            TEST_PAGE_HTML,
1381            "text/html",
1382            false);
1383        assertEquals(JS_DISABLED_STRING, getTitleOnUiThread(awContents));
1384    }
1385
1386    @SmallTest
1387    @Feature({"AndroidWebView", "Preferences"})
1388    public void testJavaScriptEnabledWithTwoViews() throws Throwable {
1389        ViewPair views = createViews();
1390        runPerViewSettingsTest(
1391            new AwSettingsJavaScriptTestHelper(views.getContainer0(), views.getClient0()),
1392            new AwSettingsJavaScriptTestHelper(views.getContainer1(), views.getClient1()));
1393    }
1394
1395    @SmallTest
1396    @Feature({"AndroidWebView", "Preferences"})
1397    public void testJavaScriptEnabledDynamicWithTwoViews() throws Throwable {
1398        ViewPair views = createViews();
1399        runPerViewSettingsTest(
1400            new AwSettingsJavaScriptDynamicTestHelper(views.getContainer0(), views.getClient0()),
1401            new AwSettingsJavaScriptDynamicTestHelper(views.getContainer1(), views.getClient1()));
1402    }
1403
1404    @SmallTest
1405    @Feature({"AndroidWebView", "Preferences"})
1406    public void testPluginsEnabledWithTwoViews() throws Throwable {
1407        ViewPair views = createViews();
1408        runPerViewSettingsTest(
1409            new AwSettingsPluginsTestHelper(views.getContainer0(), views.getClient0()),
1410            new AwSettingsPluginsTestHelper(views.getContainer1(), views.getClient1()));
1411    }
1412
1413    @SmallTest
1414    @Feature({"AndroidWebView", "Preferences"})
1415    public void testStandardFontFamilyWithTwoViews() throws Throwable {
1416        ViewPair views = createViews();
1417        runPerViewSettingsTest(
1418            new AwSettingsStandardFontFamilyTestHelper(views.getContainer0(), views.getClient0()),
1419            new AwSettingsStandardFontFamilyTestHelper(views.getContainer1(), views.getClient1()));
1420    }
1421
1422    @SmallTest
1423    @Feature({"AndroidWebView", "Preferences"})
1424    public void testDefaultFontSizeWithTwoViews() throws Throwable {
1425        ViewPair views = createViews();
1426        runPerViewSettingsTest(
1427            new AwSettingsDefaultFontSizeTestHelper(views.getContainer0(), views.getClient0()),
1428            new AwSettingsDefaultFontSizeTestHelper(views.getContainer1(), views.getClient1()));
1429    }
1430
1431    // The test verifies that after changing the LoadsImagesAutomatically
1432    // setting value from false to true previously skipped images are
1433    // automatically loaded.
1434    @SmallTest
1435    @Feature({"AndroidWebView", "Preferences"})
1436    public void testLoadsImagesAutomaticallyNoPageReload() throws Throwable {
1437        final TestAwContentsClient contentClient = new TestAwContentsClient();
1438        final AwTestContainerView testContainerView =
1439                createAwTestContainerViewOnMainSync(contentClient);
1440        final AwContents awContents = testContainerView.getAwContents();
1441        AwSettings settings = getAwSettingsOnUiThread(awContents);
1442        settings.setJavaScriptEnabled(true);
1443        ImagePageGenerator generator = new ImagePageGenerator(0, false);
1444        settings.setLoadsImagesAutomatically(false);
1445        loadDataSync(awContents,
1446                     contentClient.getOnPageFinishedHelper(),
1447                     generator.getPageSource(),
1448                     "text/html", false);
1449        assertEquals(ImagePageGenerator.IMAGE_NOT_LOADED_STRING,
1450                getTitleOnUiThread(awContents));
1451        settings.setLoadsImagesAutomatically(true);
1452        poll(new Callable<Boolean>() {
1453            @Override
1454            public Boolean call() throws Exception {
1455                return !ImagePageGenerator.IMAGE_NOT_LOADED_STRING.equals(
1456                        getTitleOnUiThread(awContents));
1457            }
1458        });
1459        assertEquals(ImagePageGenerator.IMAGE_LOADED_STRING, getTitleOnUiThread(awContents));
1460    }
1461
1462
1463    @SmallTest
1464    @Feature({"AndroidWebView", "Preferences"})
1465    public void testLoadsImagesAutomaticallyWithTwoViews() throws Throwable {
1466        ViewPair views = createViews();
1467        runPerViewSettingsTest(
1468            new AwSettingsLoadImagesAutomaticallyTestHelper(
1469                views.getContainer0(), views.getClient0(), new ImagePageGenerator(0, true)),
1470            new AwSettingsLoadImagesAutomaticallyTestHelper(
1471                views.getContainer1(), views.getClient1(), new ImagePageGenerator(1, true)));
1472    }
1473
1474    @SmallTest
1475    @Feature({"AndroidWebView", "Preferences"})
1476    public void testDefaultTextEncodingWithTwoViews() throws Throwable {
1477        ViewPair views = createViews();
1478        runPerViewSettingsTest(
1479            new AwSettingsDefaultTextEncodingTestHelper(views.getContainer0(), views.getClient0()),
1480            new AwSettingsDefaultTextEncodingTestHelper(views.getContainer1(), views.getClient1()));
1481    }
1482
1483    // The test verifies that the default user agent string follows the format
1484    // defined in Android CTS tests:
1485    //
1486    // Mozilla/5.0 (Linux;[ U;] Android <version>;[ <language>-<country>;]
1487    // [<devicemodel>;] Build/<buildID>) AppleWebKit/<major>.<minor> (KHTML, like Gecko)
1488    // Version/<major>.<minor>[ Mobile] Safari/<major>.<minor>
1489    @SmallTest
1490    @Feature({"AndroidWebView", "Preferences"})
1491    public void testUserAgentStringDefault() throws Throwable {
1492        final TestAwContentsClient contentClient = new TestAwContentsClient();
1493        final AwTestContainerView testContainerView =
1494                createAwTestContainerViewOnMainSync(contentClient);
1495        final AwContents awContents = testContainerView.getAwContents();
1496        AwSettings settings = getAwSettingsOnUiThread(awContents);
1497        final String actualUserAgentString = settings.getUserAgentString();
1498        assertEquals(actualUserAgentString, AwSettings.getDefaultUserAgent());
1499        final String patternString =
1500                "Mozilla/5\\.0 \\(Linux;( U;)? Android ([^;]+);( (\\w+)-(\\w+);)?" +
1501                "\\s?(.*)\\sBuild/(.+)\\) AppleWebKit/(\\d+)\\.(\\d+) \\(KHTML, like Gecko\\) " +
1502                "Version/\\d+\\.\\d Chrome/\\d+\\.\\d+\\.\\d+\\.\\d+" +
1503                "( Mobile)? Safari/(\\d+)\\.(\\d+)";
1504        final Pattern userAgentExpr = Pattern.compile(patternString);
1505        Matcher patternMatcher = userAgentExpr.matcher(actualUserAgentString);
1506        assertTrue(String.format("User agent string did not match expected pattern. %nExpected " +
1507                        "pattern:%n%s%nActual:%n%s", patternString, actualUserAgentString),
1508                        patternMatcher.find());
1509        // No country-language code token.
1510        assertEquals(null, patternMatcher.group(3));
1511        if ("REL".equals(Build.VERSION.CODENAME)) {
1512            // Model is only added in release builds
1513            assertEquals(Build.MODEL, patternMatcher.group(6));
1514            // Release version is valid only in release builds
1515            assertEquals(Build.VERSION.RELEASE, patternMatcher.group(2));
1516        }
1517        assertEquals(Build.ID, patternMatcher.group(7));
1518    }
1519
1520    @SmallTest
1521    @Feature({"AndroidWebView", "Preferences"})
1522    public void testUserAgentStringOverride() throws Throwable {
1523        final TestAwContentsClient contentClient = new TestAwContentsClient();
1524        final AwTestContainerView testContainerView =
1525                createAwTestContainerViewOnMainSync(contentClient);
1526        final AwContents awContents = testContainerView.getAwContents();
1527        AwSettings settings = getAwSettingsOnUiThread(awContents);
1528        final String defaultUserAgentString = settings.getUserAgentString();
1529
1530        // Check that an attempt to reset the default UA string has no effect.
1531        settings.setUserAgentString(null);
1532        assertEquals(defaultUserAgentString, settings.getUserAgentString());
1533        settings.setUserAgentString("");
1534        assertEquals(defaultUserAgentString, settings.getUserAgentString());
1535
1536        // Check that we can also set the default value.
1537        settings.setUserAgentString(defaultUserAgentString);
1538        assertEquals(defaultUserAgentString, settings.getUserAgentString());
1539
1540        // Set a custom UA string, verify that it can be reset back to default.
1541        final String customUserAgentString = "AwSettingsTest";
1542        settings.setUserAgentString(customUserAgentString);
1543        assertEquals(customUserAgentString, settings.getUserAgentString());
1544        settings.setUserAgentString(null);
1545        assertEquals(defaultUserAgentString, settings.getUserAgentString());
1546    }
1547
1548    // Verify that the current UA override setting has a priority over UA
1549    // overrides in navigation history entries.
1550    @SmallTest
1551    @Feature({"AndroidWebView", "Preferences"})
1552    public void testUserAgentStringOverrideForHistory() throws Throwable {
1553        final TestAwContentsClient contentClient = new TestAwContentsClient();
1554        final AwTestContainerView testContainerView =
1555                createAwTestContainerViewOnMainSync(contentClient);
1556        final AwContents awContents = testContainerView.getAwContents();
1557        final ContentViewCore contentView = testContainerView.getContentViewCore();
1558        CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
1559        AwSettings settings = getAwSettingsOnUiThread(awContents);
1560        settings.setJavaScriptEnabled(true);
1561        final String defaultUserAgentString = settings.getUserAgentString();
1562        final String customUserAgentString = "AwSettingsTest";
1563        // We are using different page titles to make sure that we are really
1564        // going back and forward between them.
1565        final String pageTemplate =
1566                "<html><head><title>%s</title></head>" +
1567                "<body onload='document.title+=navigator.userAgent'></body>" +
1568                "</html>";
1569        final String page1Title = "Page1";
1570        final String page2Title = "Page2";
1571        final String page1 = String.format(pageTemplate, page1Title);
1572        final String page2 = String.format(pageTemplate, page2Title);
1573        settings.setUserAgentString(customUserAgentString);
1574        loadDataSync(
1575            awContents, onPageFinishedHelper, page1, "text/html", false);
1576        assertEquals(page1Title + customUserAgentString, getTitleOnUiThread(awContents));
1577        loadDataSync(
1578            awContents, onPageFinishedHelper, page2, "text/html", false);
1579        assertEquals(page2Title + customUserAgentString, getTitleOnUiThread(awContents));
1580        settings.setUserAgentString(null);
1581        // Must not cause any changes until the next page loading.
1582        assertEquals(page2Title + customUserAgentString, getTitleOnUiThread(awContents));
1583        HistoryUtils.goBackSync(getInstrumentation(), contentView, onPageFinishedHelper);
1584        assertEquals(page1Title + defaultUserAgentString, getTitleOnUiThread(awContents));
1585        HistoryUtils.goForwardSync(getInstrumentation(), contentView,
1586                                   onPageFinishedHelper);
1587        assertEquals(page2Title + defaultUserAgentString, getTitleOnUiThread(awContents));
1588    }
1589
1590    @SmallTest
1591    @Feature({"AndroidWebView", "Preferences"})
1592    public void testUserAgentStringWithTwoViews() throws Throwable {
1593        ViewPair views = createViews();
1594        runPerViewSettingsTest(
1595            new AwSettingsUserAgentStringTestHelper(views.getContainer0(), views.getClient0()),
1596            new AwSettingsUserAgentStringTestHelper(views.getContainer1(), views.getClient1()));
1597    }
1598
1599    @SmallTest
1600    @Feature({"AndroidWebView", "Preferences"})
1601    public void testUserAgentWithTestServer() throws Throwable {
1602        final TestAwContentsClient contentClient = new TestAwContentsClient();
1603        final AwTestContainerView testContainerView =
1604                createAwTestContainerViewOnMainSync(contentClient);
1605        AwContents awContents = testContainerView.getAwContents();
1606        AwSettings settings = getAwSettingsOnUiThread(awContents);
1607        final String customUserAgentString =
1608                "testUserAgentWithTestServerUserAgent";
1609
1610        TestWebServer webServer = null;
1611        String fileName = null;
1612        try {
1613            webServer = new TestWebServer(false);
1614            final String httpPath = "/testUserAgentWithTestServer.html";
1615            final String url = webServer.setResponse(httpPath, "foo", null);
1616
1617            settings.setUserAgentString(customUserAgentString);
1618            loadUrlSync(awContents,
1619                        contentClient.getOnPageFinishedHelper(),
1620                        url);
1621
1622            assertEquals(1, webServer.getRequestCount(httpPath));
1623            HttpRequest request = webServer.getLastRequest(httpPath);
1624            Header[] matchingHeaders = request.getHeaders("User-Agent");
1625            assertEquals(1, matchingHeaders.length);
1626
1627            Header header = matchingHeaders[0];
1628            assertEquals(customUserAgentString, header.getValue());
1629        } finally {
1630            if (webServer != null) webServer.shutdown();
1631        }
1632    }
1633
1634    @SmallTest
1635    @Feature({"AndroidWebView", "Preferences"})
1636    public void testDomStorageEnabledWithTwoViews() throws Throwable {
1637        ViewPair views = createViews();
1638        runPerViewSettingsTest(
1639            new AwSettingsDomStorageEnabledTestHelper(views.getContainer0(), views.getClient0()),
1640            new AwSettingsDomStorageEnabledTestHelper(views.getContainer1(), views.getClient1()));
1641    }
1642
1643    // Ideally, these three tests below should be combined into one, or tested using
1644    // runPerViewSettingsTest. However, it seems the database setting cannot be toggled
1645    // once set. Filed b/8186497.
1646    @SmallTest
1647    @Feature({"AndroidWebView", "Preferences"})
1648    public void testDatabaseInitialValue() throws Throwable {
1649        TestAwContentsClient client = new TestAwContentsClient();
1650        final AwTestContainerView testContainerView =
1651                createAwTestContainerViewOnMainSync(client);
1652        AwSettingsDatabaseTestHelper helper =
1653                new AwSettingsDatabaseTestHelper(testContainerView, client);
1654        helper.ensureSettingHasInitialValue();
1655    }
1656
1657    @SmallTest
1658    @Feature({"AndroidWebView", "Preferences"})
1659    public void testDatabaseEnabled() throws Throwable {
1660        TestAwContentsClient client = new TestAwContentsClient();
1661        final AwTestContainerView testContainerView =
1662                createAwTestContainerViewOnMainSync(client);
1663        AwSettingsDatabaseTestHelper helper =
1664                new AwSettingsDatabaseTestHelper(testContainerView, client);
1665        helper.setAlteredSettingValue();
1666        helper.ensureSettingHasAlteredValue();
1667    }
1668
1669    @SmallTest
1670    @Feature({"AndroidWebView", "Preferences"})
1671    public void testDatabaseDisabled() throws Throwable {
1672        TestAwContentsClient client = new TestAwContentsClient();
1673        final AwTestContainerView testContainerView =
1674                createAwTestContainerViewOnMainSync(client);
1675        AwSettingsDatabaseTestHelper helper =
1676                new AwSettingsDatabaseTestHelper(testContainerView, client);
1677        helper.setInitialSettingValue();
1678        helper.ensureSettingHasInitialValue();
1679    }
1680
1681    @SmallTest
1682    @Feature({"AndroidWebView", "Preferences"})
1683    public void testUniversalAccessFromFilesWithTwoViews() throws Throwable {
1684        ViewPair views = createViews();
1685        runPerViewSettingsTest(
1686            new AwSettingsUniversalAccessFromFilesTestHelper(views.getContainer0(),
1687                views.getClient0()),
1688            new AwSettingsUniversalAccessFromFilesTestHelper(views.getContainer1(),
1689                views.getClient1()));
1690    }
1691
1692    // This test verifies that local image resources can be loaded from file:
1693    // URLs regardless of file access state.
1694    @SmallTest
1695    @Feature({"AndroidWebView", "Preferences"})
1696    public void testFileAccessFromFilesImage() throws Throwable {
1697        final String testFile = "webview/image_access.html";
1698        assertFileIsReadable(UrlUtils.getTestFilePath(testFile));
1699        final String imageContainerUrl = UrlUtils.getTestFileUrl(testFile);
1700        final String imageHeight = "16";
1701        final TestAwContentsClient contentClient = new TestAwContentsClient();
1702        final AwTestContainerView testContainerView =
1703                createAwTestContainerViewOnMainSync(contentClient);
1704        final AwContents awContents = testContainerView.getAwContents();
1705        AwSettings settings = getAwSettingsOnUiThread(awContents);
1706        settings.setJavaScriptEnabled(true);
1707        settings.setAllowUniversalAccessFromFileURLs(false);
1708        settings.setAllowFileAccessFromFileURLs(false);
1709        loadUrlSync(awContents, contentClient.getOnPageFinishedHelper(), imageContainerUrl);
1710        assertEquals(imageHeight, getTitleOnUiThread(awContents));
1711    }
1712
1713    @SmallTest
1714    @Feature({"AndroidWebView", "Preferences"})
1715    public void testFileAccessFromFilesIframeWithTwoViews() throws Throwable {
1716        ViewPair views = createViews();
1717        runPerViewSettingsTest(
1718            new AwSettingsFileAccessFromFilesIframeTestHelper(
1719                views.getContainer0(), views.getClient0()),
1720            new AwSettingsFileAccessFromFilesIframeTestHelper(
1721                views.getContainer1(), views.getClient1()));
1722    }
1723
1724    @SmallTest
1725    @Feature({"AndroidWebView", "Preferences"})
1726    public void testFileAccessFromFilesXhrWithTwoViews() throws Throwable {
1727        ViewPair views = createViews();
1728        runPerViewSettingsTest(
1729            new AwSettingsFileAccessFromFilesXhrTestHelper(views.getContainer0(),
1730                views.getClient0()),
1731            new AwSettingsFileAccessFromFilesXhrTestHelper(views.getContainer1(),
1732                views.getClient1()));
1733    }
1734
1735    @SmallTest
1736    @Feature({"AndroidWebView", "Preferences"})
1737    public void testFileUrlAccessWithTwoViews() throws Throwable {
1738        ViewPair views = createViews();
1739        runPerViewSettingsTest(
1740            new AwSettingsFileUrlAccessTestHelper(views.getContainer0(), views.getClient0(), 0),
1741            new AwSettingsFileUrlAccessTestHelper(views.getContainer1(), views.getClient1(), 1));
1742    }
1743
1744    @SmallTest
1745    @Feature({"AndroidWebView", "Preferences"})
1746    public void testContentUrlAccessWithTwoViews() throws Throwable {
1747        ViewPair views = createViews();
1748        runPerViewSettingsTest(
1749            new AwSettingsContentUrlAccessTestHelper(views.getContainer0(), views.getClient0(), 0),
1750            new AwSettingsContentUrlAccessTestHelper(views.getContainer1(), views.getClient1(), 1));
1751    }
1752
1753    @SmallTest
1754    @Feature({"AndroidWebView", "Preferences", "Navigation"})
1755    public void testBlockingContentUrlsFromDataUrls() throws Throwable {
1756        final TestAwContentsClient contentClient = new TestAwContentsClient();
1757        final AwTestContainerView testContainerView =
1758                createAwTestContainerViewOnMainSync(contentClient);
1759        final AwContents awContents = testContainerView.getAwContents();
1760        final String target = "content_from_data";
1761        final String page = "<html><body>" +
1762                "<img src=\"" +
1763                createContentUrl(target) + "\">" +
1764                "</body></html>";
1765        resetResourceRequestCountInContentProvider(target);
1766        loadDataSync(
1767            awContents,
1768            contentClient.getOnPageFinishedHelper(),
1769            page,
1770            "text/html",
1771            false);
1772        ensureResourceRequestCountInContentProvider(target, 0);
1773    }
1774
1775    @SmallTest
1776    @Feature({"AndroidWebView", "Preferences", "Navigation"})
1777    public void testContentUrlFromFileWithTwoViews() throws Throwable {
1778        ViewPair views = createViews();
1779        runPerViewSettingsTest(
1780            new AwSettingsContentUrlAccessFromFileTestHelper(
1781                    views.getContainer0(), views.getClient0(), 0),
1782            new AwSettingsContentUrlAccessFromFileTestHelper(
1783                    views.getContainer1(), views.getClient1(), 1));
1784    }
1785
1786    // @SmallTest
1787    // @Feature({"AndroidWebView", "Preferences"})
1788    // http://crbug.com/387101
1789    @DisabledTest
1790    public void testBlockNetworkImagesDoesNotBlockDataUrlImage() throws Throwable {
1791        final TestAwContentsClient contentClient = new TestAwContentsClient();
1792        final AwTestContainerView testContainerView =
1793                createAwTestContainerViewOnMainSync(contentClient);
1794        final AwContents awContents = testContainerView.getAwContents();
1795        final AwSettings settings = getAwSettingsOnUiThread(awContents);
1796        ImagePageGenerator generator = new ImagePageGenerator(0, false);
1797
1798        settings.setJavaScriptEnabled(true);
1799        settings.setImagesEnabled(false);
1800        loadDataSync(awContents,
1801                     contentClient.getOnPageFinishedHelper(),
1802                     generator.getPageSource(),
1803                     "text/html",
1804                     false);
1805        assertEquals(ImagePageGenerator.IMAGE_LOADED_STRING, getTitleOnUiThread(awContents));
1806    }
1807
1808    @SmallTest
1809    @Feature({"AndroidWebView", "Preferences"})
1810    public void testBlockNetworkImagesBlocksNetworkImageAndReloadInPlace() throws Throwable {
1811        final TestAwContentsClient contentClient = new TestAwContentsClient();
1812        final AwTestContainerView testContainerView =
1813                createAwTestContainerViewOnMainSync(contentClient);
1814        final AwContents awContents = testContainerView.getAwContents();
1815        final AwSettings settings = getAwSettingsOnUiThread(awContents);
1816        settings.setJavaScriptEnabled(true);
1817        ImagePageGenerator generator = new ImagePageGenerator(0, false);
1818
1819        TestWebServer webServer = null;
1820        try {
1821            webServer = new TestWebServer(false);
1822            final String httpImageUrl = generator.getPageUrl(webServer);
1823
1824            settings.setImagesEnabled(false);
1825            loadUrlSync(awContents, contentClient.getOnPageFinishedHelper(), httpImageUrl);
1826            assertEquals(ImagePageGenerator.IMAGE_NOT_LOADED_STRING,
1827                    getTitleOnUiThread(awContents));
1828
1829            settings.setImagesEnabled(true);
1830            poll(new Callable<Boolean>() {
1831                @Override
1832                public Boolean call() throws Exception {
1833                    return ImagePageGenerator.IMAGE_LOADED_STRING.equals(
1834                        getTitleOnUiThread(awContents));
1835                }
1836            });
1837        } finally {
1838            if (webServer != null) webServer.shutdown();
1839        }
1840    }
1841
1842    @SmallTest
1843    @Feature({"AndroidWebView", "Preferences"})
1844    public void testBlockNetworkImagesWithTwoViews() throws Throwable {
1845        ViewPair views = createViews();
1846        TestWebServer webServer = null;
1847        try {
1848            webServer = new TestWebServer(false);
1849            runPerViewSettingsTest(
1850                    new AwSettingsImagesEnabledHelper(
1851                            views.getContainer0(),
1852                            views.getClient0(),
1853                            webServer,
1854                            new ImagePageGenerator(0, true)),
1855                    new AwSettingsImagesEnabledHelper(
1856                            views.getContainer1(),
1857                            views.getClient1(),
1858                            webServer,
1859                            new ImagePageGenerator(1, true)));
1860        } finally {
1861            if (webServer != null) webServer.shutdown();
1862        }
1863    }
1864
1865    @SmallTest
1866    @Feature({"AndroidWebView", "Preferences"})
1867    public void testBlockNetworkLoadsWithHttpResources() throws Throwable {
1868        final TestAwContentsClient contentClient = new TestAwContentsClient();
1869        final AwTestContainerView testContainer =
1870                createAwTestContainerViewOnMainSync(contentClient);
1871        final AwContents awContents = testContainer.getAwContents();
1872        final AwSettings awSettings = getAwSettingsOnUiThread(awContents);
1873        awSettings.setJavaScriptEnabled(true);
1874        ImagePageGenerator generator = new ImagePageGenerator(0, false);
1875
1876        TestWebServer webServer = null;
1877        String fileName = null;
1878        try {
1879            // Set up http image.
1880            webServer = new TestWebServer(false);
1881            final String httpPath = "/image.png";
1882            final String imageUrl = webServer.setResponseBase64(
1883                    httpPath, generator.getImageSourceNoAdvance(),
1884                    CommonResources.getImagePngHeaders(true));
1885
1886            // Set up file html that loads http iframe.
1887            String pageHtml = "<img src='" + imageUrl + "' " +
1888                      "onload=\"document.title='img_onload_fired';\" " +
1889                      "onerror=\"document.title='img_onerror_fired';\" />";
1890            Context context = getInstrumentation().getTargetContext();
1891            fileName = context.getCacheDir() + "/block_network_loads_test.html";
1892            TestFileUtil.deleteFile(fileName);  // Remove leftover file if any.
1893            TestFileUtil.createNewHtmlFile(fileName, "unset", pageHtml);
1894
1895            // Actual test. Blocking should trigger onerror handler.
1896            awSettings.setBlockNetworkLoads(true);
1897            loadUrlSync(
1898                awContents,
1899                contentClient.getOnPageFinishedHelper(),
1900                "file:///" + fileName);
1901            assertEquals(0, webServer.getRequestCount(httpPath));
1902            assertEquals("img_onerror_fired", getTitleOnUiThread(awContents));
1903
1904            // Unblock should load normally.
1905            awSettings.setBlockNetworkLoads(false);
1906            loadUrlSync(
1907                awContents,
1908                contentClient.getOnPageFinishedHelper(),
1909                "file:///" + fileName);
1910            assertEquals(1, webServer.getRequestCount(httpPath));
1911            assertEquals("img_onload_fired", getTitleOnUiThread(awContents));
1912        } finally {
1913            if (fileName != null) TestFileUtil.deleteFile(fileName);
1914            if (webServer != null) webServer.shutdown();
1915        }
1916    }
1917
1918    private static class AudioEvent {
1919        private CallbackHelper mCallback;
1920        public AudioEvent(CallbackHelper callback) {
1921            mCallback = callback;
1922        }
1923
1924        @JavascriptInterface
1925        public void onCanPlay() {
1926            mCallback.notifyCalled();
1927        }
1928
1929        @JavascriptInterface
1930        public void onError() {
1931            mCallback.notifyCalled();
1932        }
1933    }
1934
1935    @SmallTest
1936    @Feature({"AndroidWebView", "Preferences"})
1937    public void testBlockNetworkLoadsWithAudio() throws Throwable {
1938        final TestAwContentsClient contentClient = new TestAwContentsClient();
1939        final AwTestContainerView testContainer =
1940                createAwTestContainerViewOnMainSync(contentClient);
1941        final AwContents awContents = testContainer.getAwContents();
1942        final AwSettings awSettings = getAwSettingsOnUiThread(awContents);
1943        final CallbackHelper callback = new CallbackHelper();
1944        awSettings.setJavaScriptEnabled(true);
1945
1946        TestWebServer webServer = null;
1947        try {
1948            webServer = new TestWebServer(false);
1949            final String httpPath = "/audio.mp3";
1950            // Don't care about the response is correct or not, just want
1951            // to know whether Url is accessed.
1952            final String audioUrl = webServer.setResponse(httpPath, "1", null);
1953
1954            String pageHtml = "<html><body><audio controls src='" + audioUrl + "' " +
1955                    "oncanplay=\"AudioEvent.onCanPlay();\" " +
1956                    "onerror=\"AudioEvent.onError();\" /> </body></html>";
1957            // Actual test. Blocking should trigger onerror handler.
1958            awSettings.setBlockNetworkLoads(true);
1959            runTestOnUiThread(new Runnable() {
1960                @Override
1961                public void run() {
1962                    awContents.addPossiblyUnsafeJavascriptInterface(
1963                            new AudioEvent(callback), "AudioEvent", null);
1964                }
1965            });
1966            int count = callback.getCallCount();
1967            loadDataSync(awContents, contentClient.getOnPageFinishedHelper(), pageHtml,
1968                    "text/html", false);
1969            callback.waitForCallback(count, 1);
1970            assertEquals(0, webServer.getRequestCount(httpPath));
1971
1972            // The below test failed in Nexus Galaxy.
1973            // See https://code.google.com/p/chromium/issues/detail?id=313463
1974            // Unblock should load normally.
1975            /*
1976            awSettings.setBlockNetworkLoads(false);
1977            count = callback.getCallCount();
1978            loadDataSync(awContents, contentClient.getOnPageFinishedHelper(), pageHtml,
1979                    "text/html", false);
1980            callback.waitForCallback(count, 1);
1981            assertTrue(0 != webServer.getRequestCount(httpPath));
1982            */
1983        } finally {
1984            if (webServer != null) webServer.shutdown();
1985        }
1986    }
1987
1988    // Test an assert URL (file:///android_asset/)
1989    @SmallTest
1990    @Feature({"AndroidWebView", "Navigation"})
1991    public void testAssetUrl() throws Throwable {
1992        // Note: this text needs to be kept in sync with the contents of the html file referenced
1993        // below.
1994        final String expectedTitle = "Asset File";
1995        final TestAwContentsClient contentClient = new TestAwContentsClient();
1996        final AwTestContainerView testContainerView =
1997                createAwTestContainerViewOnMainSync(contentClient);
1998        final AwContents awContents = testContainerView.getAwContents();
1999        loadUrlSync(awContents,
2000                    contentClient.getOnPageFinishedHelper(),
2001                    "file:///android_asset/asset_file.html");
2002        assertEquals(expectedTitle, getTitleOnUiThread(awContents));
2003    }
2004
2005    // Test a resource URL (file:///android_res/).
2006    @SmallTest
2007    @Feature({"AndroidWebView", "Navigation"})
2008    public void testResourceUrl() throws Throwable {
2009        // Note: this text needs to be kept in sync with the contents of the html file referenced
2010        // below.
2011        final String expectedTitle = "Resource File";
2012        final TestAwContentsClient contentClient = new TestAwContentsClient();
2013        final AwTestContainerView testContainerView =
2014                createAwTestContainerViewOnMainSync(contentClient);
2015        final AwContents awContents = testContainerView.getAwContents();
2016        loadUrlSync(awContents,
2017                    contentClient.getOnPageFinishedHelper(),
2018                    "file:///android_res/raw/resource_file.html");
2019        assertEquals(expectedTitle, getTitleOnUiThread(awContents));
2020    }
2021
2022    // Test that the file URL access toggle does not affect asset URLs.
2023    @SmallTest
2024    @Feature({"AndroidWebView", "Navigation"})
2025    public void testFileUrlAccessToggleDoesNotBlockAssetUrls() throws Throwable {
2026        // Note: this text needs to be kept in sync with the contents of the html file referenced
2027        // below.
2028        final String expectedTitle = "Asset File";
2029        final TestAwContentsClient contentClient = new TestAwContentsClient();
2030        final AwTestContainerView testContainerView =
2031                createAwTestContainerViewOnMainSync(contentClient);
2032        final AwContents awContents = testContainerView.getAwContents();
2033        final AwSettings settings = getAwSettingsOnUiThread(awContents);
2034        settings.setAllowFileAccess(false);
2035        loadUrlSync(awContents,
2036                    contentClient.getOnPageFinishedHelper(),
2037                    "file:///android_asset/asset_file.html");
2038        assertEquals(expectedTitle, getTitleOnUiThread(awContents));
2039    }
2040
2041    // Test that the file URL access toggle does not affect resource URLs.
2042    @SmallTest
2043    @Feature({"AndroidWebView", "Navigation"})
2044    public void testFileUrlAccessToggleDoesNotBlockResourceUrls() throws Throwable {
2045        // Note: this text needs to be kept in sync with the contents of the html file referenced
2046        // below.
2047        final String expectedTitle = "Resource File";
2048        final TestAwContentsClient contentClient = new TestAwContentsClient();
2049        final AwTestContainerView testContainerView =
2050                createAwTestContainerViewOnMainSync(contentClient);
2051        final AwContents awContents = testContainerView.getAwContents();
2052        final AwSettings settings = getAwSettingsOnUiThread(awContents);
2053        settings.setAllowFileAccess(false);
2054        loadUrlSync(awContents,
2055                    contentClient.getOnPageFinishedHelper(),
2056                    "file:///android_res/raw/resource_file.html");
2057        assertEquals(expectedTitle, getTitleOnUiThread(awContents));
2058    }
2059
2060    @SmallTest
2061    @Feature({"AndroidWebView", "Preferences"})
2062    public void testLayoutAlgorithmWithTwoViews() throws Throwable {
2063        ViewPair views = createViews();
2064        runPerViewSettingsTest(
2065            new AwSettingsLayoutAlgorithmTestHelper(views.getContainer0(), views.getClient0()),
2066            new AwSettingsLayoutAlgorithmTestHelper(views.getContainer1(), views.getClient1()));
2067    }
2068
2069    @SmallTest
2070    @Feature({"AndroidWebView", "Preferences"})
2071    public void testTextZoomWithTwoViews() throws Throwable {
2072        ViewPair views = createViews();
2073        runPerViewSettingsTest(
2074            new AwSettingsTextZoomTestHelper(views.getContainer0(), views.getClient0()),
2075            new AwSettingsTextZoomTestHelper(views.getContainer1(), views.getClient1()));
2076    }
2077
2078    @SmallTest
2079    @Feature({"AndroidWebView", "Preferences"})
2080    public void testTextZoomAutosizingWithTwoViews() throws Throwable {
2081        ViewPair views = createViews();
2082        runPerViewSettingsTest(
2083            new AwSettingsTextZoomAutosizingTestHelper(views.getContainer0(), views.getClient0()),
2084            new AwSettingsTextZoomAutosizingTestHelper(views.getContainer1(), views.getClient1()));
2085    }
2086
2087    @SmallTest
2088    @Feature({"AndroidWebView", "Preferences"})
2089    public void testJavaScriptPopupsWithTwoViews() throws Throwable {
2090        ViewPair views = createViews();
2091        runPerViewSettingsTest(
2092            new AwSettingsJavaScriptPopupsTestHelper(views.getContainer0(), views.getClient0()),
2093            new AwSettingsJavaScriptPopupsTestHelper(views.getContainer1(), views.getClient1()));
2094    }
2095
2096    @SmallTest
2097    @Feature({"AndroidWebView", "Preferences"})
2098    public void testCacheMode() throws Throwable {
2099        final TestAwContentsClient contentClient = new TestAwContentsClient();
2100        final AwTestContainerView testContainer =
2101                createAwTestContainerViewOnMainSync(contentClient);
2102        final AwContents awContents = testContainer.getAwContents();
2103        final AwSettings awSettings = getAwSettingsOnUiThread(testContainer.getAwContents());
2104        clearCacheOnUiThread(awContents, true);
2105
2106        assertEquals(WebSettings.LOAD_DEFAULT, awSettings.getCacheMode());
2107        TestWebServer webServer = null;
2108        try {
2109            webServer = new TestWebServer(false);
2110            final String htmlPath = "/testCacheMode.html";
2111            final String url = webServer.setResponse(htmlPath, "response", null);
2112            awSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
2113            loadUrlSync(awContents, contentClient.getOnPageFinishedHelper(), url);
2114            assertEquals(1, webServer.getRequestCount(htmlPath));
2115            loadUrlSync(awContents, contentClient.getOnPageFinishedHelper(), url);
2116            assertEquals(1, webServer.getRequestCount(htmlPath));
2117
2118            awSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
2119            loadUrlSync(awContents, contentClient.getOnPageFinishedHelper(), url);
2120            assertEquals(2, webServer.getRequestCount(htmlPath));
2121            loadUrlSync(awContents, contentClient.getOnPageFinishedHelper(), url);
2122            assertEquals(3, webServer.getRequestCount(htmlPath));
2123
2124            awSettings.setCacheMode(WebSettings.LOAD_CACHE_ONLY);
2125            loadUrlSync(awContents, contentClient.getOnPageFinishedHelper(), url);
2126            assertEquals(3, webServer.getRequestCount(htmlPath));
2127            loadUrlSync(awContents, contentClient.getOnPageFinishedHelper(), url);
2128            assertEquals(3, webServer.getRequestCount(htmlPath));
2129
2130            final String htmlNotInCachePath = "/testCacheMode-not-in-cache.html";
2131            final String urlNotInCache = webServer.setResponse(htmlNotInCachePath, "", null);
2132            loadUrlSyncAndExpectError(awContents,
2133                    contentClient.getOnPageFinishedHelper(),
2134                    contentClient.getOnReceivedErrorHelper(),
2135                    urlNotInCache);
2136            assertEquals(0, webServer.getRequestCount(htmlNotInCachePath));
2137        } finally {
2138            if (webServer != null) webServer.shutdown();
2139        }
2140    }
2141
2142    @SmallTest
2143    @Feature({"AndroidWebView", "Preferences"})
2144    // As our implementation of network loads blocking uses the same net::URLRequest settings, make
2145    // sure that setting cache mode doesn't accidentally enable network loads.  The reference
2146    // behaviour is that when network loads are blocked, setting cache mode has no effect.
2147    public void testCacheModeWithBlockedNetworkLoads() throws Throwable {
2148        final TestAwContentsClient contentClient = new TestAwContentsClient();
2149        final AwTestContainerView testContainer =
2150                createAwTestContainerViewOnMainSync(contentClient);
2151        final AwContents awContents = testContainer.getAwContents();
2152        final AwSettings awSettings = getAwSettingsOnUiThread(testContainer.getAwContents());
2153        clearCacheOnUiThread(awContents, true);
2154
2155        assertEquals(WebSettings.LOAD_DEFAULT, awSettings.getCacheMode());
2156        awSettings.setBlockNetworkLoads(true);
2157        TestWebServer webServer = null;
2158        try {
2159            webServer = new TestWebServer(false);
2160            final String htmlPath = "/testCacheModeWithBlockedNetworkLoads.html";
2161            final String url = webServer.setResponse(htmlPath, "response", null);
2162            loadUrlSyncAndExpectError(awContents,
2163                    contentClient.getOnPageFinishedHelper(),
2164                    contentClient.getOnReceivedErrorHelper(),
2165                    url);
2166            assertEquals(0, webServer.getRequestCount(htmlPath));
2167
2168            awSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
2169            loadUrlSyncAndExpectError(awContents,
2170                    contentClient.getOnPageFinishedHelper(),
2171                    contentClient.getOnReceivedErrorHelper(),
2172                    url);
2173            assertEquals(0, webServer.getRequestCount(htmlPath));
2174
2175            awSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
2176            loadUrlSyncAndExpectError(awContents,
2177                    contentClient.getOnPageFinishedHelper(),
2178                    contentClient.getOnReceivedErrorHelper(),
2179                    url);
2180            assertEquals(0, webServer.getRequestCount(htmlPath));
2181
2182            awSettings.setCacheMode(WebSettings.LOAD_CACHE_ONLY);
2183            loadUrlSyncAndExpectError(awContents,
2184                    contentClient.getOnPageFinishedHelper(),
2185                    contentClient.getOnReceivedErrorHelper(),
2186                    url);
2187            assertEquals(0, webServer.getRequestCount(htmlPath));
2188        } finally {
2189            if (webServer != null) webServer.shutdown();
2190        }
2191    }
2192
2193    @SmallTest
2194    @Feature({"AndroidWebView", "Preferences"})
2195    public void testCacheModeWithTwoViews() throws Throwable {
2196        ViewPair views = createViews();
2197        TestWebServer webServer = null;
2198        try {
2199            webServer = new TestWebServer(false);
2200            runPerViewSettingsTest(
2201                    new AwSettingsCacheModeTestHelper(
2202                            views.getContainer0(), views.getClient0(), 0, webServer),
2203                    new AwSettingsCacheModeTestHelper(
2204                            views.getContainer1(), views.getClient1(), 1, webServer));
2205        } finally {
2206            if (webServer != null) webServer.shutdown();
2207        }
2208    }
2209
2210    static class ManifestTestHelper {
2211        private final TestWebServer mWebServer;
2212        private final String mHtmlPath;
2213        private final String mHtmlUrl;
2214        private final String mManifestPath;
2215
2216        ManifestTestHelper(
2217                TestWebServer webServer, String htmlPageName, String manifestName) {
2218            mWebServer = webServer;
2219            mHtmlPath = "/" + htmlPageName;
2220            mHtmlUrl = webServer.setResponse(
2221                    mHtmlPath, "<html manifest=\"" + manifestName + "\"></html>", null);
2222            mManifestPath = "/" + manifestName;
2223            webServer.setResponse(
2224                    mManifestPath,
2225                    "CACHE MANIFEST",
2226                    CommonResources.getContentTypeAndCacheHeaders("text/cache-manifest", false));
2227        }
2228
2229        String getHtmlPath() {
2230            return mHtmlPath;
2231        }
2232
2233        String getHtmlUrl() {
2234            return mHtmlUrl;
2235        }
2236
2237        String getManifestPath() {
2238            return mManifestPath;
2239        }
2240
2241        int waitUntilHtmlIsRequested(final int initialRequestCount) throws Exception {
2242            return waitUntilResourceIsRequested(mHtmlPath, initialRequestCount);
2243        }
2244
2245        int waitUntilManifestIsRequested(final int initialRequestCount) throws Exception {
2246            return waitUntilResourceIsRequested(mManifestPath, initialRequestCount);
2247        }
2248
2249        private int waitUntilResourceIsRequested(
2250                final String path, final int initialRequestCount) throws Exception {
2251            poll(new Callable<Boolean>() {
2252                @Override
2253                public Boolean call() throws Exception {
2254                    return mWebServer.getRequestCount(path) > initialRequestCount;
2255                }
2256            });
2257            return mWebServer.getRequestCount(path);
2258        }
2259    }
2260
2261    @SmallTest
2262    @Feature({"AndroidWebView", "Preferences", "AppCache"})
2263    public void testAppCache() throws Throwable {
2264        final TestAwContentsClient contentClient = new TestAwContentsClient();
2265        final AwTestContainerView testContainer =
2266                createAwTestContainerViewOnMainSync(contentClient);
2267        final AwContents awContents = testContainer.getAwContents();
2268        final AwSettings settings = getAwSettingsOnUiThread(awContents);
2269        settings.setJavaScriptEnabled(true);
2270        // Note that the cache isn't actually enabled until the call to setAppCachePath.
2271        settings.setAppCacheEnabled(true);
2272
2273        TestWebServer webServer = null;
2274        try {
2275            webServer = new TestWebServer(false);
2276            ManifestTestHelper helper = new ManifestTestHelper(
2277                    webServer, "testAppCache.html", "appcache.manifest");
2278            loadUrlSync(
2279                    awContents,
2280                    contentClient.getOnPageFinishedHelper(),
2281                    helper.getHtmlUrl());
2282            helper.waitUntilHtmlIsRequested(0);
2283            // Unfortunately, there is no other good way of verifying that AppCache is
2284            // disabled, other than checking that it didn't try to fetch the manifest.
2285            Thread.sleep(1000);
2286            assertEquals(0, webServer.getRequestCount(helper.getManifestPath()));
2287            settings.setAppCachePath("whatever");  // Enables AppCache.
2288            loadUrlSync(
2289                    awContents,
2290                    contentClient.getOnPageFinishedHelper(),
2291                    helper.getHtmlUrl());
2292            helper.waitUntilManifestIsRequested(0);
2293        } finally {
2294            if (webServer != null) webServer.shutdown();
2295        }
2296    }
2297
2298    @SmallTest
2299    @Feature({"AndroidWebView", "Preferences", "AppCache"})
2300    public void testAppCacheWithTwoViews() throws Throwable {
2301        // We don't use the test helper here, because making sure that AppCache
2302        // is disabled takes a lot of time, so running through the usual drill
2303        // will take about 20 seconds.
2304        ViewPair views = createViews();
2305
2306        AwSettings settings0 = getAwSettingsOnUiThread(views.getContents0());
2307        settings0.setJavaScriptEnabled(true);
2308        settings0.setAppCachePath("whatever");
2309        settings0.setAppCacheEnabled(true);
2310        AwSettings settings1 = getAwSettingsOnUiThread(views.getContents1());
2311        settings1.setJavaScriptEnabled(true);
2312        // AppCachePath setting is global, no need to set it for the second view.
2313        settings1.setAppCacheEnabled(true);
2314
2315        TestWebServer webServer = null;
2316        try {
2317            webServer = new TestWebServer(false);
2318            ManifestTestHelper helper0 = new ManifestTestHelper(
2319                    webServer, "testAppCache_0.html", "appcache.manifest_0");
2320            loadUrlSync(
2321                    views.getContents0(),
2322                    views.getClient0().getOnPageFinishedHelper(),
2323                    helper0.getHtmlUrl());
2324            int manifestRequests0 = helper0.waitUntilManifestIsRequested(0);
2325            ManifestTestHelper helper1 = new ManifestTestHelper(
2326                    webServer, "testAppCache_1.html", "appcache.manifest_1");
2327            loadUrlSync(
2328                    views.getContents1(),
2329                    views.getClient1().getOnPageFinishedHelper(),
2330                    helper1.getHtmlUrl());
2331            helper1.waitUntilManifestIsRequested(0);
2332            settings1.setAppCacheEnabled(false);
2333            loadUrlSync(
2334                    views.getContents0(),
2335                    views.getClient0().getOnPageFinishedHelper(),
2336                    helper0.getHtmlUrl());
2337            helper0.waitUntilManifestIsRequested(manifestRequests0);
2338            final int prevManifestRequestCount =
2339                    webServer.getRequestCount(helper1.getManifestPath());
2340            int htmlRequests1 = webServer.getRequestCount(helper1.getHtmlPath());
2341            loadUrlSync(
2342                    views.getContents1(),
2343                    views.getClient1().getOnPageFinishedHelper(),
2344                    helper1.getHtmlUrl());
2345            helper1.waitUntilHtmlIsRequested(htmlRequests1);
2346            // Unfortunately, there is no other good way of verifying that AppCache is
2347            // disabled, other than checking that it didn't try to fetch the manifest.
2348            Thread.sleep(1000);
2349            assertEquals(
2350                    prevManifestRequestCount, webServer.getRequestCount(helper1.getManifestPath()));
2351        } finally {
2352            if (webServer != null) webServer.shutdown();
2353        }
2354    }
2355
2356    @SmallTest
2357    @Feature({"AndroidWebView", "Preferences"})
2358    public void testUseWideViewportWithTwoViews() throws Throwable {
2359        ViewPair views = createViews(true);
2360        runPerViewSettingsTest(
2361            new AwSettingsUseWideViewportTestHelper(views.getContainer0(), views.getClient0()),
2362            new AwSettingsUseWideViewportTestHelper(views.getContainer1(), views.getClient1()));
2363    }
2364
2365    @SmallTest
2366    @Feature({"AndroidWebView", "Preferences"})
2367    public void testUseWideViewportWithTwoViewsNoQuirks() throws Throwable {
2368        ViewPair views = createViews();
2369        runPerViewSettingsTest(
2370            new AwSettingsUseWideViewportTestHelper(views.getContainer0(), views.getClient0()),
2371            new AwSettingsUseWideViewportTestHelper(views.getContainer1(), views.getClient1()));
2372    }
2373
2374    private void useWideViewportLayoutWidthTest(
2375            AwTestContainerView testContainer, CallbackHelper onPageFinishedHelper)
2376            throws Throwable {
2377        final AwContents awContents = testContainer.getAwContents();
2378        AwSettings settings = getAwSettingsOnUiThread(awContents);
2379
2380        final String pageTemplate = "<html><head>%s</head>" +
2381                "<body onload='document.title=document.body.clientWidth'></body></html>";
2382        final String pageNoViewport = String.format(pageTemplate, "");
2383        final String pageViewportDeviceWidth = String.format(
2384                pageTemplate,
2385                "<meta name='viewport' content='width=device-width' />");
2386        final String viewportTagSpecifiedWidth = "3000";
2387        final String pageViewportSpecifiedWidth = String.format(
2388                pageTemplate,
2389                "<meta name='viewport' content='width=" + viewportTagSpecifiedWidth + "' />");
2390
2391        DeviceDisplayInfo deviceInfo = DeviceDisplayInfo.create(testContainer.getContext());
2392        int displayWidth = (int) (deviceInfo.getDisplayWidth() / deviceInfo.getDIPScale());
2393
2394        settings.setJavaScriptEnabled(true);
2395        assertFalse(settings.getUseWideViewPort());
2396        // When UseWideViewPort is off, "width" setting of "meta viewport"
2397        // tags is ignored, and the layout width is set to device width in CSS pixels.
2398        // Thus, all 3 pages will have the same body width.
2399        loadDataSync(awContents, onPageFinishedHelper, pageNoViewport, "text/html", false);
2400        int actualWidth = Integer.parseInt(getTitleOnUiThread(awContents));
2401        // Avoid rounding errors.
2402        assertTrue("Expected: " + displayWidth + ", Actual: " + actualWidth,
2403                Math.abs(displayWidth - actualWidth) <= 1);
2404        loadDataSync(awContents, onPageFinishedHelper, pageViewportDeviceWidth, "text/html", false);
2405        actualWidth = Integer.parseInt(getTitleOnUiThread(awContents));
2406        assertTrue("Expected: " + displayWidth + ", Actual: " + actualWidth,
2407                Math.abs(displayWidth - actualWidth) <= 1);
2408        loadDataSync(
2409                awContents, onPageFinishedHelper, pageViewportSpecifiedWidth, "text/html", false);
2410        actualWidth = Integer.parseInt(getTitleOnUiThread(awContents));
2411        assertTrue("Expected: " + displayWidth + ", Actual: " + actualWidth,
2412                Math.abs(displayWidth - actualWidth) <= 1);
2413
2414        settings.setUseWideViewPort(true);
2415        // When UseWideViewPort is on, "meta viewport" tag is used.
2416        // If there is no viewport tag, or width isn't specified,
2417        // then layout width is set to max(980, <device-width-in-DIP-pixels>)
2418        loadDataSync(awContents, onPageFinishedHelper, pageNoViewport, "text/html", false);
2419        actualWidth = Integer.parseInt(getTitleOnUiThread(awContents));
2420        assertTrue("Expected: >= 980 , Actual: " + actualWidth, actualWidth >= 980);
2421        loadDataSync(awContents, onPageFinishedHelper, pageViewportDeviceWidth, "text/html", false);
2422        actualWidth = Integer.parseInt(getTitleOnUiThread(awContents));
2423        assertTrue("Expected: " + displayWidth + ", Actual: " + actualWidth,
2424                Math.abs(displayWidth - actualWidth) <= 1);
2425        loadDataSync(
2426                awContents, onPageFinishedHelper, pageViewportSpecifiedWidth, "text/html", false);
2427        assertEquals(viewportTagSpecifiedWidth, getTitleOnUiThread(awContents));
2428    }
2429
2430    @SmallTest
2431    @Feature({"AndroidWebView", "Preferences"})
2432    public void testUseWideViewportLayoutWidth() throws Throwable {
2433        TestAwContentsClient contentClient = new TestAwContentsClient();
2434        AwTestContainerView testContainerView =
2435                createAwTestContainerViewOnMainSync(contentClient);
2436        useWideViewportLayoutWidthTest(testContainerView, contentClient.getOnPageFinishedHelper());
2437    }
2438
2439    @SmallTest
2440    @Feature({"AndroidWebView", "Preferences"})
2441    public void testUseWideViewportLayoutWidthNoQuirks() throws Throwable {
2442        TestAwContentsClient contentClient = new TestAwContentsClient();
2443        AwTestContainerView testContainerView =
2444                createAwTestContainerViewOnMainSync(contentClient, false);
2445        useWideViewportLayoutWidthTest(testContainerView, contentClient.getOnPageFinishedHelper());
2446    }
2447
2448    @MediumTest
2449    @Feature({"AndroidWebView", "Preferences"})
2450    public void testUseWideViewportControlsDoubleTabToZoom() throws Throwable {
2451        final TestAwContentsClient contentClient = new TestAwContentsClient();
2452        final AwTestContainerView testContainerView =
2453                createAwTestContainerViewOnMainSync(contentClient);
2454        final AwContents awContents = testContainerView.getAwContents();
2455        CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
2456        AwSettings settings = getAwSettingsOnUiThread(awContents);
2457        settings.setBuiltInZoomControls(true);
2458
2459        DeviceDisplayInfo deviceInfo =
2460                DeviceDisplayInfo.create(testContainerView.getContext());
2461        int displayWidth = (int) (deviceInfo.getDisplayWidth() / deviceInfo.getDIPScale());
2462        int layoutWidth = displayWidth * 2;
2463        final String page = "<html>" +
2464                "<head><meta name='viewport' content='width=" + layoutWidth + "'>" +
2465                "<style> body { width: " + layoutWidth + "px; }</style></head>" +
2466                "<body>Page Text</body></html>";
2467
2468        assertFalse(settings.getUseWideViewPort());
2469        // Without wide viewport the <meta viewport> tag will be ignored by WebView,
2470        // but it doesn't really matter as we don't expect double tap to change the scale.
2471        loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
2472        final float initialScale = getScaleOnUiThread(awContents);
2473        simulateDoubleTapCenterOfWebViewOnUiThread(testContainerView);
2474        Thread.sleep(1000);
2475        assertEquals(initialScale, getScaleOnUiThread(awContents));
2476
2477        settings.setUseWideViewPort(true);
2478        loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
2479        int onScaleChangedCallCount = contentClient.getOnScaleChangedHelper().getCallCount();
2480        simulateDoubleTapCenterOfWebViewOnUiThread(testContainerView);
2481        contentClient.getOnScaleChangedHelper().waitForCallback(onScaleChangedCallCount);
2482        final float zoomedOutScale = getScaleOnUiThread(awContents);
2483        assertTrue("zoomedOut: " + zoomedOutScale + ", initial: " + initialScale,
2484                zoomedOutScale < initialScale);
2485    }
2486
2487    @SmallTest
2488    @Feature({"AndroidWebView", "Preferences"})
2489    public void testLoadWithOverviewModeWithTwoViews() throws Throwable {
2490        ViewPair views = createViews();
2491        runPerViewSettingsTest(
2492                new AwSettingsLoadWithOverviewModeTestHelper(
2493                        views.getContainer0(), views.getClient0(), false),
2494                new AwSettingsLoadWithOverviewModeTestHelper(
2495                        views.getContainer1(), views.getClient1(), false));
2496    }
2497
2498    @SmallTest
2499    @Feature({"AndroidWebView", "Preferences"})
2500    public void testLoadWithOverviewModeViewportTagWithTwoViews() throws Throwable {
2501        ViewPair views = createViews();
2502        runPerViewSettingsTest(
2503                new AwSettingsLoadWithOverviewModeTestHelper(
2504                        views.getContainer0(), views.getClient0(), true),
2505                new AwSettingsLoadWithOverviewModeTestHelper(
2506                        views.getContainer1(), views.getClient1(), true));
2507    }
2508
2509    @SmallTest
2510    @Feature({"AndroidWebView", "Preferences"})
2511    public void testSetInitialScale() throws Throwable {
2512        final TestAwContentsClient contentClient = new TestAwContentsClient();
2513        final AwTestContainerView testContainerView =
2514                createAwTestContainerViewOnMainSync(contentClient);
2515        final AwContents awContents = testContainerView.getAwContents();
2516        final AwSettings awSettings = getAwSettingsOnUiThread(awContents);
2517        CallbackHelper onPageFinishedHelper = contentClient.getOnPageFinishedHelper();
2518
2519        WindowManager wm = (WindowManager) getInstrumentation().getTargetContext()
2520                .getSystemService(Context.WINDOW_SERVICE);
2521        Point screenSize = new Point();
2522        wm.getDefaultDisplay().getSize(screenSize);
2523        // Make sure after 50% scale, page width still larger than screen.
2524        int height = screenSize.y * 2 + 1;
2525        int width = screenSize.x * 2 + 1;
2526        final String page = "<html><body>" +
2527                "<p style='height:" + height + "px;width:" + width + "px'>" +
2528                "testSetInitialScale</p></body></html>";
2529        final float defaultScale =
2530            getInstrumentation().getTargetContext().getResources().getDisplayMetrics().density;
2531
2532        assertEquals(defaultScale, getPixelScaleOnUiThread(awContents), .01f);
2533        loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
2534        assertEquals(defaultScale, getPixelScaleOnUiThread(awContents), .01f);
2535
2536        int onScaleChangedCallCount = contentClient.getOnScaleChangedHelper().getCallCount();
2537        awSettings.setInitialPageScale(50);
2538        loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
2539        contentClient.getOnScaleChangedHelper().waitForCallback(onScaleChangedCallCount);
2540        assertEquals(0.5f, getPixelScaleOnUiThread(awContents), .01f);
2541
2542        onScaleChangedCallCount = contentClient.getOnScaleChangedHelper().getCallCount();
2543        awSettings.setInitialPageScale(500);
2544        loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
2545        contentClient.getOnScaleChangedHelper().waitForCallback(onScaleChangedCallCount);
2546        assertEquals(5.0f, getPixelScaleOnUiThread(awContents), .01f);
2547
2548        onScaleChangedCallCount = contentClient.getOnScaleChangedHelper().getCallCount();
2549        awSettings.setInitialPageScale(0);
2550        loadDataSync(awContents, onPageFinishedHelper, page, "text/html", false);
2551        contentClient.getOnScaleChangedHelper().waitForCallback(onScaleChangedCallCount);
2552        assertEquals(defaultScale, getPixelScaleOnUiThread(awContents), .01f);
2553    }
2554
2555    /*
2556    @LargeTest
2557    @Feature({"AndroidWebView", "Preferences"})
2558    http://crbug.com/304549
2559    */
2560    @DisabledTest
2561    public void testMediaPlaybackWithoutUserGesture() throws Throwable {
2562        assertTrue(VideoTestUtil.runVideoTest(this, false, WAIT_TIMEOUT_MS));
2563    }
2564
2565    @SmallTest
2566    @Feature({"AndroidWebView", "Preferences"})
2567    public void testMediaPlaybackWithUserGesture() throws Throwable {
2568        // Wait for 5 second to see if video played.
2569        assertFalse(VideoTestUtil.runVideoTest(this, true, scaleTimeout(5000)));
2570    }
2571
2572    @SmallTest
2573    @Feature({"AndroidWebView", "Preferences"})
2574    public void testDefaultVideoPosterURL() throws Throwable {
2575        final CallbackHelper videoPosterAccessedCallbackHelper = new CallbackHelper();
2576        final String DEFAULT_VIDEO_POSTER_URL = "http://default_video_poster/";
2577        TestAwContentsClient client = new TestAwContentsClient() {
2578            @Override
2579            public AwWebResourceResponse shouldInterceptRequest(
2580                    ShouldInterceptRequestParams params) {
2581                if (params.url.equals(DEFAULT_VIDEO_POSTER_URL)) {
2582                    videoPosterAccessedCallbackHelper.notifyCalled();
2583                }
2584                return null;
2585            }
2586        };
2587        final AwContents awContents = createAwTestContainerViewOnMainSync(client).getAwContents();
2588        getInstrumentation().runOnMainSync(new Runnable() {
2589            @Override
2590            public void run() {
2591                AwSettings awSettings = awContents.getSettings();
2592                awSettings.setDefaultVideoPosterURL(DEFAULT_VIDEO_POSTER_URL);
2593            }
2594        });
2595        VideoTestWebServer webServer = new VideoTestWebServer(
2596                getInstrumentation().getTargetContext());
2597        try {
2598            String data = "<html><head><body>" +
2599                "<video id='video' control src='" +
2600                webServer.getOnePixelOneFrameWebmURL() + "' /> </body></html>";
2601            loadDataAsync(awContents, data, "text/html", false);
2602            videoPosterAccessedCallbackHelper.waitForCallback(0, 1, 20, TimeUnit.SECONDS);
2603        } finally {
2604            if (webServer.getTestWebServer() != null)
2605                webServer.getTestWebServer().shutdown();
2606        }
2607    }
2608
2609    @SmallTest
2610    @Feature({"AndroidWebView", "Preferences"})
2611    public void testAllowMixedMode() throws Throwable {
2612        final TestAwContentsClient contentClient = new TestAwContentsClient() {
2613            @Override
2614            public void onReceivedSslError(ValueCallback<Boolean> callback, SslError error) {
2615                callback.onReceiveValue(true);
2616            }
2617        };
2618        final AwTestContainerView testContainerView =
2619                createAwTestContainerViewOnMainSync(contentClient);
2620        final AwContents awContents = testContainerView.getAwContents();
2621        final AwSettings awSettings = getAwSettingsOnUiThread(awContents);
2622
2623        awSettings.setJavaScriptEnabled(true);
2624
2625        TestWebServer httpsServer = new TestWebServer(true);
2626        TestWebServer httpServer = new TestWebServer(false);
2627
2628        final String JS_URL = "/insecure.js";
2629        final String IMG_URL = "/insecure.png";
2630        final String SECURE_URL = "/secure.html";
2631        httpServer.setResponse(JS_URL, "window.loaded_js = 42;", null);
2632        httpServer.setResponseBase64(IMG_URL, CommonResources.FAVICON_DATA_BASE64, null);
2633
2634        final String JS_HTML = "<script src=\"" + httpServer.getResponseUrl(JS_URL) +
2635                "\"></script>";
2636        final String IMG_HTML = "<img src=\"" + httpServer.getResponseUrl(IMG_URL) + "\" />";
2637        final String SECURE_HTML = "<body>" + IMG_HTML + " " + JS_HTML + "</body>";
2638
2639        String secureUrl = httpsServer.setResponse(SECURE_URL, SECURE_HTML, null);
2640
2641        awSettings.setMixedContentMode(AwSettings.MIXED_CONTENT_NEVER_ALLOW);
2642        loadUrlSync(awContents, contentClient.getOnPageFinishedHelper(), secureUrl);
2643        assertEquals(1, httpsServer.getRequestCount(SECURE_URL));
2644        assertEquals(0, httpServer.getRequestCount(JS_URL));
2645        assertEquals(0, httpServer.getRequestCount(IMG_URL));
2646
2647        awSettings.setMixedContentMode(AwSettings.MIXED_CONTENT_ALWAYS_ALLOW);
2648        loadUrlSync(awContents, contentClient.getOnPageFinishedHelper(), secureUrl);
2649        assertEquals(2, httpsServer.getRequestCount(SECURE_URL));
2650        assertEquals(1, httpServer.getRequestCount(JS_URL));
2651        assertEquals(1, httpServer.getRequestCount(IMG_URL));
2652
2653        awSettings.setMixedContentMode(AwSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
2654        loadUrlSync(awContents, contentClient.getOnPageFinishedHelper(), secureUrl);
2655        assertEquals(3, httpsServer.getRequestCount(SECURE_URL));
2656        assertEquals(1, httpServer.getRequestCount(JS_URL));
2657        assertEquals(2, httpServer.getRequestCount(IMG_URL));
2658
2659        httpServer.shutdown();
2660        httpsServer.shutdown();
2661    }
2662
2663
2664    static class ViewPair {
2665        private final AwTestContainerView mContainer0;
2666        private final TestAwContentsClient mClient0;
2667        private final AwTestContainerView mContainer1;
2668        private final TestAwContentsClient mClient1;
2669
2670        ViewPair(AwTestContainerView container0, TestAwContentsClient client0,
2671                 AwTestContainerView container1, TestAwContentsClient client1) {
2672            this.mContainer0 = container0;
2673            this.mClient0 = client0;
2674            this.mContainer1 = container1;
2675            this.mClient1 = client1;
2676        }
2677
2678        AwTestContainerView getContainer0() {
2679            return mContainer0;
2680        }
2681
2682        AwContents getContents0() {
2683            return mContainer0.getAwContents();
2684        }
2685
2686        TestAwContentsClient getClient0() {
2687            return mClient0;
2688        }
2689
2690        AwTestContainerView getContainer1() {
2691            return mContainer1;
2692        }
2693
2694        AwContents getContents1() {
2695            return mContainer1.getAwContents();
2696        }
2697
2698        TestAwContentsClient getClient1() {
2699            return mClient1;
2700        }
2701    }
2702
2703    /**
2704     * Verifies the following statements about a setting:
2705     *  - initially, the setting has a default value;
2706     *  - the setting can be switched to an alternate value and back;
2707     *  - switching a setting in the first WebView doesn't affect the setting
2708     *    state in the second WebView and vice versa.
2709     *
2710     * @param helper0 Test helper for the first ContentView
2711     * @param helper1 Test helper for the second ContentView
2712     * @throws Throwable
2713     */
2714    private void runPerViewSettingsTest(AwSettingsTestHelper helper0,
2715                                        AwSettingsTestHelper helper1) throws Throwable {
2716        helper0.ensureSettingHasInitialValue();
2717        helper1.ensureSettingHasInitialValue();
2718
2719        helper1.setAlteredSettingValue();
2720        helper0.ensureSettingHasInitialValue();
2721        helper1.ensureSettingHasAlteredValue();
2722
2723        helper1.setInitialSettingValue();
2724        helper0.ensureSettingHasInitialValue();
2725        helper1.ensureSettingHasInitialValue();
2726
2727        helper0.setAlteredSettingValue();
2728        helper0.ensureSettingHasAlteredValue();
2729        helper1.ensureSettingHasInitialValue();
2730
2731        helper0.setInitialSettingValue();
2732        helper0.ensureSettingHasInitialValue();
2733        helper1.ensureSettingHasInitialValue();
2734
2735        helper0.setAlteredSettingValue();
2736        helper0.ensureSettingHasAlteredValue();
2737        helper1.ensureSettingHasInitialValue();
2738
2739        helper1.setAlteredSettingValue();
2740        helper0.ensureSettingHasAlteredValue();
2741        helper1.ensureSettingHasAlteredValue();
2742
2743        helper0.setInitialSettingValue();
2744        helper0.ensureSettingHasInitialValue();
2745        helper1.ensureSettingHasAlteredValue();
2746
2747        helper1.setInitialSettingValue();
2748        helper0.ensureSettingHasInitialValue();
2749        helper1.ensureSettingHasInitialValue();
2750    }
2751
2752    private ViewPair createViews() throws Throwable {
2753        return createViews(false);
2754    }
2755
2756    private ViewPair createViews(boolean supportsLegacyQuirks) throws Throwable {
2757        TestAwContentsClient client0 = new TestAwContentsClient();
2758        TestAwContentsClient client1 = new TestAwContentsClient();
2759        return new ViewPair(
2760            createAwTestContainerViewOnMainSync(client0, supportsLegacyQuirks),
2761            client0,
2762            createAwTestContainerViewOnMainSync(client1, supportsLegacyQuirks),
2763            client1);
2764    }
2765
2766    static void assertFileIsReadable(String filePath) {
2767        File file = new File(filePath);
2768        try {
2769            assertTrue("Test file \"" + filePath + "\" is not readable." +
2770                    "Please make sure that files from android_webview/test/data/device_files/ " +
2771                    "has been pushed to the device before testing",
2772                    file.canRead());
2773        } catch (SecurityException e) {
2774            fail("Got a SecurityException for \"" + filePath + "\": " + e.toString());
2775        }
2776    }
2777
2778    /**
2779     * Verifies the number of resource requests made to the content provider.
2780     * @param resource Resource name
2781     * @param expectedCount Expected resource requests count
2782     */
2783    private void ensureResourceRequestCountInContentProvider(String resource, int expectedCount) {
2784        Context context = getInstrumentation().getTargetContext();
2785        int actualCount = TestContentProvider.getResourceRequestCount(context, resource);
2786        assertEquals(expectedCount, actualCount);
2787    }
2788
2789    private void resetResourceRequestCountInContentProvider(String resource) {
2790        Context context = getInstrumentation().getTargetContext();
2791        TestContentProvider.resetResourceRequestCount(context, resource);
2792    }
2793
2794    private String createContentUrl(final String target) {
2795        return TestContentProvider.createContentUrl(target);
2796    }
2797
2798    private void simulateDoubleTapCenterOfWebViewOnUiThread(final AwTestContainerView webView)
2799            throws Throwable {
2800        final int x = (webView.getRight() - webView.getLeft()) / 2;
2801        final int y = (webView.getBottom() - webView.getTop()) / 2;
2802        final AwContents awContents = webView.getAwContents();
2803        runTestOnUiThread(new Runnable() {
2804            @Override
2805            public void run() {
2806                awContents.getContentViewCore().sendDoubleTapForTest(
2807                        SystemClock.uptimeMillis(), x, y);
2808            }
2809        });
2810    }
2811}
2812