Home | History | Annotate | Download | only in browser
      1 
      2 /*
      3  * Copyright (C) 2007 The Android Open Source Project
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package com.android.browser;
     19 
     20 import android.app.ActivityManager;
     21 import android.content.ContentResolver;
     22 import android.content.Context;
     23 import android.content.pm.ActivityInfo;
     24 import android.content.SharedPreferences;
     25 import android.content.SharedPreferences.Editor;
     26 import android.preference.PreferenceActivity;
     27 import android.preference.PreferenceScreen;
     28 import android.webkit.CookieManager;
     29 import android.webkit.GeolocationPermissions;
     30 import android.webkit.ValueCallback;
     31 import android.webkit.WebView;
     32 import android.webkit.WebViewDatabase;
     33 import android.webkit.WebIconDatabase;
     34 import android.webkit.WebSettings;
     35 import android.webkit.WebStorage;
     36 import android.preference.PreferenceManager;
     37 import android.provider.Browser;
     38 
     39 import java.util.HashMap;
     40 import java.util.Map;
     41 import java.util.Set;
     42 import java.util.Observable;
     43 
     44 /*
     45  * Package level class for storing various WebView and Browser settings. To use
     46  * this class:
     47  * BrowserSettings s = BrowserSettings.getInstance();
     48  * s.addObserver(webView.getSettings());
     49  * s.loadFromDb(context); // Only needed on app startup
     50  * s.javaScriptEnabled = true;
     51  * ... // set any other settings
     52  * s.update(); // this will update all the observers
     53  *
     54  * To remove an observer:
     55  * s.deleteObserver(webView.getSettings());
     56  */
     57 class BrowserSettings extends Observable {
     58 
     59     // Private variables for settings
     60     // NOTE: these defaults need to be kept in sync with the XML
     61     // until the performance of PreferenceManager.setDefaultValues()
     62     // is improved.
     63     // Note: boolean variables are set inside reset function.
     64     private boolean loadsImagesAutomatically;
     65     private boolean javaScriptEnabled;
     66     private WebSettings.PluginState pluginState;
     67     private boolean javaScriptCanOpenWindowsAutomatically;
     68     private boolean showSecurityWarnings;
     69     private boolean rememberPasswords;
     70     private boolean saveFormData;
     71     private boolean openInBackground;
     72     private String defaultTextEncodingName;
     73     private String homeUrl = "";
     74     private boolean autoFitPage;
     75     private boolean landscapeOnly;
     76     private boolean loadsPageInOverviewMode;
     77     private boolean showDebugSettings;
     78     // HTML5 API flags
     79     private boolean appCacheEnabled;
     80     private boolean databaseEnabled;
     81     private boolean domStorageEnabled;
     82     private boolean geolocationEnabled;
     83     private boolean workersEnabled;  // only affects V8. JSC does not have a similar setting
     84     // HTML5 API configuration params
     85     private long appCacheMaxSize = Long.MAX_VALUE;
     86     private String appCachePath;  // default value set in loadFromDb().
     87     private String databasePath; // default value set in loadFromDb()
     88     private String geolocationDatabasePath; // default value set in loadFromDb()
     89     private WebStorageSizeManager webStorageSizeManager;
     90 
     91     private String jsFlags = "";
     92 
     93     private final static String TAG = "BrowserSettings";
     94 
     95     // Development settings
     96     public WebSettings.LayoutAlgorithm layoutAlgorithm =
     97         WebSettings.LayoutAlgorithm.NARROW_COLUMNS;
     98     private boolean useWideViewPort = true;
     99     private int userAgent = 0;
    100     private boolean tracing = false;
    101     private boolean lightTouch = false;
    102     private boolean navDump = false;
    103 
    104     // By default the error console is shown once the user navigates to about:debug.
    105     // The setting can be then toggled from the settings menu.
    106     private boolean showConsole = true;
    107 
    108     // Private preconfigured values
    109     private static int minimumFontSize = 8;
    110     private static int minimumLogicalFontSize = 8;
    111     private static int defaultFontSize = 16;
    112     private static int defaultFixedFontSize = 13;
    113     private static WebSettings.TextSize textSize =
    114         WebSettings.TextSize.NORMAL;
    115     private static WebSettings.ZoomDensity zoomDensity =
    116         WebSettings.ZoomDensity.MEDIUM;
    117     private static int pageCacheCapacity;
    118 
    119     // Preference keys that are used outside this class
    120     public final static String PREF_CLEAR_CACHE = "privacy_clear_cache";
    121     public final static String PREF_CLEAR_COOKIES = "privacy_clear_cookies";
    122     public final static String PREF_CLEAR_HISTORY = "privacy_clear_history";
    123     public final static String PREF_HOMEPAGE = "homepage";
    124     public final static String PREF_CLEAR_FORM_DATA =
    125             "privacy_clear_form_data";
    126     public final static String PREF_CLEAR_PASSWORDS =
    127             "privacy_clear_passwords";
    128     public final static String PREF_EXTRAS_RESET_DEFAULTS =
    129             "reset_default_preferences";
    130     public final static String PREF_DEBUG_SETTINGS = "debug_menu";
    131     public final static String PREF_WEBSITE_SETTINGS = "website_settings";
    132     public final static String PREF_TEXT_SIZE = "text_size";
    133     public final static String PREF_DEFAULT_ZOOM = "default_zoom";
    134     public final static String PREF_DEFAULT_TEXT_ENCODING =
    135             "default_text_encoding";
    136     public final static String PREF_CLEAR_GEOLOCATION_ACCESS =
    137             "privacy_clear_geolocation_access";
    138 
    139     private static final String DESKTOP_USERAGENT = "Mozilla/5.0 (Macintosh; " +
    140             "U; Intel Mac OS X 10_5_7; en-us) AppleWebKit/530.17 (KHTML, " +
    141             "like Gecko) Version/4.0 Safari/530.17";
    142 
    143     private static final String IPHONE_USERAGENT = "Mozilla/5.0 (iPhone; U; " +
    144             "CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 " +
    145             "(KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16";
    146 
    147     // Value to truncate strings when adding them to a TextView within
    148     // a ListView
    149     public final static int MAX_TEXTVIEW_LEN = 80;
    150 
    151     private TabControl mTabControl;
    152 
    153     // Single instance of the BrowserSettings for use in the Browser app.
    154     private static BrowserSettings sSingleton;
    155 
    156     // Private map of WebSettings to Observer objects used when deleting an
    157     // observer.
    158     private HashMap<WebSettings,Observer> mWebSettingsToObservers =
    159         new HashMap<WebSettings,Observer>();
    160 
    161     /*
    162      * An observer wrapper for updating a WebSettings object with the new
    163      * settings after a call to BrowserSettings.update().
    164      */
    165     static class Observer implements java.util.Observer {
    166         // Private WebSettings object that will be updated.
    167         private WebSettings mSettings;
    168 
    169         Observer(WebSettings w) {
    170             mSettings = w;
    171         }
    172 
    173         public void update(Observable o, Object arg) {
    174             BrowserSettings b = (BrowserSettings)o;
    175             WebSettings s = mSettings;
    176 
    177             s.setLayoutAlgorithm(b.layoutAlgorithm);
    178             if (b.userAgent == 0) {
    179                 // use the default ua string
    180                 s.setUserAgentString(null);
    181             } else if (b.userAgent == 1) {
    182                 s.setUserAgentString(DESKTOP_USERAGENT);
    183             } else if (b.userAgent == 2) {
    184                 s.setUserAgentString(IPHONE_USERAGENT);
    185             }
    186             s.setUseWideViewPort(b.useWideViewPort);
    187             s.setLoadsImagesAutomatically(b.loadsImagesAutomatically);
    188             s.setJavaScriptEnabled(b.javaScriptEnabled);
    189             s.setPluginState(b.pluginState);
    190             s.setJavaScriptCanOpenWindowsAutomatically(
    191                     b.javaScriptCanOpenWindowsAutomatically);
    192             s.setDefaultTextEncodingName(b.defaultTextEncodingName);
    193             s.setMinimumFontSize(b.minimumFontSize);
    194             s.setMinimumLogicalFontSize(b.minimumLogicalFontSize);
    195             s.setDefaultFontSize(b.defaultFontSize);
    196             s.setDefaultFixedFontSize(b.defaultFixedFontSize);
    197             s.setNavDump(b.navDump);
    198             s.setTextSize(b.textSize);
    199             s.setDefaultZoom(b.zoomDensity);
    200             s.setLightTouchEnabled(b.lightTouch);
    201             s.setSaveFormData(b.saveFormData);
    202             s.setSavePassword(b.rememberPasswords);
    203             s.setLoadWithOverviewMode(b.loadsPageInOverviewMode);
    204             s.setPageCacheCapacity(pageCacheCapacity);
    205 
    206             // WebView inside Browser doesn't want initial focus to be set.
    207             s.setNeedInitialFocus(false);
    208             // Browser supports multiple windows
    209             s.setSupportMultipleWindows(true);
    210 
    211             // HTML5 API flags
    212             s.setAppCacheEnabled(b.appCacheEnabled);
    213             s.setDatabaseEnabled(b.databaseEnabled);
    214             s.setDomStorageEnabled(b.domStorageEnabled);
    215             s.setWorkersEnabled(b.workersEnabled);  // This only affects V8.
    216             s.setGeolocationEnabled(b.geolocationEnabled);
    217 
    218             // HTML5 configuration parameters.
    219             s.setAppCacheMaxSize(b.appCacheMaxSize);
    220             s.setAppCachePath(b.appCachePath);
    221             s.setDatabasePath(b.databasePath);
    222             s.setGeolocationDatabasePath(b.geolocationDatabasePath);
    223 
    224             b.updateTabControlSettings();
    225         }
    226     }
    227 
    228     /**
    229      * Load settings from the browser app's database.
    230      * NOTE: Strings used for the preferences must match those specified
    231      * in the browser_preferences.xml
    232      * @param ctx A Context object used to query the browser's settings
    233      *            database. If the database exists, the saved settings will be
    234      *            stored in this BrowserSettings object. This will update all
    235      *            observers of this object.
    236      */
    237     public void loadFromDb(Context ctx) {
    238         SharedPreferences p =
    239                 PreferenceManager.getDefaultSharedPreferences(ctx);
    240         // Set the default value for the Application Caches path.
    241         appCachePath = ctx.getDir("appcache", 0).getPath();
    242         // Determine the maximum size of the application cache.
    243         webStorageSizeManager = new WebStorageSizeManager(
    244                 ctx,
    245                 new WebStorageSizeManager.StatFsDiskInfo(appCachePath),
    246                 new WebStorageSizeManager.WebKitAppCacheInfo(appCachePath));
    247         appCacheMaxSize = webStorageSizeManager.getAppCacheMaxSize();
    248         // Set the default value for the Database path.
    249         databasePath = ctx.getDir("databases", 0).getPath();
    250         // Set the default value for the Geolocation database path.
    251         geolocationDatabasePath = ctx.getDir("geolocation", 0).getPath();
    252 
    253         if (p.getString(PREF_HOMEPAGE, "") == "") {
    254             // No home page preferences is set, set it to default.
    255             setHomePage(ctx, getFactoryResetHomeUrl(ctx));
    256         }
    257 
    258         // the cost of one cached page is ~3M (measured using nytimes.com). For
    259         // low end devices, we only cache one page. For high end devices, we try
    260         // to cache more pages, currently choose 5.
    261         ActivityManager am = (ActivityManager) ctx
    262                 .getSystemService(Context.ACTIVITY_SERVICE);
    263         if (am.getMemoryClass() > 16) {
    264             pageCacheCapacity = 5;
    265         } else {
    266             pageCacheCapacity = 1;
    267         }
    268 
    269         // Load the defaults from the xml
    270         // This call is TOO SLOW, need to manually keep the defaults
    271         // in sync
    272         //PreferenceManager.setDefaultValues(ctx, R.xml.browser_preferences);
    273         syncSharedPreferences(p);
    274     }
    275 
    276     /* package */ void syncSharedPreferences(SharedPreferences p) {
    277 
    278         homeUrl =
    279             p.getString(PREF_HOMEPAGE, homeUrl);
    280 
    281         loadsImagesAutomatically = p.getBoolean("load_images",
    282                 loadsImagesAutomatically);
    283         javaScriptEnabled = p.getBoolean("enable_javascript",
    284                 javaScriptEnabled);
    285         pluginState = WebSettings.PluginState.valueOf(
    286                 p.getString("plugin_state", pluginState.name()));
    287         javaScriptCanOpenWindowsAutomatically = !p.getBoolean(
    288             "block_popup_windows",
    289             !javaScriptCanOpenWindowsAutomatically);
    290         showSecurityWarnings = p.getBoolean("show_security_warnings",
    291                 showSecurityWarnings);
    292         rememberPasswords = p.getBoolean("remember_passwords",
    293                 rememberPasswords);
    294         saveFormData = p.getBoolean("save_formdata",
    295                 saveFormData);
    296         boolean accept_cookies = p.getBoolean("accept_cookies",
    297                 CookieManager.getInstance().acceptCookie());
    298         CookieManager.getInstance().setAcceptCookie(accept_cookies);
    299         openInBackground = p.getBoolean("open_in_background", openInBackground);
    300         textSize = WebSettings.TextSize.valueOf(
    301                 p.getString(PREF_TEXT_SIZE, textSize.name()));
    302         zoomDensity = WebSettings.ZoomDensity.valueOf(
    303                 p.getString(PREF_DEFAULT_ZOOM, zoomDensity.name()));
    304         autoFitPage = p.getBoolean("autofit_pages", autoFitPage);
    305         loadsPageInOverviewMode = p.getBoolean("load_page",
    306                 loadsPageInOverviewMode);
    307         boolean landscapeOnlyTemp =
    308                 p.getBoolean("landscape_only", landscapeOnly);
    309         if (landscapeOnlyTemp != landscapeOnly) {
    310             landscapeOnly = landscapeOnlyTemp;
    311         }
    312         useWideViewPort = true; // use wide view port for either setting
    313         if (autoFitPage) {
    314             layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS;
    315         } else {
    316             layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL;
    317         }
    318         defaultTextEncodingName =
    319                 p.getString(PREF_DEFAULT_TEXT_ENCODING,
    320                         defaultTextEncodingName);
    321 
    322         showDebugSettings =
    323                 p.getBoolean(PREF_DEBUG_SETTINGS, showDebugSettings);
    324         // Debug menu items have precidence if the menu is visible
    325         if (showDebugSettings) {
    326             boolean small_screen = p.getBoolean("small_screen",
    327                     layoutAlgorithm ==
    328                     WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
    329             if (small_screen) {
    330                 layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN;
    331             } else {
    332                 boolean normal_layout = p.getBoolean("normal_layout",
    333                         layoutAlgorithm == WebSettings.LayoutAlgorithm.NORMAL);
    334                 if (normal_layout) {
    335                     layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL;
    336                 } else {
    337                     layoutAlgorithm =
    338                             WebSettings.LayoutAlgorithm.NARROW_COLUMNS;
    339                 }
    340             }
    341             useWideViewPort = p.getBoolean("wide_viewport", useWideViewPort);
    342             tracing = p.getBoolean("enable_tracing", tracing);
    343             lightTouch = p.getBoolean("enable_light_touch", lightTouch);
    344             navDump = p.getBoolean("enable_nav_dump", navDump);
    345             userAgent = Integer.parseInt(p.getString("user_agent", "0"));
    346         }
    347         // JS flags is loaded from DB even if showDebugSettings is false,
    348         // so that it can be set once and be effective all the time.
    349         jsFlags = p.getString("js_engine_flags", "");
    350 
    351         // Read the setting for showing/hiding the JS Console always so that should the
    352         // user enable debug settings, we already know if we should show the console.
    353         // The user will never see the console unless they navigate to about:debug,
    354         // regardless of the setting we read here. This setting is only used after debug
    355         // is enabled.
    356         showConsole = p.getBoolean("javascript_console", showConsole);
    357 
    358         // HTML5 API flags
    359         appCacheEnabled = p.getBoolean("enable_appcache", appCacheEnabled);
    360         databaseEnabled = p.getBoolean("enable_database", databaseEnabled);
    361         domStorageEnabled = p.getBoolean("enable_domstorage", domStorageEnabled);
    362         geolocationEnabled = p.getBoolean("enable_geolocation", geolocationEnabled);
    363         workersEnabled = p.getBoolean("enable_workers", workersEnabled);
    364 
    365         update();
    366     }
    367 
    368     public String getHomePage() {
    369         return homeUrl;
    370     }
    371 
    372     public String getJsFlags() {
    373         return jsFlags;
    374     }
    375 
    376     public WebStorageSizeManager getWebStorageSizeManager() {
    377         return webStorageSizeManager;
    378     }
    379 
    380     public void setHomePage(Context context, String url) {
    381         Editor ed = PreferenceManager.
    382                 getDefaultSharedPreferences(context).edit();
    383         ed.putString(PREF_HOMEPAGE, url);
    384         ed.commit();
    385         homeUrl = url;
    386     }
    387 
    388     public WebSettings.TextSize getTextSize() {
    389         return textSize;
    390     }
    391 
    392     public WebSettings.ZoomDensity getDefaultZoom() {
    393         return zoomDensity;
    394     }
    395 
    396     public boolean openInBackground() {
    397         return openInBackground;
    398     }
    399 
    400     public boolean showSecurityWarnings() {
    401         return showSecurityWarnings;
    402     }
    403 
    404     public boolean isTracing() {
    405         return tracing;
    406     }
    407 
    408     public boolean isLightTouch() {
    409         return lightTouch;
    410     }
    411 
    412     public boolean isNavDump() {
    413         return navDump;
    414     }
    415 
    416     public boolean showDebugSettings() {
    417         return showDebugSettings;
    418     }
    419 
    420     public void toggleDebugSettings() {
    421         showDebugSettings = !showDebugSettings;
    422         navDump = showDebugSettings;
    423         update();
    424     }
    425 
    426     /**
    427      * Add a WebSettings object to the list of observers that will be updated
    428      * when update() is called.
    429      *
    430      * @param s A WebSettings object that is strictly tied to the life of a
    431      *            WebView.
    432      */
    433     public Observer addObserver(WebSettings s) {
    434         Observer old = mWebSettingsToObservers.get(s);
    435         if (old != null) {
    436             super.deleteObserver(old);
    437         }
    438         Observer o = new Observer(s);
    439         mWebSettingsToObservers.put(s, o);
    440         super.addObserver(o);
    441         return o;
    442     }
    443 
    444     /**
    445      * Delete the given WebSettings observer from the list of observers.
    446      * @param s The WebSettings object to be deleted.
    447      */
    448     public void deleteObserver(WebSettings s) {
    449         Observer o = mWebSettingsToObservers.get(s);
    450         if (o != null) {
    451             mWebSettingsToObservers.remove(s);
    452             super.deleteObserver(o);
    453         }
    454     }
    455 
    456     /*
    457      * Package level method for obtaining a single app instance of the
    458      * BrowserSettings.
    459      */
    460     /*package*/ static BrowserSettings getInstance() {
    461         if (sSingleton == null ) {
    462             sSingleton = new BrowserSettings();
    463         }
    464         return sSingleton;
    465     }
    466 
    467     /*
    468      * Package level method for associating the BrowserSettings with TabControl
    469      */
    470     /* package */void setTabControl(TabControl tabControl) {
    471         mTabControl = tabControl;
    472         updateTabControlSettings();
    473     }
    474 
    475     /*
    476      * Update all the observers of the object.
    477      */
    478     /*package*/ void update() {
    479         setChanged();
    480         notifyObservers();
    481     }
    482 
    483     /*package*/ void clearCache(Context context) {
    484         WebIconDatabase.getInstance().removeAllIcons();
    485         if (mTabControl != null) {
    486             WebView current = mTabControl.getCurrentWebView();
    487             if (current != null) {
    488                 current.clearCache(true);
    489             }
    490         }
    491     }
    492 
    493     /*package*/ void clearCookies(Context context) {
    494         CookieManager.getInstance().removeAllCookie();
    495     }
    496 
    497     /* package */void clearHistory(Context context) {
    498         ContentResolver resolver = context.getContentResolver();
    499         Browser.clearHistory(resolver);
    500         Browser.clearSearches(resolver);
    501     }
    502 
    503     /* package */ void clearFormData(Context context) {
    504         WebViewDatabase.getInstance(context).clearFormData();
    505         if (mTabControl != null) {
    506             mTabControl.getCurrentTopWebView().clearFormData();
    507         }
    508     }
    509 
    510     /*package*/ void clearPasswords(Context context) {
    511         WebViewDatabase db = WebViewDatabase.getInstance(context);
    512         db.clearUsernamePassword();
    513         db.clearHttpAuthUsernamePassword();
    514     }
    515 
    516     private void updateTabControlSettings() {
    517         // Enable/disable the error console.
    518         mTabControl.getBrowserActivity().setShouldShowErrorConsole(
    519             showDebugSettings && showConsole);
    520         mTabControl.getBrowserActivity().setRequestedOrientation(
    521             landscapeOnly ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
    522             : ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
    523     }
    524 
    525     private void maybeDisableWebsiteSettings(Context context) {
    526         PreferenceActivity activity = (PreferenceActivity) context;
    527         final PreferenceScreen screen = (PreferenceScreen)
    528             activity.findPreference(BrowserSettings.PREF_WEBSITE_SETTINGS);
    529         screen.setEnabled(false);
    530         WebStorage.getInstance().getOrigins(new ValueCallback<Map>() {
    531             public void onReceiveValue(Map webStorageOrigins) {
    532                 if ((webStorageOrigins != null) && !webStorageOrigins.isEmpty()) {
    533                     screen.setEnabled(true);
    534                 }
    535             }
    536         });
    537 
    538         GeolocationPermissions.getInstance().getOrigins(new ValueCallback<Set<String> >() {
    539             public void onReceiveValue(Set<String> geolocationOrigins) {
    540                 if ((geolocationOrigins != null) && !geolocationOrigins.isEmpty()) {
    541                     screen.setEnabled(true);
    542                 }
    543             }
    544         });
    545     }
    546 
    547     /*package*/ void clearDatabases(Context context) {
    548         WebStorage.getInstance().deleteAllData();
    549         maybeDisableWebsiteSettings(context);
    550     }
    551 
    552     /*package*/ void clearLocationAccess(Context context) {
    553         GeolocationPermissions.getInstance().clearAll();
    554         maybeDisableWebsiteSettings(context);
    555     }
    556 
    557     /*package*/ void resetDefaultPreferences(Context ctx) {
    558         reset();
    559         SharedPreferences p =
    560             PreferenceManager.getDefaultSharedPreferences(ctx);
    561         p.edit().clear().commit();
    562         PreferenceManager.setDefaultValues(ctx, R.xml.browser_preferences,
    563                 true);
    564         // reset homeUrl
    565         setHomePage(ctx, getFactoryResetHomeUrl(ctx));
    566         // reset appcache max size
    567         appCacheMaxSize = webStorageSizeManager.getAppCacheMaxSize();
    568     }
    569 
    570     private String getFactoryResetHomeUrl(Context context) {
    571         String url = context.getResources().getString(R.string.homepage_base);
    572         if (url.indexOf("{CID}") != -1) {
    573             url = url.replace("{CID}",
    574                     BrowserProvider.getClientId(context.getContentResolver()));
    575         }
    576         return url;
    577     }
    578 
    579     // Private constructor that does nothing.
    580     private BrowserSettings() {
    581         reset();
    582     }
    583 
    584     private void reset() {
    585         // Private variables for settings
    586         // NOTE: these defaults need to be kept in sync with the XML
    587         // until the performance of PreferenceManager.setDefaultValues()
    588         // is improved.
    589         loadsImagesAutomatically = true;
    590         javaScriptEnabled = true;
    591         pluginState = WebSettings.PluginState.ON;
    592         javaScriptCanOpenWindowsAutomatically = false;
    593         showSecurityWarnings = true;
    594         rememberPasswords = true;
    595         saveFormData = true;
    596         openInBackground = false;
    597         autoFitPage = true;
    598         landscapeOnly = false;
    599         loadsPageInOverviewMode = true;
    600         showDebugSettings = false;
    601         // HTML5 API flags
    602         appCacheEnabled = true;
    603         databaseEnabled = true;
    604         domStorageEnabled = true;
    605         geolocationEnabled = true;
    606         workersEnabled = true;  // only affects V8. JSC does not have a similar setting
    607     }
    608 }
    609