BrowserSettings.java revision 092dd5d22d7f2ee0efcc68bd6e5a3afd1ea98953
1/*
2 * Copyright (C) 2007 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 com.google.android.providers.GoogleSettings.Partner;
20
21import android.app.Activity;
22import android.content.ContentResolver;
23import android.content.Context;
24import android.content.pm.ActivityInfo;
25import android.content.SharedPreferences;
26import android.content.SharedPreferences.Editor;
27import android.os.SystemProperties;
28import android.view.WindowManager;
29import android.webkit.CacheManager;
30import android.webkit.CookieManager;
31import android.webkit.WebView;
32import android.webkit.WebViewDatabase;
33import android.webkit.WebIconDatabase;
34import android.webkit.WebSettings;
35import android.preference.PreferenceManager;
36import android.provider.Browser;
37
38import java.util.HashMap;
39import java.util.Observable;
40
41/*
42 * Package level class for storing various WebView and Browser settings. To use
43 * this class:
44 * BrowserSettings s = BrowserSettings.getInstance();
45 * s.addObserver(webView.getSettings());
46 * s.loadFromDb(context); // Only needed on app startup
47 * s.javaScriptEnabled = true;
48 * ... // set any other settings
49 * s.update(); // this will update all the observers
50 *
51 * To remove an observer:
52 * s.deleteObserver(webView.getSettings());
53 */
54class BrowserSettings extends Observable {
55
56    private static final String DEFAULT_HOME_URL =
57            "http://www.google.com/m?client=ms-";
58    // Private variables for settings
59    // NOTE: these defaults need to be kept in sync with the XML
60    // until the performance of PreferenceManager.setDefaultValues()
61    // is improved.
62    private boolean loadsImagesAutomatically = true;
63    private boolean javaScriptEnabled = true;
64    private boolean pluginsEnabled = true;
65    private String pluginsPath;  // default value set in loadFromDb().
66    private boolean javaScriptCanOpenWindowsAutomatically = false;
67    private boolean showSecurityWarnings = true;
68    private boolean rememberPasswords = true;
69    private boolean saveFormData = true;
70    private boolean openInBackground = false;
71    private String defaultTextEncodingName;
72    private String homeUrl;
73    private boolean loginInitialized = false;
74    private boolean autoFitPage = true;
75    private boolean landscapeOnly = false;
76    private boolean showDebugSettings = false;
77    private String databasePath; // default value set in loadFromDb()
78    private boolean databaseEnabled = true;
79    // The Browser always enables Application Caches.
80    private boolean appCacheEnabled = true;
81    private String appCachePath;  // default value set in loadFromDb().
82
83    // Development settings
84    public WebSettings.LayoutAlgorithm layoutAlgorithm =
85        WebSettings.LayoutAlgorithm.NARROW_COLUMNS;
86    private boolean useWideViewPort = true;
87    private int userAgent = 0;
88    private boolean tracing = false;
89    private boolean lightTouch = false;
90    private boolean navDump = false;
91    // Browser only settings
92    private boolean doFlick = false;
93
94    // Private preconfigured values
95    private static int minimumFontSize = 8;
96    private static int minimumLogicalFontSize = 8;
97    private static int defaultFontSize = 16;
98    private static int defaultFixedFontSize = 13;
99    private static WebSettings.TextSize textSize =
100        WebSettings.TextSize.NORMAL;
101
102    // Preference keys that are used outside this class
103    public final static String PREF_CLEAR_CACHE = "privacy_clear_cache";
104    public final static String PREF_CLEAR_COOKIES = "privacy_clear_cookies";
105    public final static String PREF_CLEAR_HISTORY = "privacy_clear_history";
106    public final static String PREF_HOMEPAGE = "homepage";
107    public final static String PREF_CLEAR_FORM_DATA =
108            "privacy_clear_form_data";
109    public final static String PREF_CLEAR_PASSWORDS =
110            "privacy_clear_passwords";
111    public final static String PREF_EXTRAS_RESET_DEFAULTS =
112            "reset_default_preferences";
113    public final static String PREF_DEBUG_SETTINGS = "debug_menu";
114    public final static String PREF_GEARS_SETTINGS = "gears_settings";
115    public final static String PREF_TEXT_SIZE = "text_size";
116    public final static String PREF_DEFAULT_TEXT_ENCODING =
117            "default_text_encoding";
118
119    private static final String DESKTOP_USERAGENT = "Mozilla/5.0 (Macintosh; " +
120            "U; Intel Mac OS X 10_5_5; en-us) AppleWebKit/525.18 (KHTML, " +
121            "like Gecko) Version/3.1.2 Safari/525.20.1";
122
123    private static final String IPHONE_USERAGENT = "Mozilla/5.0 (iPhone; U; " +
124            "CPU iPhone OS 2_2 like Mac OS X; en-us) AppleWebKit/525.18.1 " +
125            "(KHTML, like Gecko) Version/3.1.1 Mobile/5G77 Safari/525.20";
126
127    // Value to truncate strings when adding them to a TextView within
128    // a ListView
129    public final static int MAX_TEXTVIEW_LEN = 80;
130
131    private TabControl mTabControl;
132
133    // Single instance of the BrowserSettings for use in the Browser app.
134    private static BrowserSettings sSingleton;
135
136    // Private map of WebSettings to Observer objects used when deleting an
137    // observer.
138    private HashMap<WebSettings,Observer> mWebSettingsToObservers =
139        new HashMap<WebSettings,Observer>();
140
141    /*
142     * An observer wrapper for updating a WebSettings object with the new
143     * settings after a call to BrowserSettings.update().
144     */
145    static class Observer implements java.util.Observer {
146        // Private WebSettings object that will be updated.
147        private WebSettings mSettings;
148
149        Observer(WebSettings w) {
150            mSettings = w;
151        }
152
153        public void update(Observable o, Object arg) {
154            BrowserSettings b = (BrowserSettings)o;
155            WebSettings s = mSettings;
156
157            s.setLayoutAlgorithm(b.layoutAlgorithm);
158            if (b.userAgent == 0) {
159                // use the default ua string
160                s.setUserAgentString(null);
161            } else if (b.userAgent == 1) {
162                s.setUserAgentString(DESKTOP_USERAGENT);
163            } else if (b.userAgent == 2) {
164                s.setUserAgentString(IPHONE_USERAGENT);
165            }
166            s.setUseWideViewPort(b.useWideViewPort);
167            s.setLoadsImagesAutomatically(b.loadsImagesAutomatically);
168            s.setJavaScriptEnabled(b.javaScriptEnabled);
169            s.setPluginsEnabled(b.pluginsEnabled);
170            s.setPluginsPath(b.pluginsPath);
171            s.setJavaScriptCanOpenWindowsAutomatically(
172                    b.javaScriptCanOpenWindowsAutomatically);
173            s.setDefaultTextEncodingName(b.defaultTextEncodingName);
174            s.setMinimumFontSize(b.minimumFontSize);
175            s.setMinimumLogicalFontSize(b.minimumLogicalFontSize);
176            s.setDefaultFontSize(b.defaultFontSize);
177            s.setDefaultFixedFontSize(b.defaultFixedFontSize);
178            s.setNavDump(b.navDump);
179            s.setTextSize(b.textSize);
180            s.setLightTouchEnabled(b.lightTouch);
181            s.setSaveFormData(b.saveFormData);
182            s.setSavePassword(b.rememberPasswords);
183
184            // WebView inside Browser doesn't want initial focus to be set.
185            s.setNeedInitialFocus(false);
186            // Browser supports multiple windows
187            s.setSupportMultipleWindows(true);
188            // Turn off file access
189            s.setAllowFileAccess(false);
190
191            s.setDatabasePath(b.databasePath);
192            s.setDatabaseEnabled(b.databaseEnabled);
193
194            // Turn on Application Caches.
195            s.setAppCachePath(b.appCachePath);
196            s.setAppCacheEnabled(b.appCacheEnabled);
197        }
198    }
199
200    /**
201     * Load settings from the browser app's database.
202     * NOTE: Strings used for the preferences must match those specified
203     * in the browser_preferences.xml
204     * @param ctx A Context object used to query the browser's settings
205     *            database. If the database exists, the saved settings will be
206     *            stored in this BrowserSettings object. This will update all
207     *            observers of this object.
208     */
209    public void loadFromDb(Context ctx) {
210        SharedPreferences p =
211                PreferenceManager.getDefaultSharedPreferences(ctx);
212
213        // Set the default value for the plugins path to the application's
214        // local directory.
215        pluginsPath = ctx.getDir("plugins", 0).getPath();
216        // Set the default value for the Application Caches path.
217        appCachePath = ctx.getDir("appcache", 0).getPath();
218        // Set the default value for the Database path.
219        databasePath = ctx.getDir("databases", 0).getPath();
220
221        homeUrl = DEFAULT_HOME_URL +
222                Partner.getString(ctx.getContentResolver(), Partner.CLIENT_ID);
223
224        // Load the defaults from the xml
225        // This call is TOO SLOW, need to manually keep the defaults
226        // in sync
227        //PreferenceManager.setDefaultValues(ctx, R.xml.browser_preferences);
228        syncSharedPreferences(p);
229    }
230
231    /* package */ void syncSharedPreferences(SharedPreferences p) {
232
233        homeUrl =
234            p.getString(PREF_HOMEPAGE, homeUrl);
235
236        loadsImagesAutomatically = p.getBoolean("load_images",
237                loadsImagesAutomatically);
238        javaScriptEnabled = p.getBoolean("enable_javascript",
239                javaScriptEnabled);
240        pluginsEnabled = p.getBoolean("enable_plugins",
241                pluginsEnabled);
242        pluginsPath = p.getString("plugins_path", pluginsPath);
243        databasePath = p.getString("database_path", databasePath);
244        databaseEnabled = p.getBoolean("enable_database", databaseEnabled);
245        appCacheEnabled = p.getBoolean("enable_appcache",
246            appCacheEnabled);
247        appCachePath = p.getString("appcache_path", appCachePath);
248        javaScriptCanOpenWindowsAutomatically = !p.getBoolean(
249            "block_popup_windows",
250            !javaScriptCanOpenWindowsAutomatically);
251        showSecurityWarnings = p.getBoolean("show_security_warnings",
252                showSecurityWarnings);
253        rememberPasswords = p.getBoolean("remember_passwords",
254                rememberPasswords);
255        saveFormData = p.getBoolean("save_formdata",
256                saveFormData);
257        boolean accept_cookies = p.getBoolean("accept_cookies",
258                CookieManager.getInstance().acceptCookie());
259        CookieManager.getInstance().setAcceptCookie(accept_cookies);
260        openInBackground = p.getBoolean("open_in_background", openInBackground);
261        loginInitialized = p.getBoolean("login_initialized", loginInitialized);
262        textSize = WebSettings.TextSize.valueOf(
263                p.getString(PREF_TEXT_SIZE, textSize.name()));
264        autoFitPage = p.getBoolean("autofit_pages", autoFitPage);
265        boolean landscapeOnlyTemp =
266                p.getBoolean("landscape_only", landscapeOnly);
267        if (landscapeOnlyTemp != landscapeOnly) {
268            landscapeOnly = landscapeOnlyTemp;
269            mTabControl.getBrowserActivity().setRequestedOrientation(
270                    landscapeOnly ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
271                    : ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
272        }
273        useWideViewPort = true; // use wide view port for either setting
274        if (autoFitPage) {
275            layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS;
276        } else {
277            layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL;
278        }
279        defaultTextEncodingName =
280                p.getString(PREF_DEFAULT_TEXT_ENCODING,
281                        defaultTextEncodingName);
282
283        showDebugSettings =
284                p.getBoolean(PREF_DEBUG_SETTINGS, showDebugSettings);
285        // Debug menu items have precidence if the menu is visible
286        if (showDebugSettings) {
287            boolean small_screen = p.getBoolean("small_screen",
288                    layoutAlgorithm ==
289                    WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
290            if (small_screen) {
291                layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN;
292            } else {
293                boolean normal_layout = p.getBoolean("normal_layout",
294                        layoutAlgorithm == WebSettings.LayoutAlgorithm.NORMAL);
295                if (normal_layout) {
296                    layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL;
297                } else {
298                    layoutAlgorithm =
299                            WebSettings.LayoutAlgorithm.NARROW_COLUMNS;
300                }
301            }
302            useWideViewPort = p.getBoolean("wide_viewport", useWideViewPort);
303            tracing = p.getBoolean("enable_tracing", tracing);
304            lightTouch = p.getBoolean("enable_light_touch", lightTouch);
305            navDump = p.getBoolean("enable_nav_dump", navDump);
306            doFlick = p.getBoolean("enable_flick", doFlick);
307            userAgent = Integer.parseInt(p.getString("user_agent", "0"));
308            mTabControl.getBrowserActivity().setBaseSearchUrl(
309                    p.getString("search_url", ""));
310        }
311        update();
312    }
313
314    public String getPluginsPath() {
315        return pluginsPath;
316    }
317
318    public String getHomePage() {
319        return homeUrl;
320    }
321
322    public void setHomePage(Context context, String url) {
323        Editor ed = PreferenceManager.
324                getDefaultSharedPreferences(context).edit();
325        ed.putString(PREF_HOMEPAGE, url);
326        ed.commit();
327        homeUrl = url;
328    }
329
330    public boolean isLoginInitialized() {
331        return loginInitialized;
332    }
333
334    public void setLoginInitialized(Context context) {
335        loginInitialized = true;
336        Editor ed = PreferenceManager.
337                getDefaultSharedPreferences(context).edit();
338        ed.putBoolean("login_initialized", loginInitialized);
339        ed.commit();
340    }
341
342    public WebSettings.TextSize getTextSize() {
343        return textSize;
344    }
345
346    public boolean openInBackground() {
347        return openInBackground;
348    }
349
350    public boolean showSecurityWarnings() {
351        return showSecurityWarnings;
352    }
353
354    public boolean isTracing() {
355        return tracing;
356    }
357
358    public boolean isLightTouch() {
359        return lightTouch;
360    }
361
362    public boolean isNavDump() {
363        return navDump;
364    }
365
366    public boolean doFlick() {
367        return doFlick;
368    }
369
370    public boolean showDebugSettings() {
371        return showDebugSettings;
372    }
373
374    public void toggleDebugSettings() {
375        showDebugSettings = !showDebugSettings;
376        navDump = showDebugSettings;
377        update();
378    }
379
380    /**
381     * Add a WebSettings object to the list of observers that will be updated
382     * when update() is called.
383     *
384     * @param s A WebSettings object that is strictly tied to the life of a
385     *            WebView.
386     */
387    public Observer addObserver(WebSettings s) {
388        Observer old = mWebSettingsToObservers.get(s);
389        if (old != null) {
390            super.deleteObserver(old);
391        }
392        Observer o = new Observer(s);
393        mWebSettingsToObservers.put(s, o);
394        super.addObserver(o);
395        return o;
396    }
397
398    /**
399     * Delete the given WebSettings observer from the list of observers.
400     * @param s The WebSettings object to be deleted.
401     */
402    public void deleteObserver(WebSettings s) {
403        Observer o = mWebSettingsToObservers.get(s);
404        if (o != null) {
405            mWebSettingsToObservers.remove(s);
406            super.deleteObserver(o);
407        }
408    }
409
410    /*
411     * Package level method for obtaining a single app instance of the
412     * BrowserSettings.
413     */
414    /*package*/ static BrowserSettings getInstance() {
415        if (sSingleton == null ) {
416            sSingleton = new BrowserSettings();
417        }
418        return sSingleton;
419    }
420
421    /*
422     * Package level method for associating the BrowserSettings with TabControl
423     */
424    /* package */void setTabControl(TabControl tabControl) {
425        mTabControl = tabControl;
426    }
427
428    /*
429     * Update all the observers of the object.
430     */
431    /*package*/ void update() {
432        setChanged();
433        notifyObservers();
434    }
435
436    /*package*/ void clearCache(Context context) {
437        WebIconDatabase.getInstance().removeAllIcons();
438        if (mTabControl != null) {
439            WebView current = mTabControl.getCurrentWebView();
440            if (current != null) {
441                current.clearCache(true);
442            }
443        }
444    }
445
446    /*package*/ void clearCookies(Context context) {
447        CookieManager.getInstance().removeAllCookie();
448    }
449
450    /* package */void clearHistory(Context context) {
451        ContentResolver resolver = context.getContentResolver();
452        Browser.clearHistory(resolver);
453        Browser.clearSearches(resolver);
454    }
455
456    /* package */ void clearFormData(Context context) {
457        WebViewDatabase.getInstance(context).clearFormData();
458        if (mTabControl != null) {
459            mTabControl.getCurrentTopWebView().clearFormData();
460        }
461    }
462
463    /*package*/ void clearPasswords(Context context) {
464        WebViewDatabase db = WebViewDatabase.getInstance(context);
465        db.clearUsernamePassword();
466        db.clearHttpAuthUsernamePassword();
467    }
468
469    /*package*/ void resetDefaultPreferences(Context ctx) {
470        SharedPreferences p =
471            PreferenceManager.getDefaultSharedPreferences(ctx);
472        p.edit().clear().commit();
473        PreferenceManager.setDefaultValues(ctx, R.xml.browser_preferences,
474                true);
475        setHomePage(ctx, DEFAULT_HOME_URL +
476                Partner.getString(ctx.getContentResolver(), Partner.CLIENT_ID));
477    }
478
479    // Private constructor that does nothing.
480    private BrowserSettings() {
481    }
482}
483