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