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