• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.browser.search.SearchEngine;
21 import com.android.browser.search.SearchEngines;
22 
23 import android.app.ActivityManager;
24 import android.content.ComponentName;
25 import android.content.ContentResolver;
26 import android.content.ContentUris;
27 import android.content.ContentValues;
28 import android.content.Context;
29 import android.content.pm.ActivityInfo;
30 import android.content.pm.PackageManager;
31 import android.content.SharedPreferences;
32 import android.content.SharedPreferences.Editor;
33 import android.database.ContentObserver;
34 import android.database.Cursor;
35 import android.net.Uri;
36 import android.os.AsyncTask;
37 import android.os.Handler;
38 import android.preference.PreferenceActivity;
39 import android.preference.PreferenceScreen;
40 import android.provider.Browser.BookmarkColumns;
41 import android.provider.Settings;
42 import android.util.Log;
43 import android.webkit.CookieManager;
44 import android.webkit.GeolocationPermissions;
45 import android.webkit.ValueCallback;
46 import android.webkit.WebView;
47 import android.webkit.WebViewDatabase;
48 import android.webkit.WebIconDatabase;
49 import android.webkit.WebSettings;
50 import android.webkit.WebStorage;
51 import android.preference.PreferenceManager;
52 import android.provider.Browser;
53 
54 import java.util.HashMap;
55 import java.util.Map;
56 import java.util.Set;
57 import java.util.Observable;
58 
59 /*
60  * Package level class for storing various WebView and Browser settings. To use
61  * this class:
62  * BrowserSettings s = BrowserSettings.getInstance();
63  * s.addObserver(webView.getSettings());
64  * s.loadFromDb(context); // Only needed on app startup
65  * s.javaScriptEnabled = true;
66  * ... // set any other settings
67  * s.update(); // this will update all the observers
68  *
69  * To remove an observer:
70  * s.deleteObserver(webView.getSettings());
71  */
72 class BrowserSettings extends Observable {
73 
74     // Private variables for settings
75     // NOTE: these defaults need to be kept in sync with the XML
76     // until the performance of PreferenceManager.setDefaultValues()
77     // is improved.
78     // Note: boolean variables are set inside reset function.
79     private boolean loadsImagesAutomatically;
80     private boolean javaScriptEnabled;
81     private WebSettings.PluginState pluginState;
82     private boolean javaScriptCanOpenWindowsAutomatically;
83     private boolean showSecurityWarnings;
84     private boolean rememberPasswords;
85     private boolean saveFormData;
86     private boolean openInBackground;
87     private String defaultTextEncodingName;
88     private String homeUrl = "";
89     private SearchEngine searchEngine;
90     private boolean autoFitPage;
91     private boolean landscapeOnly;
92     private boolean loadsPageInOverviewMode;
93     private boolean showDebugSettings;
94     // HTML5 API flags
95     private boolean appCacheEnabled;
96     private boolean databaseEnabled;
97     private boolean domStorageEnabled;
98     private boolean geolocationEnabled;
99     private boolean workersEnabled;  // only affects V8. JSC does not have a similar setting
100     // HTML5 API configuration params
101     private long appCacheMaxSize = Long.MAX_VALUE;
102     private String appCachePath;  // default value set in loadFromDb().
103     private String databasePath; // default value set in loadFromDb()
104     private String geolocationDatabasePath; // default value set in loadFromDb()
105     private WebStorageSizeManager webStorageSizeManager;
106 
107     private String jsFlags = "";
108 
109     private final static String TAG = "BrowserSettings";
110 
111     // Development settings
112     public WebSettings.LayoutAlgorithm layoutAlgorithm =
113         WebSettings.LayoutAlgorithm.NARROW_COLUMNS;
114     private boolean useWideViewPort = true;
115     private int userAgent = 0;
116     private boolean tracing = false;
117     private boolean lightTouch = false;
118     private boolean navDump = false;
119 
120     // By default the error console is shown once the user navigates to about:debug.
121     // The setting can be then toggled from the settings menu.
122     private boolean showConsole = true;
123 
124     // Private preconfigured values
125     private static int minimumFontSize = 8;
126     private static int minimumLogicalFontSize = 8;
127     private static int defaultFontSize = 16;
128     private static int defaultFixedFontSize = 13;
129     private static WebSettings.TextSize textSize =
130         WebSettings.TextSize.NORMAL;
131     private static WebSettings.ZoomDensity zoomDensity =
132         WebSettings.ZoomDensity.MEDIUM;
133     private static int pageCacheCapacity;
134 
135     // Preference keys that are used outside this class
136     public final static String PREF_CLEAR_CACHE = "privacy_clear_cache";
137     public final static String PREF_CLEAR_COOKIES = "privacy_clear_cookies";
138     public final static String PREF_CLEAR_HISTORY = "privacy_clear_history";
139     public final static String PREF_HOMEPAGE = "homepage";
140     public final static String PREF_SEARCH_ENGINE = "search_engine";
141     public final static String PREF_CLEAR_FORM_DATA =
142             "privacy_clear_form_data";
143     public final static String PREF_CLEAR_PASSWORDS =
144             "privacy_clear_passwords";
145     public final static String PREF_EXTRAS_RESET_DEFAULTS =
146             "reset_default_preferences";
147     public final static String PREF_DEBUG_SETTINGS = "debug_menu";
148     public final static String PREF_WEBSITE_SETTINGS = "website_settings";
149     public final static String PREF_TEXT_SIZE = "text_size";
150     public final static String PREF_DEFAULT_ZOOM = "default_zoom";
151     public final static String PREF_DEFAULT_TEXT_ENCODING =
152             "default_text_encoding";
153     public final static String PREF_CLEAR_GEOLOCATION_ACCESS =
154             "privacy_clear_geolocation_access";
155 
156     private static final String DESKTOP_USERAGENT = "Mozilla/5.0 (Macintosh; " +
157             "U; Intel Mac OS X 10_6_3; en-us) AppleWebKit/533.16 (KHTML, " +
158             "like Gecko) Version/5.0 Safari/533.16";
159 
160     private static final String IPHONE_USERAGENT = "Mozilla/5.0 (iPhone; U; " +
161             "CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 " +
162             "(KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7";
163 
164     private static final String IPAD_USERAGENT = "Mozilla/5.0 (iPad; U; " +
165             "CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 " +
166             "(KHTML, like Gecko) Version/4.0.4 Mobile/7B367 Safari/531.21.10";
167 
168     private static final String FROYO_USERAGENT = "Mozilla/5.0 (Linux; U; " +
169             "Android 2.2; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 " +
170             "(KHTML, like Gecko) Version/4.0 Mobile Safari/533.1";
171 
172     // Value to truncate strings when adding them to a TextView within
173     // a ListView
174     public final static int MAX_TEXTVIEW_LEN = 80;
175 
176     public static final String RLZ_PROVIDER = "com.google.android.partnersetup.rlzappprovider";
177     public static final Uri RLZ_PROVIDER_URI = Uri.parse("content://" + RLZ_PROVIDER + "/");
178 
179     private String mRlzValue = "";
180 
181     private TabControl mTabControl;
182 
183     // Single instance of the BrowserSettings for use in the Browser app.
184     private static BrowserSettings sSingleton;
185 
186     // Private map of WebSettings to Observer objects used when deleting an
187     // observer.
188     private HashMap<WebSettings,Observer> mWebSettingsToObservers =
189         new HashMap<WebSettings,Observer>();
190 
191     /*
192      * An observer wrapper for updating a WebSettings object with the new
193      * settings after a call to BrowserSettings.update().
194      */
195     static class Observer implements java.util.Observer {
196         // Private WebSettings object that will be updated.
197         private WebSettings mSettings;
198 
Observer(WebSettings w)199         Observer(WebSettings w) {
200             mSettings = w;
201         }
202 
update(Observable o, Object arg)203         public void update(Observable o, Object arg) {
204             BrowserSettings b = (BrowserSettings)o;
205             WebSettings s = mSettings;
206 
207             s.setLayoutAlgorithm(b.layoutAlgorithm);
208             if (b.userAgent == 0) {
209                 // use the default ua string
210                 s.setUserAgentString(null);
211             } else if (b.userAgent == 1) {
212                 s.setUserAgentString(DESKTOP_USERAGENT);
213             } else if (b.userAgent == 2) {
214                 s.setUserAgentString(IPHONE_USERAGENT);
215             } else if (b.userAgent == 3) {
216                 s.setUserAgentString(IPAD_USERAGENT);
217             } else if (b.userAgent == 4) {
218                 s.setUserAgentString(FROYO_USERAGENT);
219             }
220             s.setUseWideViewPort(b.useWideViewPort);
221             s.setLoadsImagesAutomatically(b.loadsImagesAutomatically);
222             s.setJavaScriptEnabled(b.javaScriptEnabled);
223             s.setPluginState(b.pluginState);
224             s.setJavaScriptCanOpenWindowsAutomatically(
225                     b.javaScriptCanOpenWindowsAutomatically);
226             s.setDefaultTextEncodingName(b.defaultTextEncodingName);
227             s.setMinimumFontSize(b.minimumFontSize);
228             s.setMinimumLogicalFontSize(b.minimumLogicalFontSize);
229             s.setDefaultFontSize(b.defaultFontSize);
230             s.setDefaultFixedFontSize(b.defaultFixedFontSize);
231             s.setNavDump(b.navDump);
232             s.setTextSize(b.textSize);
233             s.setDefaultZoom(b.zoomDensity);
234             s.setLightTouchEnabled(b.lightTouch);
235             s.setSaveFormData(b.saveFormData);
236             s.setSavePassword(b.rememberPasswords);
237             s.setLoadWithOverviewMode(b.loadsPageInOverviewMode);
238             s.setPageCacheCapacity(pageCacheCapacity);
239 
240             // WebView inside Browser doesn't want initial focus to be set.
241             s.setNeedInitialFocus(false);
242             // Browser supports multiple windows
243             s.setSupportMultipleWindows(true);
244             // disable content url access
245             s.setAllowContentAccess(false);
246 
247             // HTML5 API flags
248             s.setAppCacheEnabled(b.appCacheEnabled);
249             s.setDatabaseEnabled(b.databaseEnabled);
250             s.setDomStorageEnabled(b.domStorageEnabled);
251             s.setWorkersEnabled(b.workersEnabled);  // This only affects V8.
252             s.setGeolocationEnabled(b.geolocationEnabled);
253 
254             // HTML5 configuration parameters.
255             s.setAppCacheMaxSize(b.appCacheMaxSize);
256             s.setAppCachePath(b.appCachePath);
257             s.setDatabasePath(b.databasePath);
258             s.setGeolocationDatabasePath(b.geolocationDatabasePath);
259 
260             b.updateTabControlSettings();
261         }
262     }
263 
264     /**
265      * Load settings from the browser app's database.
266      * NOTE: Strings used for the preferences must match those specified
267      * in the browser_preferences.xml
268      * @param ctx A Context object used to query the browser's settings
269      *            database. If the database exists, the saved settings will be
270      *            stored in this BrowserSettings object. This will update all
271      *            observers of this object.
272      */
loadFromDb(final Context ctx)273     public void loadFromDb(final Context ctx) {
274         SharedPreferences p =
275                 PreferenceManager.getDefaultSharedPreferences(ctx);
276         // Set the default value for the Application Caches path.
277         appCachePath = ctx.getDir("appcache", 0).getPath();
278         // Determine the maximum size of the application cache.
279         webStorageSizeManager = new WebStorageSizeManager(
280                 ctx,
281                 new WebStorageSizeManager.StatFsDiskInfo(appCachePath),
282                 new WebStorageSizeManager.WebKitAppCacheInfo(appCachePath));
283         appCacheMaxSize = webStorageSizeManager.getAppCacheMaxSize();
284         // Set the default value for the Database path.
285         databasePath = ctx.getDir("databases", 0).getPath();
286         // Set the default value for the Geolocation database path.
287         geolocationDatabasePath = ctx.getDir("geolocation", 0).getPath();
288 
289         if (p.getString(PREF_HOMEPAGE, "") == "") {
290             // No home page preferences is set, set it to default.
291             setHomePage(ctx, getFactoryResetHomeUrl(ctx));
292         }
293 
294         // the cost of one cached page is ~3M (measured using nytimes.com). For
295         // low end devices, we only cache one page. For high end devices, we try
296         // to cache more pages, currently choose 5.
297         ActivityManager am = (ActivityManager) ctx
298                 .getSystemService(Context.ACTIVITY_SERVICE);
299         if (am.getMemoryClass() > 16) {
300             pageCacheCapacity = 5;
301         } else {
302             pageCacheCapacity = 1;
303         }
304 
305     // Load the defaults from the xml
306         // This call is TOO SLOW, need to manually keep the defaults
307         // in sync
308         //PreferenceManager.setDefaultValues(ctx, R.xml.browser_preferences);
309         syncSharedPreferences(ctx, p);
310     }
311 
syncSharedPreferences(Context ctx, SharedPreferences p)312     /* package */ void syncSharedPreferences(Context ctx, SharedPreferences p) {
313 
314         homeUrl =
315             p.getString(PREF_HOMEPAGE, homeUrl);
316         String searchEngineName = p.getString(PREF_SEARCH_ENGINE,
317                 SearchEngine.GOOGLE);
318         if (searchEngine == null || !searchEngine.getName().equals(searchEngineName)) {
319             if (searchEngine != null) {
320                 if (searchEngine.supportsVoiceSearch()) {
321                     // One or more tabs could have been in voice search mode.
322                     // Clear it, since the new SearchEngine may not support
323                     // it, or may handle it differently.
324                     for (int i = 0; i < mTabControl.getTabCount(); i++) {
325                         mTabControl.getTab(i).revertVoiceSearchMode();
326                     }
327                 }
328                 searchEngine.close();
329             }
330             searchEngine = SearchEngines.get(ctx, searchEngineName);
331         }
332         Log.i(TAG, "Selected search engine: " + searchEngine);
333 
334         loadsImagesAutomatically = p.getBoolean("load_images",
335                 loadsImagesAutomatically);
336         javaScriptEnabled = p.getBoolean("enable_javascript",
337                 javaScriptEnabled);
338         pluginState = WebSettings.PluginState.valueOf(
339                 p.getString("plugin_state", pluginState.name()));
340         javaScriptCanOpenWindowsAutomatically = !p.getBoolean(
341             "block_popup_windows",
342             !javaScriptCanOpenWindowsAutomatically);
343         showSecurityWarnings = p.getBoolean("show_security_warnings",
344                 showSecurityWarnings);
345         rememberPasswords = p.getBoolean("remember_passwords",
346                 rememberPasswords);
347         saveFormData = p.getBoolean("save_formdata",
348                 saveFormData);
349         boolean accept_cookies = p.getBoolean("accept_cookies",
350                 CookieManager.getInstance().acceptCookie());
351         CookieManager.getInstance().setAcceptCookie(accept_cookies);
352         openInBackground = p.getBoolean("open_in_background", openInBackground);
353         textSize = WebSettings.TextSize.valueOf(
354                 p.getString(PREF_TEXT_SIZE, textSize.name()));
355         zoomDensity = WebSettings.ZoomDensity.valueOf(
356                 p.getString(PREF_DEFAULT_ZOOM, zoomDensity.name()));
357         autoFitPage = p.getBoolean("autofit_pages", autoFitPage);
358         loadsPageInOverviewMode = p.getBoolean("load_page",
359                 loadsPageInOverviewMode);
360         boolean landscapeOnlyTemp =
361                 p.getBoolean("landscape_only", landscapeOnly);
362         if (landscapeOnlyTemp != landscapeOnly) {
363             landscapeOnly = landscapeOnlyTemp;
364         }
365         useWideViewPort = true; // use wide view port for either setting
366         if (autoFitPage) {
367             layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS;
368         } else {
369             layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL;
370         }
371         defaultTextEncodingName =
372                 p.getString(PREF_DEFAULT_TEXT_ENCODING,
373                         defaultTextEncodingName);
374 
375         showDebugSettings =
376                 p.getBoolean(PREF_DEBUG_SETTINGS, showDebugSettings);
377         // Debug menu items have precidence if the menu is visible
378         if (showDebugSettings) {
379             boolean small_screen = p.getBoolean("small_screen",
380                     layoutAlgorithm ==
381                     WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
382             if (small_screen) {
383                 layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN;
384             } else {
385                 boolean normal_layout = p.getBoolean("normal_layout",
386                         layoutAlgorithm == WebSettings.LayoutAlgorithm.NORMAL);
387                 if (normal_layout) {
388                     layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL;
389                 } else {
390                     layoutAlgorithm =
391                             WebSettings.LayoutAlgorithm.NARROW_COLUMNS;
392                 }
393             }
394             useWideViewPort = p.getBoolean("wide_viewport", useWideViewPort);
395             tracing = p.getBoolean("enable_tracing", tracing);
396             lightTouch = p.getBoolean("enable_light_touch", lightTouch);
397             navDump = p.getBoolean("enable_nav_dump", navDump);
398             userAgent = Integer.parseInt(p.getString("user_agent", "0"));
399         }
400         // JS flags is loaded from DB even if showDebugSettings is false,
401         // so that it can be set once and be effective all the time.
402         jsFlags = p.getString("js_engine_flags", "");
403 
404         // Read the setting for showing/hiding the JS Console always so that should the
405         // user enable debug settings, we already know if we should show the console.
406         // The user will never see the console unless they navigate to about:debug,
407         // regardless of the setting we read here. This setting is only used after debug
408         // is enabled.
409         showConsole = p.getBoolean("javascript_console", showConsole);
410 
411         // HTML5 API flags
412         appCacheEnabled = p.getBoolean("enable_appcache", appCacheEnabled);
413         databaseEnabled = p.getBoolean("enable_database", databaseEnabled);
414         domStorageEnabled = p.getBoolean("enable_domstorage", domStorageEnabled);
415         geolocationEnabled = p.getBoolean("enable_geolocation", geolocationEnabled);
416         workersEnabled = p.getBoolean("enable_workers", workersEnabled);
417 
418         update();
419     }
420 
getHomePage()421     public String getHomePage() {
422         return homeUrl;
423     }
424 
getSearchEngine()425     public SearchEngine getSearchEngine() {
426         return searchEngine;
427     }
428 
getJsFlags()429     public String getJsFlags() {
430         return jsFlags;
431     }
432 
getWebStorageSizeManager()433     public WebStorageSizeManager getWebStorageSizeManager() {
434         return webStorageSizeManager;
435     }
436 
setHomePage(Context context, String url)437     public void setHomePage(Context context, String url) {
438         Editor ed = PreferenceManager.
439                 getDefaultSharedPreferences(context).edit();
440         ed.putString(PREF_HOMEPAGE, url);
441         ed.apply();
442         homeUrl = url;
443     }
444 
getTextSize()445     public WebSettings.TextSize getTextSize() {
446         return textSize;
447     }
448 
getDefaultZoom()449     public WebSettings.ZoomDensity getDefaultZoom() {
450         return zoomDensity;
451     }
452 
openInBackground()453     public boolean openInBackground() {
454         return openInBackground;
455     }
456 
showSecurityWarnings()457     public boolean showSecurityWarnings() {
458         return showSecurityWarnings;
459     }
460 
isTracing()461     public boolean isTracing() {
462         return tracing;
463     }
464 
isLightTouch()465     public boolean isLightTouch() {
466         return lightTouch;
467     }
468 
isNavDump()469     public boolean isNavDump() {
470         return navDump;
471     }
472 
showDebugSettings()473     public boolean showDebugSettings() {
474         return showDebugSettings;
475     }
476 
toggleDebugSettings()477     public void toggleDebugSettings() {
478         showDebugSettings = !showDebugSettings;
479         navDump = showDebugSettings;
480         update();
481     }
482 
483     /**
484      * Add a WebSettings object to the list of observers that will be updated
485      * when update() is called.
486      *
487      * @param s A WebSettings object that is strictly tied to the life of a
488      *            WebView.
489      */
addObserver(WebSettings s)490     public Observer addObserver(WebSettings s) {
491         Observer old = mWebSettingsToObservers.get(s);
492         if (old != null) {
493             super.deleteObserver(old);
494         }
495         Observer o = new Observer(s);
496         mWebSettingsToObservers.put(s, o);
497         super.addObserver(o);
498         return o;
499     }
500 
501     /**
502      * Delete the given WebSettings observer from the list of observers.
503      * @param s The WebSettings object to be deleted.
504      */
deleteObserver(WebSettings s)505     public void deleteObserver(WebSettings s) {
506         Observer o = mWebSettingsToObservers.get(s);
507         if (o != null) {
508             mWebSettingsToObservers.remove(s);
509             super.deleteObserver(o);
510         }
511     }
512 
513     /*
514      * Package level method for obtaining a single app instance of the
515      * BrowserSettings.
516      */
getInstance()517     /*package*/ static BrowserSettings getInstance() {
518         if (sSingleton == null ) {
519             sSingleton = new BrowserSettings();
520         }
521         return sSingleton;
522     }
523 
524     /*
525      * Package level method for associating the BrowserSettings with TabControl
526      */
setTabControl(TabControl tabControl)527     /* package */void setTabControl(TabControl tabControl) {
528         mTabControl = tabControl;
529         updateTabControlSettings();
530     }
531 
532     /*
533      * Update all the observers of the object.
534      */
update()535     /*package*/ void update() {
536         setChanged();
537         notifyObservers();
538     }
539 
clearCache(Context context)540     /*package*/ void clearCache(Context context) {
541         WebIconDatabase.getInstance().removeAllIcons();
542         if (mTabControl != null) {
543             WebView current = mTabControl.getCurrentWebView();
544             if (current != null) {
545                 current.clearCache(true);
546             }
547         }
548     }
549 
clearCookies(Context context)550     /*package*/ void clearCookies(Context context) {
551         CookieManager.getInstance().removeAllCookie();
552     }
553 
clearHistory(Context context)554     /* package */void clearHistory(Context context) {
555         ContentResolver resolver = context.getContentResolver();
556         Browser.clearHistory(resolver);
557         Browser.clearSearches(resolver);
558     }
559 
clearFormData(Context context)560     /* package */ void clearFormData(Context context) {
561         WebViewDatabase.getInstance(context).clearFormData();
562         if (mTabControl != null) {
563             WebView currentTopView = mTabControl.getCurrentTopWebView();
564             if (currentTopView != null) {
565                 currentTopView.clearFormData();
566             }
567         }
568     }
569 
clearPasswords(Context context)570     /*package*/ void clearPasswords(Context context) {
571         WebViewDatabase db = WebViewDatabase.getInstance(context);
572         db.clearUsernamePassword();
573         db.clearHttpAuthUsernamePassword();
574     }
575 
updateTabControlSettings()576     private void updateTabControlSettings() {
577         // Enable/disable the error console.
578         mTabControl.getBrowserActivity().setShouldShowErrorConsole(
579             showDebugSettings && showConsole);
580         mTabControl.getBrowserActivity().setRequestedOrientation(
581             landscapeOnly ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
582             : ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
583     }
584 
maybeDisableWebsiteSettings(Context context)585     private void maybeDisableWebsiteSettings(Context context) {
586         PreferenceActivity activity = (PreferenceActivity) context;
587         final PreferenceScreen screen = (PreferenceScreen)
588             activity.findPreference(BrowserSettings.PREF_WEBSITE_SETTINGS);
589         screen.setEnabled(false);
590         WebStorage.getInstance().getOrigins(new ValueCallback<Map>() {
591             public void onReceiveValue(Map webStorageOrigins) {
592                 if ((webStorageOrigins != null) && !webStorageOrigins.isEmpty()) {
593                     screen.setEnabled(true);
594                 }
595             }
596         });
597 
598         GeolocationPermissions.getInstance().getOrigins(new ValueCallback<Set<String> >() {
599             public void onReceiveValue(Set<String> geolocationOrigins) {
600                 if ((geolocationOrigins != null) && !geolocationOrigins.isEmpty()) {
601                     screen.setEnabled(true);
602                 }
603             }
604         });
605     }
606 
clearDatabases(Context context)607     /*package*/ void clearDatabases(Context context) {
608         WebStorage.getInstance().deleteAllData();
609         maybeDisableWebsiteSettings(context);
610     }
611 
clearLocationAccess(Context context)612     /*package*/ void clearLocationAccess(Context context) {
613         GeolocationPermissions.getInstance().clearAll();
614         maybeDisableWebsiteSettings(context);
615     }
616 
resetDefaultPreferences(Context ctx)617     /*package*/ void resetDefaultPreferences(Context ctx) {
618         reset();
619         SharedPreferences p =
620             PreferenceManager.getDefaultSharedPreferences(ctx);
621         p.edit().clear().apply();
622         PreferenceManager.setDefaultValues(ctx, R.xml.browser_preferences,
623                 true);
624         // reset homeUrl
625         setHomePage(ctx, getFactoryResetHomeUrl(ctx));
626         // reset appcache max size
627         appCacheMaxSize = webStorageSizeManager.getAppCacheMaxSize();
628     }
629 
getFactoryResetHomeUrl(Context context)630     private String getFactoryResetHomeUrl(Context context) {
631         String url = context.getResources().getString(R.string.homepage_base);
632         if (url.indexOf("{CID}") != -1) {
633             url = url.replace("{CID}",
634                     BrowserProvider.getClientId(context.getContentResolver()));
635         }
636         return url;
637     }
638 
639     // Private constructor that does nothing.
BrowserSettings()640     private BrowserSettings() {
641         reset();
642     }
643 
reset()644     private void reset() {
645         // Private variables for settings
646         // NOTE: these defaults need to be kept in sync with the XML
647         // until the performance of PreferenceManager.setDefaultValues()
648         // is improved.
649         loadsImagesAutomatically = true;
650         javaScriptEnabled = true;
651         pluginState = WebSettings.PluginState.ON;
652         javaScriptCanOpenWindowsAutomatically = false;
653         showSecurityWarnings = true;
654         rememberPasswords = true;
655         saveFormData = true;
656         openInBackground = false;
657         autoFitPage = true;
658         landscapeOnly = false;
659         loadsPageInOverviewMode = true;
660         showDebugSettings = false;
661         // HTML5 API flags
662         appCacheEnabled = true;
663         databaseEnabled = true;
664         domStorageEnabled = true;
665         geolocationEnabled = true;
666         workersEnabled = true;  // only affects V8. JSC does not have a similar setting
667     }
668 
getRlzValue()669     /*package*/ String getRlzValue() {
670         return mRlzValue;
671     }
672 
updateRlzValues(Context context)673     /*package*/ void updateRlzValues(Context context) {
674         // Use AsyncTask because this queries both RlzProvider and Bookmarks URIs
675         new RlzUpdateTask(context).execute();
676     }
677 
678     private class RlzUpdateTask extends AsyncTask<Void, Void, Void> {
679         private final Context context;
680 
RlzUpdateTask(Context context)681         public RlzUpdateTask(Context context) {
682             this.context = context;
683         }
684 
685         @Override
doInBackground(Void...unused)686         protected Void doInBackground(Void...unused) {
687             String rlz = retrieveRlzValue(context);
688             if (!rlz.isEmpty()) {
689                 mRlzValue = rlz;
690                 updateHomePageRlzParameter(context);
691                 updateBookmarksRlzParameter(context);
692             }
693             return null;
694         }
695     }
696 
697     // Update RLZ value if present in Home page
updateHomePageRlzParameter(Context context)698     private void updateHomePageRlzParameter(Context context) {
699         Uri uri = Uri.parse(homeUrl);
700         if ((uri.getQueryParameter("rlz") != null) && UrlUtils.isGoogleUri(uri)) {
701             String newHomeUrl = updateRlzParameter(homeUrl);
702             if (!homeUrl.equals(newHomeUrl)) {
703                 setHomePage(context, newHomeUrl);
704             }
705         }
706     }
707 
708     // Update RLZ value if present in bookmarks
updateBookmarksRlzParameter(Context context)709     private void updateBookmarksRlzParameter(Context context) {
710         Cursor cur = null;
711         try {
712             cur = context.getContentResolver().query(Browser.BOOKMARKS_URI,
713                 new String[] { BookmarkColumns._ID, BookmarkColumns.URL },
714                 "url LIKE '%rlz=%'", null, null);
715             if ((cur == null) || (cur.getCount() == 0)) {
716                 return;
717             }
718             for (cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()) {
719                 long id = cur.getLong(0);
720                 String url = cur.getString(1);
721                 if ((url == null) || url.isEmpty()) {
722                     continue;
723                 }
724 
725                 Uri uri = Uri.parse(url);
726                 if ((uri.getQueryParameter("rlz") != null) && UrlUtils.isGoogleUri(uri)) {
727                     String newUrl = updateRlzParameter(url);
728                     if (!url.equals(newUrl)) {
729                         ContentValues values = new ContentValues();
730                         values.put(BookmarkColumns.URL, newUrl);
731                         Uri bookmarkUri = ContentUris.withAppendedId(Browser.BOOKMARKS_URI, id);
732                         context.getContentResolver().update(bookmarkUri, values, null, null);
733                     }
734                 }
735             }
736         } finally {
737             if (cur != null) {
738                 cur.close();
739             }
740         }
741     }
742 
updateRlzParameter(String url)743     private String updateRlzParameter(String url) {
744         Uri uri = Uri.parse(url);
745         String oldRlz = uri.getQueryParameter("rlz");
746         if (oldRlz != null) {
747             return url.replace("rlz=" + oldRlz, "rlz=" + mRlzValue);
748         }
749         return url;
750     }
751 
752     // Retrieve the RLZ value from the Rlz Provider
retrieveRlzValue(Context context)753     private static String retrieveRlzValue(Context context) {
754         String rlz = "";
755         PackageManager pm = context.getPackageManager();
756         if (pm.resolveContentProvider(RLZ_PROVIDER, 0) == null) {
757             return rlz;
758         }
759 
760         String ap = context.getResources().getString(R.string.rlz_access_point);
761         if (ap.isEmpty()) {
762             return rlz;
763         }
764 
765         Uri rlzUri = Uri.withAppendedPath(RLZ_PROVIDER_URI, ap);
766         Cursor cur = null;
767         try {
768             cur = context.getContentResolver().query(rlzUri, null, null, null, null);
769             if (cur != null && cur.moveToFirst() && !cur.isNull(0)) {
770                 rlz = cur.getString(0);
771             }
772         } finally {
773             if (cur != null) {
774                 cur.close();
775             }
776         }
777         return rlz;
778     }
779 }
780