Home | History | Annotate | Download | only in browser
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.browser;
     18 
     19 import android.app.ActivityManager;
     20 import android.content.ContentResolver;
     21 import android.content.Context;
     22 import android.content.SharedPreferences;
     23 import android.content.SharedPreferences.Editor;
     24 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
     25 import android.net.ConnectivityManager;
     26 import android.net.NetworkInfo;
     27 import android.os.Build;
     28 import android.os.Message;
     29 import android.preference.PreferenceManager;
     30 import android.provider.Browser;
     31 import android.provider.Settings;
     32 import android.util.DisplayMetrics;
     33 import android.webkit.CookieManager;
     34 import android.webkit.GeolocationPermissions;
     35 import android.webkit.WebIconDatabase;
     36 import android.webkit.WebSettings;
     37 import android.webkit.WebSettings.LayoutAlgorithm;
     38 import android.webkit.WebSettings.PluginState;
     39 import android.webkit.WebSettings.TextSize;
     40 import android.webkit.WebSettings.ZoomDensity;
     41 import android.webkit.WebSettingsClassic;
     42 import android.webkit.WebSettingsClassic.AutoFillProfile;
     43 import android.webkit.WebStorage;
     44 import android.webkit.WebView;
     45 import android.webkit.WebViewDatabase;
     46 
     47 import com.android.browser.homepages.HomeProvider;
     48 import com.android.browser.provider.BrowserProvider;
     49 import com.android.browser.search.SearchEngine;
     50 import com.android.browser.search.SearchEngines;
     51 
     52 import java.lang.ref.WeakReference;
     53 import java.util.Iterator;
     54 import java.util.LinkedList;
     55 import java.util.WeakHashMap;
     56 
     57 /**
     58  * Class for managing settings
     59  */
     60 public class BrowserSettings implements OnSharedPreferenceChangeListener,
     61         PreferenceKeys {
     62 
     63     // TODO: Do something with this UserAgent stuff
     64     private static final String DESKTOP_USERAGENT = "Mozilla/5.0 (X11; " +
     65         "Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) " +
     66         "Chrome/11.0.696.34 Safari/534.24";
     67 
     68     private static final String IPHONE_USERAGENT = "Mozilla/5.0 (iPhone; U; " +
     69         "CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 " +
     70         "(KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7";
     71 
     72     private static final String IPAD_USERAGENT = "Mozilla/5.0 (iPad; U; " +
     73         "CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 " +
     74         "(KHTML, like Gecko) Version/4.0.4 Mobile/7B367 Safari/531.21.10";
     75 
     76     private static final String FROYO_USERAGENT = "Mozilla/5.0 (Linux; U; " +
     77         "Android 2.2; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 " +
     78         "(KHTML, like Gecko) Version/4.0 Mobile Safari/533.1";
     79 
     80     private static final String HONEYCOMB_USERAGENT = "Mozilla/5.0 (Linux; U; " +
     81         "Android 3.1; en-us; Xoom Build/HMJ25) AppleWebKit/534.13 " +
     82         "(KHTML, like Gecko) Version/4.0 Safari/534.13";
     83 
     84     private static final String USER_AGENTS[] = { null,
     85             DESKTOP_USERAGENT,
     86             IPHONE_USERAGENT,
     87             IPAD_USERAGENT,
     88             FROYO_USERAGENT,
     89             HONEYCOMB_USERAGENT,
     90     };
     91 
     92     // The minimum min font size
     93     // Aka, the lower bounds for the min font size range
     94     // which is 1:5..24
     95     private static final int MIN_FONT_SIZE_OFFSET = 5;
     96     // The initial value in the text zoom range
     97     // This is what represents 100% in the SeekBarPreference range
     98     private static final int TEXT_ZOOM_START_VAL = 10;
     99     // The size of a single step in the text zoom range, in percent
    100     private static final int TEXT_ZOOM_STEP = 5;
    101     // The initial value in the double tap zoom range
    102     // This is what represents 100% in the SeekBarPreference range
    103     private static final int DOUBLE_TAP_ZOOM_START_VAL = 5;
    104     // The size of a single step in the double tap zoom range, in percent
    105     private static final int DOUBLE_TAP_ZOOM_STEP = 5;
    106 
    107     private static BrowserSettings sInstance;
    108 
    109     private Context mContext;
    110     private SharedPreferences mPrefs;
    111     private LinkedList<WeakReference<WebSettings>> mManagedSettings;
    112     private Controller mController;
    113     private WebStorageSizeManager mWebStorageSizeManager;
    114     private AutofillHandler mAutofillHandler;
    115     private WeakHashMap<WebSettings, String> mCustomUserAgents;
    116     private static boolean sInitialized = false;
    117     private boolean mNeedsSharedSync = true;
    118     private float mFontSizeMult = 1.0f;
    119 
    120     // Current state of network-dependent settings
    121     private boolean mLinkPrefetchAllowed = true;
    122 
    123     // Cached values
    124     private int mPageCacheCapacity = 1;
    125     private String mAppCachePath;
    126 
    127     // Cached settings
    128     private SearchEngine mSearchEngine;
    129 
    130     private static String sFactoryResetUrl;
    131 
    132     public static void initialize(final Context context) {
    133         sInstance = new BrowserSettings(context);
    134     }
    135 
    136     public static BrowserSettings getInstance() {
    137         return sInstance;
    138     }
    139 
    140     private BrowserSettings(Context context) {
    141         mContext = context.getApplicationContext();
    142         mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
    143         mAutofillHandler = new AutofillHandler(mContext);
    144         mManagedSettings = new LinkedList<WeakReference<WebSettings>>();
    145         mCustomUserAgents = new WeakHashMap<WebSettings, String>();
    146         mAutofillHandler.asyncLoadFromDb();
    147         BackgroundHandler.execute(mSetup);
    148     }
    149 
    150     public void setController(Controller controller) {
    151         mController = controller;
    152         if (sInitialized) {
    153             syncSharedSettings();
    154         }
    155     }
    156 
    157     public void startManagingSettings(WebSettings settings) {
    158 
    159         if (mNeedsSharedSync) {
    160             syncSharedSettings();
    161         }
    162 
    163         synchronized (mManagedSettings) {
    164             syncStaticSettings(settings);
    165             syncSetting(settings);
    166             mManagedSettings.add(new WeakReference<WebSettings>(settings));
    167         }
    168     }
    169 
    170     public void stopManagingSettings(WebSettings settings) {
    171         Iterator<WeakReference<WebSettings>> iter = mManagedSettings.iterator();
    172         while (iter.hasNext()) {
    173             WeakReference<WebSettings> ref = iter.next();
    174             if (ref.get() == settings) {
    175                 iter.remove();
    176                 return;
    177             }
    178         }
    179     }
    180 
    181     private Runnable mSetup = new Runnable() {
    182 
    183         @Override
    184         public void run() {
    185             DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
    186             mFontSizeMult = metrics.scaledDensity / metrics.density;
    187             // the cost of one cached page is ~3M (measured using nytimes.com). For
    188             // low end devices, we only cache one page. For high end devices, we try
    189             // to cache more pages, currently choose 5.
    190             if (ActivityManager.staticGetMemoryClass() > 16) {
    191                 mPageCacheCapacity = 5;
    192             }
    193             mWebStorageSizeManager = new WebStorageSizeManager(mContext,
    194                     new WebStorageSizeManager.StatFsDiskInfo(getAppCachePath()),
    195                     new WebStorageSizeManager.WebKitAppCacheInfo(getAppCachePath()));
    196             // Workaround b/5254577
    197             mPrefs.registerOnSharedPreferenceChangeListener(BrowserSettings.this);
    198             if (Build.VERSION.CODENAME.equals("REL")) {
    199                 // This is a release build, always startup with debug disabled
    200                 setDebugEnabled(false);
    201             }
    202             if (mPrefs.contains(PREF_TEXT_SIZE)) {
    203                 /*
    204                  * Update from TextSize enum to zoom percent
    205                  * SMALLEST is 50%
    206                  * SMALLER is 75%
    207                  * NORMAL is 100%
    208                  * LARGER is 150%
    209                  * LARGEST is 200%
    210                  */
    211                 switch (getTextSize()) {
    212                 case SMALLEST:
    213                     setTextZoom(50);
    214                     break;
    215                 case SMALLER:
    216                     setTextZoom(75);
    217                     break;
    218                 case LARGER:
    219                     setTextZoom(150);
    220                     break;
    221                 case LARGEST:
    222                     setTextZoom(200);
    223                     break;
    224                 }
    225                 mPrefs.edit().remove(PREF_TEXT_SIZE).apply();
    226             }
    227 
    228             sFactoryResetUrl = mContext.getResources().getString(R.string.homepage_base);
    229             if (sFactoryResetUrl.indexOf("{CID}") != -1) {
    230                 sFactoryResetUrl = sFactoryResetUrl.replace("{CID}",
    231                     BrowserProvider.getClientId(mContext.getContentResolver()));
    232             }
    233 
    234             synchronized (BrowserSettings.class) {
    235                 sInitialized = true;
    236                 BrowserSettings.class.notifyAll();
    237             }
    238         }
    239     };
    240 
    241     private static void requireInitialization() {
    242         synchronized (BrowserSettings.class) {
    243             while (!sInitialized) {
    244                 try {
    245                     BrowserSettings.class.wait();
    246                 } catch (InterruptedException e) {
    247                 }
    248             }
    249         }
    250     }
    251 
    252     /**
    253      * Syncs all the settings that have a Preference UI
    254      */
    255     private void syncSetting(WebSettings settings) {
    256         settings.setGeolocationEnabled(enableGeolocation());
    257         settings.setJavaScriptEnabled(enableJavascript());
    258         settings.setLightTouchEnabled(enableLightTouch());
    259         settings.setNavDump(enableNavDump());
    260         settings.setDefaultTextEncodingName(getDefaultTextEncoding());
    261         settings.setDefaultZoom(getDefaultZoom());
    262         settings.setMinimumFontSize(getMinimumFontSize());
    263         settings.setMinimumLogicalFontSize(getMinimumFontSize());
    264         settings.setPluginState(getPluginState());
    265         settings.setTextZoom(getTextZoom());
    266         settings.setLayoutAlgorithm(getLayoutAlgorithm());
    267         settings.setJavaScriptCanOpenWindowsAutomatically(!blockPopupWindows());
    268         settings.setLoadsImagesAutomatically(loadImages());
    269         settings.setLoadWithOverviewMode(loadPageInOverviewMode());
    270         settings.setSavePassword(rememberPasswords());
    271         settings.setSaveFormData(saveFormdata());
    272         settings.setUseWideViewPort(isWideViewport());
    273 
    274         String ua = mCustomUserAgents.get(settings);
    275         if (ua != null) {
    276             settings.setUserAgentString(ua);
    277         } else {
    278             settings.setUserAgentString(USER_AGENTS[getUserAgent()]);
    279         }
    280 
    281         if (!(settings instanceof WebSettingsClassic)) return;
    282 
    283         WebSettingsClassic settingsClassic = (WebSettingsClassic) settings;
    284         settingsClassic.setHardwareAccelSkiaEnabled(isSkiaHardwareAccelerated());
    285         settingsClassic.setShowVisualIndicator(enableVisualIndicator());
    286         settingsClassic.setForceUserScalable(forceEnableUserScalable());
    287         settingsClassic.setDoubleTapZoom(getDoubleTapZoom());
    288         settingsClassic.setAutoFillEnabled(isAutofillEnabled());
    289         settingsClassic.setAutoFillProfile(getAutoFillProfile());
    290 
    291         boolean useInverted = useInvertedRendering();
    292         settingsClassic.setProperty(WebViewProperties.gfxInvertedScreen,
    293                 useInverted ? "true" : "false");
    294         if (useInverted) {
    295           settingsClassic.setProperty(WebViewProperties.gfxInvertedScreenContrast,
    296                     Float.toString(getInvertedContrast()));
    297         }
    298 
    299         if (isDebugEnabled()) {
    300           settingsClassic.setProperty(WebViewProperties.gfxEnableCpuUploadPath,
    301                     enableCpuUploadPath() ? "true" : "false");
    302         }
    303 
    304         settingsClassic.setLinkPrefetchEnabled(mLinkPrefetchAllowed);
    305     }
    306 
    307     /**
    308      * Syncs all the settings that have no UI
    309      * These cannot change, so we only need to set them once per WebSettings
    310      */
    311     private void syncStaticSettings(WebSettings settings) {
    312         settings.setDefaultFontSize(16);
    313         settings.setDefaultFixedFontSize(13);
    314 
    315         // WebView inside Browser doesn't want initial focus to be set.
    316         settings.setNeedInitialFocus(false);
    317         // Browser supports multiple windows
    318         settings.setSupportMultipleWindows(true);
    319         // enable smooth transition for better performance during panning or
    320         // zooming
    321         settings.setEnableSmoothTransition(true);
    322         // disable content url access
    323         settings.setAllowContentAccess(false);
    324 
    325         // HTML5 API flags
    326         settings.setAppCacheEnabled(true);
    327         settings.setDatabaseEnabled(true);
    328         settings.setDomStorageEnabled(true);
    329 
    330         // HTML5 configuration parametersettings.
    331         settings.setAppCacheMaxSize(getWebStorageSizeManager().getAppCacheMaxSize());
    332         settings.setAppCachePath(getAppCachePath());
    333         settings.setDatabasePath(mContext.getDir("databases", 0).getPath());
    334         settings.setGeolocationDatabasePath(mContext.getDir("geolocation", 0).getPath());
    335         // origin policy for file access
    336         settings.setAllowUniversalAccessFromFileURLs(false);
    337         settings.setAllowFileAccessFromFileURLs(false);
    338 
    339         if (!(settings instanceof WebSettingsClassic)) return;
    340 
    341         WebSettingsClassic settingsClassic = (WebSettingsClassic) settings;
    342         settingsClassic.setPageCacheCapacity(getPageCacheCapacity());
    343         // WebView should be preserving the memory as much as possible.
    344         // However, apps like browser wish to turn on the performance mode which
    345         // would require more memory.
    346         // TODO: We need to dynamically allocate/deallocate temporary memory for
    347         // apps which are trying to use minimal memory. Currently, double
    348         // buffering is always turned on, which is unnecessary.
    349         settingsClassic.setProperty(WebViewProperties.gfxUseMinimalMemory, "false");
    350         settingsClassic.setWorkersEnabled(true);  // This only affects V8.
    351     }
    352 
    353     private void syncSharedSettings() {
    354         mNeedsSharedSync = false;
    355         CookieManager.getInstance().setAcceptCookie(acceptCookies());
    356         if (mController != null) {
    357             mController.setShouldShowErrorConsole(enableJavascriptConsole());
    358         }
    359     }
    360 
    361     private void syncManagedSettings() {
    362         syncSharedSettings();
    363         synchronized (mManagedSettings) {
    364             Iterator<WeakReference<WebSettings>> iter = mManagedSettings.iterator();
    365             while (iter.hasNext()) {
    366                 WeakReference<WebSettings> ref = iter.next();
    367                 WebSettings settings = ref.get();
    368                 if (settings == null) {
    369                     iter.remove();
    370                     continue;
    371                 }
    372                 syncSetting(settings);
    373             }
    374         }
    375     }
    376 
    377     @Override
    378     public void onSharedPreferenceChanged(
    379             SharedPreferences sharedPreferences, String key) {
    380         syncManagedSettings();
    381         if (PREF_SEARCH_ENGINE.equals(key)) {
    382             updateSearchEngine(false);
    383         } else if (PREF_FULLSCREEN.equals(key)) {
    384             if (mController != null && mController.getUi() != null) {
    385                 mController.getUi().setFullscreen(useFullscreen());
    386             }
    387         } else if (PREF_ENABLE_QUICK_CONTROLS.equals(key)) {
    388             if (mController != null && mController.getUi() != null) {
    389                 mController.getUi().setUseQuickControls(sharedPreferences.getBoolean(key, false));
    390             }
    391         } else if (PREF_LINK_PREFETCH.equals(key)) {
    392             updateConnectionType();
    393         }
    394     }
    395 
    396     public static String getFactoryResetHomeUrl(Context context) {
    397         requireInitialization();
    398         return sFactoryResetUrl;
    399     }
    400 
    401     public LayoutAlgorithm getLayoutAlgorithm() {
    402         LayoutAlgorithm layoutAlgorithm = LayoutAlgorithm.NORMAL;
    403         if (autofitPages()) {
    404             layoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS;
    405         }
    406         if (isDebugEnabled()) {
    407             if (isSmallScreen()) {
    408                 layoutAlgorithm = LayoutAlgorithm.SINGLE_COLUMN;
    409             } else {
    410                 if (isNormalLayout()) {
    411                     layoutAlgorithm = LayoutAlgorithm.NORMAL;
    412                 } else {
    413                     layoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS;
    414                 }
    415             }
    416         }
    417         return layoutAlgorithm;
    418     }
    419 
    420     public int getPageCacheCapacity() {
    421         requireInitialization();
    422         return mPageCacheCapacity;
    423     }
    424 
    425     public WebStorageSizeManager getWebStorageSizeManager() {
    426         requireInitialization();
    427         return mWebStorageSizeManager;
    428     }
    429 
    430     private String getAppCachePath() {
    431         if (mAppCachePath == null) {
    432             mAppCachePath = mContext.getDir("appcache", 0).getPath();
    433         }
    434         return mAppCachePath;
    435     }
    436 
    437     private void updateSearchEngine(boolean force) {
    438         String searchEngineName = getSearchEngineName();
    439         if (force || mSearchEngine == null ||
    440                 !mSearchEngine.getName().equals(searchEngineName)) {
    441             mSearchEngine = SearchEngines.get(mContext, searchEngineName);
    442          }
    443     }
    444 
    445     public SearchEngine getSearchEngine() {
    446         if (mSearchEngine == null) {
    447             updateSearchEngine(false);
    448         }
    449         return mSearchEngine;
    450     }
    451 
    452     public boolean isDebugEnabled() {
    453         requireInitialization();
    454         return mPrefs.getBoolean(PREF_DEBUG_MENU, false);
    455     }
    456 
    457     public void setDebugEnabled(boolean value) {
    458         Editor edit = mPrefs.edit();
    459         edit.putBoolean(PREF_DEBUG_MENU, value);
    460         if (!value) {
    461             // Reset to "safe" value
    462             edit.putBoolean(PREF_ENABLE_HARDWARE_ACCEL_SKIA, false);
    463         }
    464         edit.apply();
    465     }
    466 
    467     public void clearCache() {
    468         WebIconDatabase.getInstance().removeAllIcons();
    469         if (mController != null) {
    470             WebView current = mController.getCurrentWebView();
    471             if (current != null) {
    472                 current.clearCache(true);
    473             }
    474         }
    475     }
    476 
    477     public void clearCookies() {
    478         CookieManager.getInstance().removeAllCookie();
    479     }
    480 
    481     public void clearHistory() {
    482         ContentResolver resolver = mContext.getContentResolver();
    483         Browser.clearHistory(resolver);
    484         Browser.clearSearches(resolver);
    485     }
    486 
    487     public void clearFormData() {
    488         WebViewDatabase.getInstance(mContext).clearFormData();
    489         if (mController!= null) {
    490             WebView currentTopView = mController.getCurrentTopWebView();
    491             if (currentTopView != null) {
    492                 currentTopView.clearFormData();
    493             }
    494         }
    495     }
    496 
    497     public void clearPasswords() {
    498         WebViewDatabase db = WebViewDatabase.getInstance(mContext);
    499         db.clearUsernamePassword();
    500         db.clearHttpAuthUsernamePassword();
    501     }
    502 
    503     public void clearDatabases() {
    504         WebStorage.getInstance().deleteAllData();
    505     }
    506 
    507     public void clearLocationAccess() {
    508         GeolocationPermissions.getInstance().clearAll();
    509     }
    510 
    511     public void resetDefaultPreferences() {
    512         // Preserve autologin setting
    513         long gal = mPrefs.getLong(GoogleAccountLogin.PREF_AUTOLOGIN_TIME, -1);
    514         mPrefs.edit()
    515                 .clear()
    516                 .putLong(GoogleAccountLogin.PREF_AUTOLOGIN_TIME, gal)
    517                 .apply();
    518         resetCachedValues();
    519         syncManagedSettings();
    520     }
    521 
    522     private void resetCachedValues() {
    523         updateSearchEngine(false);
    524     }
    525 
    526     public AutoFillProfile getAutoFillProfile() {
    527         return mAutofillHandler.getAutoFillProfile();
    528     }
    529 
    530     public void setAutoFillProfile(AutoFillProfile profile, Message msg) {
    531         mAutofillHandler.setAutoFillProfile(profile, msg);
    532         // Auto-fill will reuse the same profile ID when making edits to the profile,
    533         // so we need to force a settings sync (otherwise the SharedPreferences
    534         // manager will optimise out the call to onSharedPreferenceChanged(), as
    535         // it thinks nothing has changed).
    536         syncManagedSettings();
    537     }
    538 
    539     public void toggleDebugSettings() {
    540         setDebugEnabled(!isDebugEnabled());
    541     }
    542 
    543     public boolean hasDesktopUseragent(WebView view) {
    544         return view != null && mCustomUserAgents.get(view.getSettings()) != null;
    545     }
    546 
    547     public void toggleDesktopUseragent(WebView view) {
    548         if (view == null) {
    549             return;
    550         }
    551         WebSettings settings = view.getSettings();
    552         if (mCustomUserAgents.get(settings) != null) {
    553             mCustomUserAgents.remove(settings);
    554             settings.setUserAgentString(USER_AGENTS[getUserAgent()]);
    555         } else {
    556             mCustomUserAgents.put(settings, DESKTOP_USERAGENT);
    557             settings.setUserAgentString(DESKTOP_USERAGENT);
    558         }
    559     }
    560 
    561     public static int getAdjustedMinimumFontSize(int rawValue) {
    562         rawValue++; // Preference starts at 0, min font at 1
    563         if (rawValue > 1) {
    564             rawValue += (MIN_FONT_SIZE_OFFSET - 2);
    565         }
    566         return rawValue;
    567     }
    568 
    569     public int getAdjustedTextZoom(int rawValue) {
    570         rawValue = (rawValue - TEXT_ZOOM_START_VAL) * TEXT_ZOOM_STEP;
    571         return (int) ((rawValue + 100) * mFontSizeMult);
    572     }
    573 
    574     static int getRawTextZoom(int percent) {
    575         return (percent - 100) / TEXT_ZOOM_STEP + TEXT_ZOOM_START_VAL;
    576     }
    577 
    578     public int getAdjustedDoubleTapZoom(int rawValue) {
    579         rawValue = (rawValue - DOUBLE_TAP_ZOOM_START_VAL) * DOUBLE_TAP_ZOOM_STEP;
    580         return (int) ((rawValue + 100) * mFontSizeMult);
    581     }
    582 
    583     static int getRawDoubleTapZoom(int percent) {
    584         return (percent - 100) / DOUBLE_TAP_ZOOM_STEP + DOUBLE_TAP_ZOOM_START_VAL;
    585     }
    586 
    587     public SharedPreferences getPreferences() {
    588         return mPrefs;
    589     }
    590 
    591     // update connectivity-dependent options
    592     public void updateConnectionType() {
    593         ConnectivityManager cm = (ConnectivityManager)
    594             mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
    595         String linkPrefetchPreference = getLinkPrefetchEnabled();
    596         boolean linkPrefetchAllowed = linkPrefetchPreference.
    597             equals(getLinkPrefetchAlwaysPreferenceString(mContext));
    598         NetworkInfo ni = cm.getActiveNetworkInfo();
    599         if (ni != null) {
    600             switch (ni.getType()) {
    601                 case ConnectivityManager.TYPE_WIFI:
    602                 case ConnectivityManager.TYPE_ETHERNET:
    603                 case ConnectivityManager.TYPE_BLUETOOTH:
    604                     linkPrefetchAllowed |= linkPrefetchPreference.
    605                         equals(getLinkPrefetchOnWifiOnlyPreferenceString(mContext));
    606                     break;
    607                 case ConnectivityManager.TYPE_MOBILE:
    608                 case ConnectivityManager.TYPE_MOBILE_DUN:
    609                 case ConnectivityManager.TYPE_MOBILE_MMS:
    610                 case ConnectivityManager.TYPE_MOBILE_SUPL:
    611                 case ConnectivityManager.TYPE_WIMAX:
    612                 default:
    613                     break;
    614             }
    615         }
    616         if (mLinkPrefetchAllowed != linkPrefetchAllowed) {
    617             mLinkPrefetchAllowed = linkPrefetchAllowed;
    618             syncManagedSettings();
    619         }
    620     }
    621 
    622     // -----------------------------
    623     // getter/setters for accessibility_preferences.xml
    624     // -----------------------------
    625 
    626     @Deprecated
    627     private TextSize getTextSize() {
    628         String textSize = mPrefs.getString(PREF_TEXT_SIZE, "NORMAL");
    629         return TextSize.valueOf(textSize);
    630     }
    631 
    632     public int getMinimumFontSize() {
    633         int minFont = mPrefs.getInt(PREF_MIN_FONT_SIZE, 0);
    634         return getAdjustedMinimumFontSize(minFont);
    635     }
    636 
    637     public boolean forceEnableUserScalable() {
    638         return mPrefs.getBoolean(PREF_FORCE_USERSCALABLE, false);
    639     }
    640 
    641     public int getTextZoom() {
    642         requireInitialization();
    643         int textZoom = mPrefs.getInt(PREF_TEXT_ZOOM, 10);
    644         return getAdjustedTextZoom(textZoom);
    645     }
    646 
    647     public void setTextZoom(int percent) {
    648         mPrefs.edit().putInt(PREF_TEXT_ZOOM, getRawTextZoom(percent)).apply();
    649     }
    650 
    651     public int getDoubleTapZoom() {
    652         requireInitialization();
    653         int doubleTapZoom = mPrefs.getInt(PREF_DOUBLE_TAP_ZOOM, 5);
    654         return getAdjustedDoubleTapZoom(doubleTapZoom);
    655     }
    656 
    657     public void setDoubleTapZoom(int percent) {
    658         mPrefs.edit().putInt(PREF_DOUBLE_TAP_ZOOM, getRawDoubleTapZoom(percent)).apply();
    659     }
    660 
    661     // -----------------------------
    662     // getter/setters for advanced_preferences.xml
    663     // -----------------------------
    664 
    665     public String getSearchEngineName() {
    666         return mPrefs.getString(PREF_SEARCH_ENGINE, SearchEngine.GOOGLE);
    667     }
    668 
    669     public boolean allowAppTabs() {
    670         return mPrefs.getBoolean(PREF_ALLOW_APP_TABS, false);
    671     }
    672 
    673     public boolean openInBackground() {
    674         return mPrefs.getBoolean(PREF_OPEN_IN_BACKGROUND, false);
    675     }
    676 
    677     public boolean enableJavascript() {
    678         return mPrefs.getBoolean(PREF_ENABLE_JAVASCRIPT, true);
    679     }
    680 
    681     // TODO: Cache
    682     public PluginState getPluginState() {
    683         String state = mPrefs.getString(PREF_PLUGIN_STATE, "ON");
    684         return PluginState.valueOf(state);
    685     }
    686 
    687     // TODO: Cache
    688     public ZoomDensity getDefaultZoom() {
    689         String zoom = mPrefs.getString(PREF_DEFAULT_ZOOM, "MEDIUM");
    690         return ZoomDensity.valueOf(zoom);
    691     }
    692 
    693     public boolean loadPageInOverviewMode() {
    694         return mPrefs.getBoolean(PREF_LOAD_PAGE, true);
    695     }
    696 
    697     public boolean autofitPages() {
    698         return mPrefs.getBoolean(PREF_AUTOFIT_PAGES, true);
    699     }
    700 
    701     public boolean blockPopupWindows() {
    702         return mPrefs.getBoolean(PREF_BLOCK_POPUP_WINDOWS, true);
    703     }
    704 
    705     public boolean loadImages() {
    706         return mPrefs.getBoolean(PREF_LOAD_IMAGES, true);
    707     }
    708 
    709     public String getDefaultTextEncoding() {
    710         return mPrefs.getString(PREF_DEFAULT_TEXT_ENCODING, null);
    711     }
    712 
    713     // -----------------------------
    714     // getter/setters for general_preferences.xml
    715     // -----------------------------
    716 
    717     public String getHomePage() {
    718         return mPrefs.getString(PREF_HOMEPAGE, getFactoryResetHomeUrl(mContext));
    719     }
    720 
    721     public void setHomePage(String value) {
    722         mPrefs.edit().putString(PREF_HOMEPAGE, value).apply();
    723     }
    724 
    725     public boolean isAutofillEnabled() {
    726         return mPrefs.getBoolean(PREF_AUTOFILL_ENABLED, true);
    727     }
    728 
    729     public void setAutofillEnabled(boolean value) {
    730         mPrefs.edit().putBoolean(PREF_AUTOFILL_ENABLED, value).apply();
    731     }
    732 
    733     // -----------------------------
    734     // getter/setters for debug_preferences.xml
    735     // -----------------------------
    736 
    737     public boolean isHardwareAccelerated() {
    738         if (!isDebugEnabled()) {
    739             return true;
    740         }
    741         return mPrefs.getBoolean(PREF_ENABLE_HARDWARE_ACCEL, true);
    742     }
    743 
    744     public boolean isSkiaHardwareAccelerated() {
    745         if (!isDebugEnabled()) {
    746             return false;
    747         }
    748         return mPrefs.getBoolean(PREF_ENABLE_HARDWARE_ACCEL_SKIA, false);
    749     }
    750 
    751     public int getUserAgent() {
    752         if (!isDebugEnabled()) {
    753             return 0;
    754         }
    755         return Integer.parseInt(mPrefs.getString(PREF_USER_AGENT, "0"));
    756     }
    757 
    758     // -----------------------------
    759     // getter/setters for hidden_debug_preferences.xml
    760     // -----------------------------
    761 
    762     public boolean enableVisualIndicator() {
    763         if (!isDebugEnabled()) {
    764             return false;
    765         }
    766         return mPrefs.getBoolean(PREF_ENABLE_VISUAL_INDICATOR, false);
    767     }
    768 
    769     public boolean enableCpuUploadPath() {
    770         if (!isDebugEnabled()) {
    771             return false;
    772         }
    773         return mPrefs.getBoolean(PREF_ENABLE_CPU_UPLOAD_PATH, false);
    774     }
    775 
    776     public boolean enableJavascriptConsole() {
    777         if (!isDebugEnabled()) {
    778             return false;
    779         }
    780         return mPrefs.getBoolean(PREF_JAVASCRIPT_CONSOLE, true);
    781     }
    782 
    783     public boolean isSmallScreen() {
    784         if (!isDebugEnabled()) {
    785             return false;
    786         }
    787         return mPrefs.getBoolean(PREF_SMALL_SCREEN, false);
    788     }
    789 
    790     public boolean isWideViewport() {
    791         if (!isDebugEnabled()) {
    792             return true;
    793         }
    794         return mPrefs.getBoolean(PREF_WIDE_VIEWPORT, true);
    795     }
    796 
    797     public boolean isNormalLayout() {
    798         if (!isDebugEnabled()) {
    799             return false;
    800         }
    801         return mPrefs.getBoolean(PREF_NORMAL_LAYOUT, false);
    802     }
    803 
    804     public boolean isTracing() {
    805         if (!isDebugEnabled()) {
    806             return false;
    807         }
    808         return mPrefs.getBoolean(PREF_ENABLE_TRACING, false);
    809     }
    810 
    811     public boolean enableLightTouch() {
    812         if (!isDebugEnabled()) {
    813             return false;
    814         }
    815         return mPrefs.getBoolean(PREF_ENABLE_LIGHT_TOUCH, false);
    816     }
    817 
    818     public boolean enableNavDump() {
    819         if (!isDebugEnabled()) {
    820             return false;
    821         }
    822         return mPrefs.getBoolean(PREF_ENABLE_NAV_DUMP, false);
    823     }
    824 
    825     public String getJsEngineFlags() {
    826         if (!isDebugEnabled()) {
    827             return "";
    828         }
    829         return mPrefs.getString(PREF_JS_ENGINE_FLAGS, "");
    830     }
    831 
    832     // -----------------------------
    833     // getter/setters for lab_preferences.xml
    834     // -----------------------------
    835 
    836     public boolean useQuickControls() {
    837         return mPrefs.getBoolean(PREF_ENABLE_QUICK_CONTROLS, false);
    838     }
    839 
    840     public boolean useMostVisitedHomepage() {
    841         return HomeProvider.MOST_VISITED.equals(getHomePage());
    842     }
    843 
    844     public boolean useFullscreen() {
    845         return mPrefs.getBoolean(PREF_FULLSCREEN, false);
    846     }
    847 
    848     public boolean useInvertedRendering() {
    849         return mPrefs.getBoolean(PREF_INVERTED, false);
    850     }
    851 
    852     public float getInvertedContrast() {
    853         return 1 + (mPrefs.getInt(PREF_INVERTED_CONTRAST, 0) / 10f);
    854     }
    855 
    856     // -----------------------------
    857     // getter/setters for privacy_security_preferences.xml
    858     // -----------------------------
    859 
    860     public boolean showSecurityWarnings() {
    861         return mPrefs.getBoolean(PREF_SHOW_SECURITY_WARNINGS, true);
    862     }
    863 
    864     public boolean acceptCookies() {
    865         return mPrefs.getBoolean(PREF_ACCEPT_COOKIES, true);
    866     }
    867 
    868     public boolean saveFormdata() {
    869         return mPrefs.getBoolean(PREF_SAVE_FORMDATA, true);
    870     }
    871 
    872     public boolean enableGeolocation() {
    873         return mPrefs.getBoolean(PREF_ENABLE_GEOLOCATION, true);
    874     }
    875 
    876     public boolean rememberPasswords() {
    877         return mPrefs.getBoolean(PREF_REMEMBER_PASSWORDS, true);
    878     }
    879 
    880     // -----------------------------
    881     // getter/setters for bandwidth_preferences.xml
    882     // -----------------------------
    883 
    884     public static String getPreloadOnWifiOnlyPreferenceString(Context context) {
    885         return context.getResources().getString(R.string.pref_data_preload_value_wifi_only);
    886     }
    887 
    888     public static String getPreloadAlwaysPreferenceString(Context context) {
    889         return context.getResources().getString(R.string.pref_data_preload_value_always);
    890     }
    891 
    892     private static final String DEAULT_PRELOAD_SECURE_SETTING_KEY =
    893             "browser_default_preload_setting";
    894 
    895     public String getDefaultPreloadSetting() {
    896         String preload = Settings.Secure.getString(mContext.getContentResolver(),
    897                 DEAULT_PRELOAD_SECURE_SETTING_KEY);
    898         if (preload == null) {
    899             preload = mContext.getResources().getString(R.string.pref_data_preload_default_value);
    900         }
    901         return preload;
    902     }
    903 
    904     public String getPreloadEnabled() {
    905         return mPrefs.getString(PREF_DATA_PRELOAD, getDefaultPreloadSetting());
    906     }
    907 
    908     public static String getLinkPrefetchOnWifiOnlyPreferenceString(Context context) {
    909         return context.getResources().getString(R.string.pref_link_prefetch_value_wifi_only);
    910     }
    911 
    912     public static String getLinkPrefetchAlwaysPreferenceString(Context context) {
    913         return context.getResources().getString(R.string.pref_link_prefetch_value_always);
    914     }
    915 
    916     private static final String DEFAULT_LINK_PREFETCH_SECURE_SETTING_KEY =
    917             "browser_default_link_prefetch_setting";
    918 
    919     public String getDefaultLinkPrefetchSetting() {
    920         String preload = Settings.Secure.getString(mContext.getContentResolver(),
    921             DEFAULT_LINK_PREFETCH_SECURE_SETTING_KEY);
    922         if (preload == null) {
    923             preload = mContext.getResources().getString(R.string.pref_link_prefetch_default_value);
    924         }
    925         return preload;
    926     }
    927 
    928     public String getLinkPrefetchEnabled() {
    929         return mPrefs.getString(PREF_LINK_PREFETCH, getDefaultLinkPrefetchSetting());
    930     }
    931 
    932     // -----------------------------
    933     // getter/setters for browser recovery
    934     // -----------------------------
    935     /**
    936      * The last time browser was started.
    937      * @return The last browser start time as System.currentTimeMillis. This
    938      * can be 0 if this is the first time or the last tab was closed.
    939      */
    940     public long getLastRecovered() {
    941         return mPrefs.getLong(KEY_LAST_RECOVERED, 0);
    942     }
    943 
    944     /**
    945      * Sets the last browser start time.
    946      * @param time The last time as System.currentTimeMillis that the browser
    947      * was started. This should be set to 0 if the last tab is closed.
    948      */
    949     public void setLastRecovered(long time) {
    950         mPrefs.edit()
    951             .putLong(KEY_LAST_RECOVERED, time)
    952             .apply();
    953     }
    954 
    955     /**
    956      * Used to determine whether or not the previous browser run crashed. Once
    957      * the previous state has been determined, the value will be set to false
    958      * until a pause is received.
    959      * @return true if the last browser run was paused or false if it crashed.
    960      */
    961     public boolean wasLastRunPaused() {
    962         return mPrefs.getBoolean(KEY_LAST_RUN_PAUSED, false);
    963     }
    964 
    965     /**
    966      * Sets whether or not the last run was a pause or crash.
    967      * @param isPaused Set to true When a pause is received or false after
    968      * resuming.
    969      */
    970     public void setLastRunPaused(boolean isPaused) {
    971         mPrefs.edit()
    972             .putBoolean(KEY_LAST_RUN_PAUSED, isPaused)
    973             .apply();
    974     }
    975 }
    976