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