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