Home | History | Annotate | Download | only in test
      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 
      5 package org.chromium.android_webview.test;
      6 
      7 import android.content.Context;
      8 import android.graphics.Point;
      9 import android.net.http.SslError;
     10 import android.os.Build;
     11 import android.os.SystemClock;
     12 import android.test.suitebuilder.annotation.MediumTest;
     13 import android.test.suitebuilder.annotation.SmallTest;
     14 import android.view.WindowManager;
     15 import android.webkit.JavascriptInterface;
     16 import android.webkit.ValueCallback;
     17 import android.webkit.WebSettings;
     18 
     19 import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
     20 
     21 import org.apache.http.Header;
     22 import org.apache.http.HttpRequest;
     23 import org.chromium.android_webview.AwContents;
     24 import org.chromium.android_webview.AwContentsClient.ShouldInterceptRequestParams;
     25 import org.chromium.android_webview.AwSettings;
     26 import org.chromium.android_webview.AwSettings.LayoutAlgorithm;
     27 import org.chromium.android_webview.AwWebResourceResponse;
     28 import org.chromium.android_webview.test.util.CommonResources;
     29 import org.chromium.android_webview.test.util.ImagePageGenerator;
     30 import org.chromium.android_webview.test.util.VideoTestUtil;
     31 import org.chromium.android_webview.test.util.VideoTestWebServer;
     32 import org.chromium.base.test.util.DisabledTest;
     33 import org.chromium.base.test.util.Feature;
     34 import org.chromium.base.test.util.TestFileUtil;
     35 import org.chromium.base.test.util.UrlUtils;
     36 import org.chromium.content.browser.test.util.CallbackHelper;
     37 import org.chromium.content.browser.test.util.HistoryUtils;
     38 import org.chromium.content_public.browser.WebContents;
     39 import org.chromium.net.test.util.TestWebServer;
     40 import org.chromium.ui.gfx.DeviceDisplayInfo;
     41 
     42 import java.io.File;
     43 import java.util.concurrent.Callable;
     44 import java.util.concurrent.TimeUnit;
     45 import java.util.regex.Matcher;
     46 import 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  */
     53 public 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