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