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