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