OSDN Git Service

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