OSDN Git Service

am e08dbd1e: Merge change 26219 into eclair
[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 com.google.android.providers.GoogleSettings.Partner;
21
22 import android.content.ContentResolver;
23 import android.content.Context;
24 import android.content.pm.ActivityInfo;
25 import android.content.SharedPreferences;
26 import android.content.SharedPreferences.Editor;
27 import android.preference.PreferenceActivity;
28 import android.preference.PreferenceScreen;
29 import android.webkit.CookieManager;
30 import android.webkit.GeolocationPermissions;
31 import android.webkit.ValueCallback;
32 import android.webkit.WebView;
33 import android.webkit.WebViewDatabase;
34 import android.webkit.WebIconDatabase;
35 import android.webkit.WebSettings;
36 import android.webkit.WebStorage;
37 import android.preference.PreferenceManager;
38 import android.provider.Browser;
39
40 import java.util.HashMap;
41 import java.util.Map;
42 import java.util.Set;
43 import java.util.Observable;
44
45 /*
46  * Package level class for storing various WebView and Browser settings. To use
47  * this class:
48  * BrowserSettings s = BrowserSettings.getInstance();
49  * s.addObserver(webView.getSettings());
50  * s.loadFromDb(context); // Only needed on app startup
51  * s.javaScriptEnabled = true;
52  * ... // set any other settings
53  * s.update(); // this will update all the observers
54  *
55  * To remove an observer:
56  * s.deleteObserver(webView.getSettings());
57  */
58 class BrowserSettings extends Observable {
59
60     // Private variables for settings
61     // NOTE: these defaults need to be kept in sync with the XML
62     // until the performance of PreferenceManager.setDefaultValues()
63     // is improved.
64     private boolean loadsImagesAutomatically = true;
65     private boolean javaScriptEnabled = true;
66     private boolean pluginsEnabled = true;
67     private String pluginsPath;  // default value set in loadFromDb().
68     private boolean javaScriptCanOpenWindowsAutomatically = false;
69     private boolean showSecurityWarnings = true;
70     private boolean rememberPasswords = true;
71     private boolean saveFormData = true;
72     private boolean openInBackground = false;
73     private String defaultTextEncodingName;
74     private String homeUrl = "";
75     private boolean loginInitialized = false;
76     private boolean autoFitPage = true;
77     private boolean landscapeOnly = false;
78     private boolean loadsPageInOverviewMode = true;
79     private boolean showDebugSettings = false;
80     // HTML5 API flags
81     private boolean appCacheEnabled = true;
82     private boolean databaseEnabled = true;
83     private boolean domStorageEnabled = true;
84     private boolean geolocationEnabled = true;
85     private boolean workersEnabled = true;  // only affects V8. JSC does not have a similar setting
86     // HTML5 API configuration params
87     private long appCacheMaxSize = Long.MAX_VALUE;
88     private String appCachePath;  // default value set in loadFromDb().
89     private String databasePath; // default value set in loadFromDb()
90     private String geolocationDatabasePath; // default value set in loadFromDb()
91     private WebStorageSizeManager webStorageSizeManager;
92
93     private String jsFlags = "";
94
95     private final static String TAG = "BrowserSettings";
96
97     // Development settings
98     public WebSettings.LayoutAlgorithm layoutAlgorithm =
99         WebSettings.LayoutAlgorithm.NARROW_COLUMNS;
100     private boolean useWideViewPort = true;
101     private int userAgent = 0;
102     private boolean tracing = false;
103     private boolean lightTouch = false;
104     private boolean navDump = false;
105
106     // By default the error console is shown once the user navigates to about:debug.
107     // The setting can be then toggled from the settings menu.
108     private boolean showConsole = true;
109
110     // Browser only settings
111     private boolean doFlick = false;
112
113     // Private preconfigured values
114     private static int minimumFontSize = 8;
115     private static int minimumLogicalFontSize = 8;
116     private static int defaultFontSize = 16;
117     private static int defaultFixedFontSize = 13;
118     private static WebSettings.TextSize textSize =
119         WebSettings.TextSize.NORMAL;
120     private static WebSettings.ZoomDensity zoomDensity =
121         WebSettings.ZoomDensity.MEDIUM;
122
123     // Preference keys that are used outside this class
124     public final static String PREF_CLEAR_CACHE = "privacy_clear_cache";
125     public final static String PREF_CLEAR_COOKIES = "privacy_clear_cookies";
126     public final static String PREF_CLEAR_HISTORY = "privacy_clear_history";
127     public final static String PREF_HOMEPAGE = "homepage";
128     public final static String PREF_CLEAR_FORM_DATA =
129             "privacy_clear_form_data";
130     public final static String PREF_CLEAR_PASSWORDS =
131             "privacy_clear_passwords";
132     public final static String PREF_EXTRAS_RESET_DEFAULTS =
133             "reset_default_preferences";
134     public final static String PREF_DEBUG_SETTINGS = "debug_menu";
135     public final static String PREF_WEBSITE_SETTINGS = "website_settings";
136     public final static String PREF_TEXT_SIZE = "text_size";
137     public final static String PREF_DEFAULT_ZOOM = "default_zoom";
138     public final static String PREF_DEFAULT_TEXT_ENCODING =
139             "default_text_encoding";
140     public final static String PREF_CLEAR_GEOLOCATION_ACCESS =
141             "privacy_clear_geolocation_access";
142
143     private static final String DESKTOP_USERAGENT = "Mozilla/5.0 (Macintosh; " +
144             "U; Intel Mac OS X 10_5_7; en-us) AppleWebKit/530.17 (KHTML, " +
145             "like Gecko) Version/4.0 Safari/530.17";
146
147     private static final String IPHONE_USERAGENT = "Mozilla/5.0 (iPhone; U; " +
148             "CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 " +
149             "(KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16";
150
151     // Value to truncate strings when adding them to a TextView within
152     // a ListView
153     public final static int MAX_TEXTVIEW_LEN = 80;
154
155     private TabControl mTabControl;
156
157     // Single instance of the BrowserSettings for use in the Browser app.
158     private static BrowserSettings sSingleton;
159
160     // Private map of WebSettings to Observer objects used when deleting an
161     // observer.
162     private HashMap<WebSettings,Observer> mWebSettingsToObservers =
163         new HashMap<WebSettings,Observer>();
164
165     /*
166      * An observer wrapper for updating a WebSettings object with the new
167      * settings after a call to BrowserSettings.update().
168      */
169     static class Observer implements java.util.Observer {
170         // Private WebSettings object that will be updated.
171         private WebSettings mSettings;
172
173         Observer(WebSettings w) {
174             mSettings = w;
175         }
176
177         public void update(Observable o, Object arg) {
178             BrowserSettings b = (BrowserSettings)o;
179             WebSettings s = mSettings;
180
181             s.setLayoutAlgorithm(b.layoutAlgorithm);
182             if (b.userAgent == 0) {
183                 // use the default ua string
184                 s.setUserAgentString(null);
185             } else if (b.userAgent == 1) {
186                 s.setUserAgentString(DESKTOP_USERAGENT);
187             } else if (b.userAgent == 2) {
188                 s.setUserAgentString(IPHONE_USERAGENT);
189             }
190             s.setUseWideViewPort(b.useWideViewPort);
191             s.setLoadsImagesAutomatically(b.loadsImagesAutomatically);
192             s.setJavaScriptEnabled(b.javaScriptEnabled);
193             s.setPluginsEnabled(b.pluginsEnabled);
194             s.setJavaScriptCanOpenWindowsAutomatically(
195                     b.javaScriptCanOpenWindowsAutomatically);
196             s.setDefaultTextEncodingName(b.defaultTextEncodingName);
197             s.setMinimumFontSize(b.minimumFontSize);
198             s.setMinimumLogicalFontSize(b.minimumLogicalFontSize);
199             s.setDefaultFontSize(b.defaultFontSize);
200             s.setDefaultFixedFontSize(b.defaultFixedFontSize);
201             s.setNavDump(b.navDump);
202             s.setTextSize(b.textSize);
203             s.setDefaultZoom(b.zoomDensity);
204             s.setLightTouchEnabled(b.lightTouch);
205             s.setSaveFormData(b.saveFormData);
206             s.setSavePassword(b.rememberPasswords);
207             s.setLoadWithOverviewMode(b.loadsPageInOverviewMode);
208
209             // WebView inside Browser doesn't want initial focus to be set.
210             s.setNeedInitialFocus(false);
211             // Browser supports multiple windows
212             s.setSupportMultipleWindows(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             // Enable/Disable the error console.
228             b.mTabControl.getBrowserActivity().setShouldShowErrorConsole(
229                     b.showDebugSettings && b.showConsole);
230         }
231     }
232
233     /**
234      * Load settings from the browser app's database.
235      * NOTE: Strings used for the preferences must match those specified
236      * in the browser_preferences.xml
237      * @param ctx A Context object used to query the browser's settings
238      *            database. If the database exists, the saved settings will be
239      *            stored in this BrowserSettings object. This will update all
240      *            observers of this object.
241      */
242     public void loadFromDb(Context ctx) {
243         SharedPreferences p =
244                 PreferenceManager.getDefaultSharedPreferences(ctx);
245
246         // Set the default value for the plugins path to the application's
247         // local directory.
248         pluginsPath = ctx.getDir("plugins", 0).getPath();
249         // Set the default value for the Application Caches path.
250         appCachePath = ctx.getDir("appcache", 0).getPath();
251         // Determine the maximum size of the application cache.
252         webStorageSizeManager = new WebStorageSizeManager(
253                 ctx,
254                 new WebStorageSizeManager.StatFsDiskInfo(appCachePath),
255                 new WebStorageSizeManager.WebKitAppCacheInfo(appCachePath));
256         appCacheMaxSize = webStorageSizeManager.getAppCacheMaxSize();
257         // Set the default value for the Database path.
258         databasePath = ctx.getDir("databases", 0).getPath();
259         // Set the default value for the Geolocation database path.
260         geolocationDatabasePath = ctx.getDir("geolocation", 0).getPath();
261
262         homeUrl = getFactoryResetHomeUrl(ctx);
263
264         // Load the defaults from the xml
265         // This call is TOO SLOW, need to manually keep the defaults
266         // in sync
267         //PreferenceManager.setDefaultValues(ctx, R.xml.browser_preferences);
268         syncSharedPreferences(p);
269     }
270
271     /* package */ void syncSharedPreferences(SharedPreferences p) {
272
273         homeUrl =
274             p.getString(PREF_HOMEPAGE, homeUrl);
275
276         loadsImagesAutomatically = p.getBoolean("load_images",
277                 loadsImagesAutomatically);
278         javaScriptEnabled = p.getBoolean("enable_javascript",
279                 javaScriptEnabled);
280         pluginsEnabled = p.getBoolean("enable_plugins",
281                 pluginsEnabled);
282         pluginsPath = p.getString("plugins_path", pluginsPath);
283         javaScriptCanOpenWindowsAutomatically = !p.getBoolean(
284             "block_popup_windows",
285             !javaScriptCanOpenWindowsAutomatically);
286         showSecurityWarnings = p.getBoolean("show_security_warnings",
287                 showSecurityWarnings);
288         rememberPasswords = p.getBoolean("remember_passwords",
289                 rememberPasswords);
290         saveFormData = p.getBoolean("save_formdata",
291                 saveFormData);
292         boolean accept_cookies = p.getBoolean("accept_cookies",
293                 CookieManager.getInstance().acceptCookie());
294         CookieManager.getInstance().setAcceptCookie(accept_cookies);
295         openInBackground = p.getBoolean("open_in_background", openInBackground);
296         loginInitialized = p.getBoolean("login_initialized", loginInitialized);
297         textSize = WebSettings.TextSize.valueOf(
298                 p.getString(PREF_TEXT_SIZE, textSize.name()));
299         zoomDensity = WebSettings.ZoomDensity.valueOf(
300                 p.getString(PREF_DEFAULT_ZOOM, zoomDensity.name()));
301         autoFitPage = p.getBoolean("autofit_pages", autoFitPage);
302         loadsPageInOverviewMode = p.getBoolean("load_page",
303                 loadsPageInOverviewMode);
304         boolean landscapeOnlyTemp =
305                 p.getBoolean("landscape_only", landscapeOnly);
306         if (landscapeOnlyTemp != landscapeOnly) {
307             landscapeOnly = landscapeOnlyTemp;
308             mTabControl.getBrowserActivity().setRequestedOrientation(
309                     landscapeOnly ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
310                     : ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
311         }
312         useWideViewPort = true; // use wide view port for either setting
313         if (autoFitPage) {
314             layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS;
315         } else {
316             layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL;
317         }
318         defaultTextEncodingName =
319                 p.getString(PREF_DEFAULT_TEXT_ENCODING,
320                         defaultTextEncodingName);
321
322         showDebugSettings =
323                 p.getBoolean(PREF_DEBUG_SETTINGS, showDebugSettings);
324         // Debug menu items have precidence if the menu is visible
325         if (showDebugSettings) {
326             boolean small_screen = p.getBoolean("small_screen",
327                     layoutAlgorithm ==
328                     WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
329             if (small_screen) {
330                 layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN;
331             } else {
332                 boolean normal_layout = p.getBoolean("normal_layout",
333                         layoutAlgorithm == WebSettings.LayoutAlgorithm.NORMAL);
334                 if (normal_layout) {
335                     layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL;
336                 } else {
337                     layoutAlgorithm =
338                             WebSettings.LayoutAlgorithm.NARROW_COLUMNS;
339                 }
340             }
341             useWideViewPort = p.getBoolean("wide_viewport", useWideViewPort);
342             tracing = p.getBoolean("enable_tracing", tracing);
343             lightTouch = p.getBoolean("enable_light_touch", lightTouch);
344             navDump = p.getBoolean("enable_nav_dump", navDump);
345             doFlick = p.getBoolean("enable_flick", doFlick);
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         mTabControl.getBrowserActivity().setShouldShowErrorConsole(
359                 showDebugSettings && showConsole);
360
361         // HTML5 API flags
362         appCacheEnabled = p.getBoolean("enable_appcache", appCacheEnabled);
363         databaseEnabled = p.getBoolean("enable_database", databaseEnabled);
364         domStorageEnabled = p.getBoolean("enable_domstorage", domStorageEnabled);
365         geolocationEnabled = p.getBoolean("enable_geolocation", geolocationEnabled);
366         workersEnabled = p.getBoolean("enable_workers", workersEnabled);
367
368         update();
369     }
370
371     public String getPluginsPath() {
372         return pluginsPath;
373     }
374
375     public String getHomePage() {
376         return homeUrl;
377     }
378
379     public String getJsFlags() {
380         return jsFlags;
381     }
382
383     public WebStorageSizeManager getWebStorageSizeManager() {
384         return webStorageSizeManager;
385     }
386
387     public void setHomePage(Context context, String url) {
388         Editor ed = PreferenceManager.
389                 getDefaultSharedPreferences(context).edit();
390         ed.putString(PREF_HOMEPAGE, url);
391         ed.commit();
392         homeUrl = url;
393     }
394
395     public boolean isLoginInitialized() {
396         return loginInitialized;
397     }
398
399     public void setLoginInitialized(Context context) {
400         loginInitialized = true;
401         Editor ed = PreferenceManager.
402                 getDefaultSharedPreferences(context).edit();
403         ed.putBoolean("login_initialized", loginInitialized);
404         ed.commit();
405     }
406
407     public WebSettings.TextSize getTextSize() {
408         return textSize;
409     }
410
411     public WebSettings.ZoomDensity getDefaultZoom() {
412         return zoomDensity;
413     }
414
415     public boolean openInBackground() {
416         return openInBackground;
417     }
418
419     public boolean showSecurityWarnings() {
420         return showSecurityWarnings;
421     }
422
423     public boolean isTracing() {
424         return tracing;
425     }
426
427     public boolean isLightTouch() {
428         return lightTouch;
429     }
430
431     public boolean isNavDump() {
432         return navDump;
433     }
434
435     public boolean doFlick() {
436         return doFlick;
437     }
438
439     public boolean showDebugSettings() {
440         return showDebugSettings;
441     }
442
443     public void toggleDebugSettings() {
444         showDebugSettings = !showDebugSettings;
445         navDump = showDebugSettings;
446         update();
447     }
448
449     /**
450      * Add a WebSettings object to the list of observers that will be updated
451      * when update() is called.
452      *
453      * @param s A WebSettings object that is strictly tied to the life of a
454      *            WebView.
455      */
456     public Observer addObserver(WebSettings s) {
457         Observer old = mWebSettingsToObservers.get(s);
458         if (old != null) {
459             super.deleteObserver(old);
460         }
461         Observer o = new Observer(s);
462         mWebSettingsToObservers.put(s, o);
463         super.addObserver(o);
464         return o;
465     }
466
467     /**
468      * Delete the given WebSettings observer from the list of observers.
469      * @param s The WebSettings object to be deleted.
470      */
471     public void deleteObserver(WebSettings s) {
472         Observer o = mWebSettingsToObservers.get(s);
473         if (o != null) {
474             mWebSettingsToObservers.remove(s);
475             super.deleteObserver(o);
476         }
477     }
478
479     /*
480      * Package level method for obtaining a single app instance of the
481      * BrowserSettings.
482      */
483     /*package*/ static BrowserSettings getInstance() {
484         if (sSingleton == null ) {
485             sSingleton = new BrowserSettings();
486         }
487         return sSingleton;
488     }
489
490     /*
491      * Package level method for associating the BrowserSettings with TabControl
492      */
493     /* package */void setTabControl(TabControl tabControl) {
494         mTabControl = tabControl;
495     }
496
497     /*
498      * Update all the observers of the object.
499      */
500     /*package*/ void update() {
501         setChanged();
502         notifyObservers();
503     }
504
505     /*package*/ void clearCache(Context context) {
506         WebIconDatabase.getInstance().removeAllIcons();
507         if (mTabControl != null) {
508             WebView current = mTabControl.getCurrentWebView();
509             if (current != null) {
510                 current.clearCache(true);
511             }
512         }
513     }
514
515     /*package*/ void clearCookies(Context context) {
516         CookieManager.getInstance().removeAllCookie();
517     }
518
519     /* package */void clearHistory(Context context) {
520         ContentResolver resolver = context.getContentResolver();
521         Browser.clearHistory(resolver);
522         Browser.clearSearches(resolver);
523     }
524
525     /* package */ void clearFormData(Context context) {
526         WebViewDatabase.getInstance(context).clearFormData();
527         if (mTabControl != null) {
528             mTabControl.getCurrentTopWebView().clearFormData();
529         }
530     }
531
532     /*package*/ void clearPasswords(Context context) {
533         WebViewDatabase db = WebViewDatabase.getInstance(context);
534         db.clearUsernamePassword();
535         db.clearHttpAuthUsernamePassword();
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>() {
552             public void onReceiveValue(Set 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         SharedPreferences p =
572             PreferenceManager.getDefaultSharedPreferences(ctx);
573         p.edit().clear().commit();
574         PreferenceManager.setDefaultValues(ctx, R.xml.browser_preferences,
575                 true);
576         // reset homeUrl
577         setHomePage(ctx, getFactoryResetHomeUrl(ctx));
578         // reset appcache max size
579         appCacheMaxSize = webStorageSizeManager.getAppCacheMaxSize();
580     }
581
582     private String getFactoryResetHomeUrl(Context context) {
583         String url = context.getResources().getString(R.string.homepage_base);
584         if (url.indexOf("{CID}") != -1) {
585             url = url.replace("{CID}", Partner.getString(context
586                     .getContentResolver(), Partner.CLIENT_ID, "android-google"));
587         }
588         return url;
589     }
590
591     // Private constructor that does nothing.
592     private BrowserSettings() {
593     }
594 }