WebSettings.java revision 28c742573ccaeb55c16bc02fb25fdd86b8d1f76a
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 android.webkit;
18
19import android.content.Context;
20import android.content.SharedPreferences;
21import android.content.pm.PackageManager;
22import android.os.Build;
23import android.os.Handler;
24import android.os.Message;
25import android.util.EventLog;
26import java.lang.SecurityException;
27import java.util.Locale;
28
29/**
30 * Manages settings state for a WebView. When a WebView is first created, it
31 * obtains a set of default settings. These default settings will be returned
32 * from any getter call. A WebSettings object obtained from
33 * WebView.getSettings() is tied to the life of the WebView. If a WebView has
34 * been destroyed, any method call on WebSettings will throw an
35 * IllegalStateException.
36 */
37public class WebSettings {
38    /**
39     * Enum for controlling the layout of html.
40     * NORMAL means no rendering changes.
41     * SINGLE_COLUMN moves all content into one column that is the width of the
42     * view.
43     * NARROW_COLUMNS makes all columns no wider than the screen if possible.
44     */
45    // XXX: These must match LayoutAlgorithm in Settings.h in WebCore.
46    public enum LayoutAlgorithm {
47        NORMAL,
48        SINGLE_COLUMN,
49        NARROW_COLUMNS
50    }
51
52    /**
53     * Enum for specifying the text size.
54     * SMALLEST is 50%
55     * SMALLER is 75%
56     * NORMAL is 100%
57     * LARGER is 150%
58     * LARGEST is 200%
59     */
60    public enum TextSize {
61        SMALLEST(50),
62        SMALLER(75),
63        NORMAL(100),
64        LARGER(150),
65        LARGEST(200);
66        TextSize(int size) {
67            value = size;
68        }
69        int value;
70    }
71
72    /**
73     * Enum for specifying the WebView's desired density.
74     * FAR makes 100% looking like in 240dpi
75     * MEDIUM makes 100% looking like in 160dpi
76     * CLOSE makes 100% looking like in 120dpi
77     */
78    public enum ZoomDensity {
79        FAR(150),      // 240dpi
80        MEDIUM(100),    // 160dpi
81        CLOSE(75);     // 120dpi
82        ZoomDensity(int size) {
83            value = size;
84        }
85        int value;
86    }
87
88    /**
89     * Default cache usage pattern  Use with {@link #setCacheMode}.
90     */
91    public static final int LOAD_DEFAULT = -1;
92
93    /**
94     * Normal cache usage pattern  Use with {@link #setCacheMode}.
95     */
96    public static final int LOAD_NORMAL = 0;
97
98    /**
99     * Use cache if content is there, even if expired (eg, history nav)
100     * If it is not in the cache, load from network.
101     * Use with {@link #setCacheMode}.
102     */
103    public static final int LOAD_CACHE_ELSE_NETWORK = 1;
104
105    /**
106     * Don't use the cache, load from network
107     * Use with {@link #setCacheMode}.
108     */
109    public static final int LOAD_NO_CACHE = 2;
110
111    /**
112     * Don't use the network, load from cache only.
113     * Use with {@link #setCacheMode}.
114     */
115    public static final int LOAD_CACHE_ONLY = 3;
116
117    public enum RenderPriority {
118        NORMAL,
119        HIGH,
120        LOW
121    }
122
123    /**
124     * The plugin state effects how plugins are treated on a page. ON means
125     * that any object will be loaded even if a plugin does not exist to handle
126     * the content. ON_DEMAND means that if there is a plugin installed that
127     * can handle the content, a placeholder is shown until the user clicks on
128     * the placeholder. Once clicked, the plugin will be enabled on the page.
129     * OFF means that all plugins will be turned off and any fallback content
130     * will be used.
131     */
132    public enum PluginState {
133        ON,
134        ON_DEMAND,
135        OFF
136    }
137
138    // WebView associated with this WebSettings.
139    private WebView mWebView;
140    // BrowserFrame used to access the native frame pointer.
141    private BrowserFrame mBrowserFrame;
142    // Flag to prevent multiple SYNC messages at one time.
143    private boolean mSyncPending = false;
144    // Custom handler that queues messages until the WebCore thread is active.
145    private final EventHandler mEventHandler;
146
147    // Private settings so we don't have to go into native code to
148    // retrieve the values. After setXXX, postSync() needs to be called.
149    //
150    // The default values need to match those in WebSettings.cpp
151    // If the defaults change, please also update the JavaDocs so developers
152    // know what they are.
153    private LayoutAlgorithm mLayoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS;
154    private Context         mContext;
155    private TextSize        mTextSize = TextSize.NORMAL;
156    private String          mStandardFontFamily = "sans-serif";
157    private String          mFixedFontFamily = "monospace";
158    private String          mSansSerifFontFamily = "sans-serif";
159    private String          mSerifFontFamily = "serif";
160    private String          mCursiveFontFamily = "cursive";
161    private String          mFantasyFontFamily = "fantasy";
162    private String          mDefaultTextEncoding;
163    private String          mUserAgent;
164    private boolean         mUseDefaultUserAgent;
165    private String          mAcceptLanguage;
166    private int             mMinimumFontSize = 8;
167    private int             mMinimumLogicalFontSize = 8;
168    private int             mDefaultFontSize = 16;
169    private int             mDefaultFixedFontSize = 13;
170    private int             mPageCacheCapacity = 0;
171    private boolean         mLoadsImagesAutomatically = true;
172    private boolean         mBlockNetworkImage = false;
173    private boolean         mBlockNetworkLoads;
174    private boolean         mJavaScriptEnabled = false;
175    private PluginState     mPluginState = PluginState.OFF;
176    private boolean         mJavaScriptCanOpenWindowsAutomatically = false;
177    private boolean         mUseDoubleTree = false;
178    private boolean         mUseWideViewport = false;
179    private boolean         mSupportMultipleWindows = false;
180    private boolean         mShrinksStandaloneImagesToFit = false;
181    // HTML5 API flags
182    private boolean         mAppCacheEnabled = false;
183    private boolean         mDatabaseEnabled = false;
184    private boolean         mDomStorageEnabled = false;
185    private boolean         mWorkersEnabled = false;  // only affects V8.
186    private boolean         mGeolocationEnabled = true;
187    // HTML5 configuration parameters
188    private long            mAppCacheMaxSize = Long.MAX_VALUE;
189    private String          mAppCachePath = "";
190    private String          mDatabasePath = "";
191    // The WebCore DatabaseTracker only allows the database path to be set
192    // once. Keep track of when the path has been set.
193    private boolean         mDatabasePathHasBeenSet = false;
194    private String          mGeolocationDatabasePath = "";
195    // Don't need to synchronize the get/set methods as they
196    // are basic types, also none of these values are used in
197    // native WebCore code.
198    private ZoomDensity     mDefaultZoom = ZoomDensity.MEDIUM;
199    private RenderPriority  mRenderPriority = RenderPriority.NORMAL;
200    private int             mOverrideCacheMode = LOAD_DEFAULT;
201    private boolean         mSaveFormData = true;
202    private boolean         mSavePassword = true;
203    private boolean         mLightTouchEnabled = false;
204    private boolean         mNeedInitialFocus = true;
205    private boolean         mNavDump = false;
206    private boolean         mSupportZoom = true;
207    private boolean         mBuiltInZoomControls = false;
208    private boolean         mAllowFileAccess = true;
209    private boolean         mLoadWithOverviewMode = false;
210    private boolean         mUseWebViewBackgroundOverscrollBackground = true;
211
212    // private WebSettings, not accessible by the host activity
213    static private int      mDoubleTapToastCount = 3;
214
215    private static final String PREF_FILE = "WebViewSettings";
216    private static final String DOUBLE_TAP_TOAST_COUNT = "double_tap_toast_count";
217
218    // Class to handle messages before WebCore is ready.
219    private class EventHandler {
220        // Message id for syncing
221        static final int SYNC = 0;
222        // Message id for setting priority
223        static final int PRIORITY = 1;
224        // Message id for writing double-tap toast count
225        static final int SET_DOUBLE_TAP_TOAST_COUNT = 2;
226        // Actual WebCore thread handler
227        private Handler mHandler;
228
229        private synchronized void createHandler() {
230            // as mRenderPriority can be set before thread is running, sync up
231            setRenderPriority();
232
233            // create a new handler
234            mHandler = new Handler() {
235                @Override
236                public void handleMessage(Message msg) {
237                    switch (msg.what) {
238                        case SYNC:
239                            synchronized (WebSettings.this) {
240                                if (mBrowserFrame.mNativeFrame != 0) {
241                                    nativeSync(mBrowserFrame.mNativeFrame);
242                                }
243                                mSyncPending = false;
244                            }
245                            break;
246
247                        case PRIORITY: {
248                            setRenderPriority();
249                            break;
250                        }
251
252                        case SET_DOUBLE_TAP_TOAST_COUNT: {
253                            SharedPreferences.Editor editor = mContext
254                                    .getSharedPreferences(PREF_FILE,
255                                            Context.MODE_PRIVATE).edit();
256                            editor.putInt(DOUBLE_TAP_TOAST_COUNT,
257                                    mDoubleTapToastCount);
258                            editor.commit();
259                            break;
260                        }
261                    }
262                }
263            };
264        }
265
266        private void setRenderPriority() {
267            synchronized (WebSettings.this) {
268                if (mRenderPriority == RenderPriority.NORMAL) {
269                    android.os.Process.setThreadPriority(
270                            android.os.Process.THREAD_PRIORITY_DEFAULT);
271                } else if (mRenderPriority == RenderPriority.HIGH) {
272                    android.os.Process.setThreadPriority(
273                            android.os.Process.THREAD_PRIORITY_FOREGROUND +
274                            android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE);
275                } else if (mRenderPriority == RenderPriority.LOW) {
276                    android.os.Process.setThreadPriority(
277                            android.os.Process.THREAD_PRIORITY_BACKGROUND);
278                }
279            }
280        }
281
282        /**
283         * Send a message to the private queue or handler.
284         */
285        private synchronized boolean sendMessage(Message msg) {
286            if (mHandler != null) {
287                mHandler.sendMessage(msg);
288                return true;
289            } else {
290                return false;
291            }
292        }
293    }
294
295    // User agent strings.
296    private static final String DESKTOP_USERAGENT =
297            "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_7; en-us)"
298            + " AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0"
299            + " Safari/530.17";
300    private static final String IPHONE_USERAGENT =
301            "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us)"
302            + " AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0"
303            + " Mobile/7A341 Safari/528.16";
304    private static Locale sLocale;
305    private static Object sLockForLocaleSettings;
306
307    /**
308     * Package constructor to prevent clients from creating a new settings
309     * instance.
310     */
311    WebSettings(Context context, WebView webview) {
312        mEventHandler = new EventHandler();
313        mContext = context;
314        mWebView = webview;
315        mDefaultTextEncoding = context.getString(com.android.internal.
316                                                 R.string.default_text_encoding);
317
318        if (sLockForLocaleSettings == null) {
319            sLockForLocaleSettings = new Object();
320            sLocale = Locale.getDefault();
321        }
322        mAcceptLanguage = getCurrentAcceptLanguage();
323        mUserAgent = getCurrentUserAgent();
324        mUseDefaultUserAgent = true;
325
326        mBlockNetworkLoads = mContext.checkPermission(
327                "android.permission.INTERNET", android.os.Process.myPid(),
328                android.os.Process.myUid()) != PackageManager.PERMISSION_GRANTED;
329    }
330
331    /**
332     * Looks at sLocale and returns current AcceptLanguage String.
333     * @return Current AcceptLanguage String.
334     */
335    private String getCurrentAcceptLanguage() {
336        Locale locale;
337        synchronized(sLockForLocaleSettings) {
338            locale = sLocale;
339        }
340        StringBuffer buffer = new StringBuffer();
341        final String language = locale.getLanguage();
342        if (language != null) {
343            buffer.append(language);
344            final String country = locale.getCountry();
345            if (country != null) {
346                buffer.append("-");
347                buffer.append(country);
348            }
349        }
350        if (!locale.equals(Locale.US)) {
351            buffer.append(", ");
352            java.util.Locale us = Locale.US;
353            if (us.getLanguage() != null) {
354                buffer.append(us.getLanguage());
355                final String country = us.getCountry();
356                if (country != null) {
357                    buffer.append("-");
358                    buffer.append(country);
359                }
360            }
361        }
362
363        return buffer.toString();
364    }
365
366    /**
367     * Looks at sLocale and mContext and returns current UserAgent String.
368     * @return Current UserAgent String.
369     */
370    private synchronized String getCurrentUserAgent() {
371        Locale locale;
372        synchronized(sLockForLocaleSettings) {
373            locale = sLocale;
374        }
375        StringBuffer buffer = new StringBuffer();
376        // Add version
377        final String version = Build.VERSION.RELEASE;
378        if (version.length() > 0) {
379            buffer.append(version);
380        } else {
381            // default to "1.0"
382            buffer.append("1.0");
383        }
384        buffer.append("; ");
385        final String language = locale.getLanguage();
386        if (language != null) {
387            buffer.append(language.toLowerCase());
388            final String country = locale.getCountry();
389            if (country != null) {
390                buffer.append("-");
391                buffer.append(country.toLowerCase());
392            }
393        } else {
394            // default to "en"
395            buffer.append("en");
396        }
397        // add the model for the release build
398        if ("REL".equals(Build.VERSION.CODENAME)) {
399            final String model = Build.MODEL;
400            if (model.length() > 0) {
401                buffer.append("; ");
402                buffer.append(model);
403            }
404        }
405        final String id = Build.ID;
406        if (id.length() > 0) {
407            buffer.append(" Build/");
408            buffer.append(id);
409        }
410        final String base = mContext.getResources().getText(
411                com.android.internal.R.string.web_user_agent).toString();
412        return String.format(base, buffer);
413    }
414
415    /**
416     * Enables dumping the pages navigation cache to a text file.
417     */
418    public void setNavDump(boolean enabled) {
419        mNavDump = enabled;
420    }
421
422    /**
423     * Returns true if dumping the navigation cache is enabled.
424     */
425    public boolean getNavDump() {
426        return mNavDump;
427    }
428
429    /**
430     * Set whether the WebView supports zoom
431     */
432    public void setSupportZoom(boolean support) {
433        mSupportZoom = support;
434        mWebView.updateMultiTouchSupport(mContext);
435    }
436
437    /**
438     * Returns whether the WebView supports zoom
439     */
440    public boolean supportZoom() {
441        return mSupportZoom;
442    }
443
444    /**
445     * Sets whether the zoom mechanism built into WebView is used.
446     */
447    public void setBuiltInZoomControls(boolean enabled) {
448        mBuiltInZoomControls = enabled;
449        mWebView.updateMultiTouchSupport(mContext);
450    }
451
452    /**
453     * Returns true if the zoom mechanism built into WebView is being used.
454     */
455    public boolean getBuiltInZoomControls() {
456        return mBuiltInZoomControls;
457    }
458
459    /**
460     * Enable or disable file access within WebView. File access is enabled by
461     * default.
462     */
463    public void setAllowFileAccess(boolean allow) {
464        mAllowFileAccess = allow;
465    }
466
467    /**
468     * Returns true if this WebView supports file access.
469     */
470    public boolean getAllowFileAccess() {
471        return mAllowFileAccess;
472    }
473
474    /**
475     * Set whether the WebView loads a page with overview mode.
476     */
477    public void setLoadWithOverviewMode(boolean overview) {
478        mLoadWithOverviewMode = overview;
479    }
480
481    /**
482     * Returns true if this WebView loads page with overview mode
483     */
484    public boolean getLoadWithOverviewMode() {
485        return mLoadWithOverviewMode;
486    }
487
488    /**
489     * Set whether the WebView uses its background for over scroll background.
490     * If true, it will use the WebView's background. If false, it will use an
491     * internal pattern. Default is true.
492     */
493    public void setUseWebViewBackgroundForOverscrollBackground(boolean view) {
494        mUseWebViewBackgroundOverscrollBackground = view;
495    }
496
497    /**
498     * Returns true if this WebView uses WebView's background instead of
499     * internal pattern for over scroll background.
500     */
501    public boolean getUseWebViewBackgroundForOverscrollBackground() {
502        return mUseWebViewBackgroundOverscrollBackground;
503    }
504
505    /**
506     * Store whether the WebView is saving form data.
507     */
508    public void setSaveFormData(boolean save) {
509        mSaveFormData = save;
510    }
511
512    /**
513     *  Return whether the WebView is saving form data.
514     */
515    public boolean getSaveFormData() {
516        return mSaveFormData;
517    }
518
519    /**
520     *  Store whether the WebView is saving password.
521     */
522    public void setSavePassword(boolean save) {
523        mSavePassword = save;
524    }
525
526    /**
527     *  Return whether the WebView is saving password.
528     */
529    public boolean getSavePassword() {
530        return mSavePassword;
531    }
532
533    /**
534     * Set the text size of the page.
535     * @param t A TextSize value for increasing or decreasing the text.
536     * @see WebSettings.TextSize
537     */
538    public synchronized void setTextSize(TextSize t) {
539        if (WebView.mLogEvent && mTextSize != t ) {
540            EventLog.writeEvent(EventLogTags.BROWSER_TEXT_SIZE_CHANGE,
541                    mTextSize.value, t.value);
542        }
543        mTextSize = t;
544        postSync();
545    }
546
547    /**
548     * Get the text size of the page.
549     * @return A TextSize enum value describing the text size.
550     * @see WebSettings.TextSize
551     */
552    public synchronized TextSize getTextSize() {
553        return mTextSize;
554    }
555
556    /**
557     * Set the default zoom density of the page. This should be called from UI
558     * thread.
559     * @param zoom A ZoomDensity value
560     * @see WebSettings.ZoomDensity
561     */
562    public void setDefaultZoom(ZoomDensity zoom) {
563        if (mDefaultZoom != zoom) {
564            mDefaultZoom = zoom;
565            mWebView.updateDefaultZoomDensity(zoom.value);
566        }
567    }
568
569    /**
570     * Get the default zoom density of the page. This should be called from UI
571     * thread.
572     * @return A ZoomDensity value
573     * @see WebSettings.ZoomDensity
574     */
575    public ZoomDensity getDefaultZoom() {
576        return mDefaultZoom;
577    }
578
579    /**
580     * Enables using light touches to make a selection and activate mouseovers.
581     */
582    public void setLightTouchEnabled(boolean enabled) {
583        mLightTouchEnabled = enabled;
584    }
585
586    /**
587     * Returns true if light touches are enabled.
588     */
589    public boolean getLightTouchEnabled() {
590        return mLightTouchEnabled;
591    }
592
593    /**
594     * @deprecated This setting controlled a rendering optimization
595     * that is no longer present. Setting it now has no effect.
596     */
597    @Deprecated
598    public synchronized void setUseDoubleTree(boolean use) {
599        return;
600    }
601
602    /**
603     * @deprecated This setting controlled a rendering optimization
604     * that is no longer present. Setting it now has no effect.
605     */
606    @Deprecated
607    public synchronized boolean getUseDoubleTree() {
608        return false;
609    }
610
611    /**
612     * Tell the WebView about user-agent string.
613     * @param ua 0 if the WebView should use an Android user-agent string,
614     *           1 if the WebView should use a desktop user-agent string.
615     *
616     * @deprecated Please use setUserAgentString instead.
617     */
618    @Deprecated
619    public synchronized void setUserAgent(int ua) {
620        String uaString = null;
621        if (ua == 1) {
622            if (DESKTOP_USERAGENT.equals(mUserAgent)) {
623                return; // do nothing
624            } else {
625                uaString = DESKTOP_USERAGENT;
626            }
627        } else if (ua == 2) {
628            if (IPHONE_USERAGENT.equals(mUserAgent)) {
629                return; // do nothing
630            } else {
631                uaString = IPHONE_USERAGENT;
632            }
633        } else if (ua != 0) {
634            return; // do nothing
635        }
636        setUserAgentString(uaString);
637    }
638
639    /**
640     * Return user-agent as int
641     * @return int  0 if the WebView is using an Android user-agent string.
642     *              1 if the WebView is using a desktop user-agent string.
643     *             -1 if the WebView is using user defined user-agent string.
644     *
645     * @deprecated Please use getUserAgentString instead.
646     */
647    @Deprecated
648    public synchronized int getUserAgent() {
649        if (DESKTOP_USERAGENT.equals(mUserAgent)) {
650            return 1;
651        } else if (IPHONE_USERAGENT.equals(mUserAgent)) {
652            return 2;
653        } else if (mUseDefaultUserAgent) {
654            return 0;
655        }
656        return -1;
657    }
658
659    /**
660     * Tell the WebView to use the wide viewport
661     */
662    public synchronized void setUseWideViewPort(boolean use) {
663        if (mUseWideViewport != use) {
664            mUseWideViewport = use;
665            postSync();
666        }
667    }
668
669    /**
670     * @return True if the WebView is using a wide viewport
671     */
672    public synchronized boolean getUseWideViewPort() {
673        return mUseWideViewport;
674    }
675
676    /**
677     * Tell the WebView whether it supports multiple windows. TRUE means
678     *         that {@link WebChromeClient#onCreateWindow(WebView, boolean,
679     *         boolean, Message)} is implemented by the host application.
680     */
681    public synchronized void setSupportMultipleWindows(boolean support) {
682        if (mSupportMultipleWindows != support) {
683            mSupportMultipleWindows = support;
684            postSync();
685        }
686    }
687
688    /**
689     * @return True if the WebView is supporting multiple windows. This means
690     *         that {@link WebChromeClient#onCreateWindow(WebView, boolean,
691     *         boolean, Message)} is implemented by the host application.
692     */
693    public synchronized boolean supportMultipleWindows() {
694        return mSupportMultipleWindows;
695    }
696
697    /**
698     * Set the underlying layout algorithm. This will cause a relayout of the
699     * WebView.
700     * @param l A LayoutAlgorithm enum specifying the algorithm to use.
701     * @see WebSettings.LayoutAlgorithm
702     */
703    public synchronized void setLayoutAlgorithm(LayoutAlgorithm l) {
704        // XXX: This will only be affective if libwebcore was built with
705        // ANDROID_LAYOUT defined.
706        if (mLayoutAlgorithm != l) {
707            mLayoutAlgorithm = l;
708            postSync();
709        }
710    }
711
712    /**
713     * Return the current layout algorithm. The default is NARROW_COLUMNS.
714     * @return LayoutAlgorithm enum value describing the layout algorithm
715     *         being used.
716     * @see WebSettings.LayoutAlgorithm
717     */
718    public synchronized LayoutAlgorithm getLayoutAlgorithm() {
719        return mLayoutAlgorithm;
720    }
721
722    /**
723     * Set the standard font family name.
724     * @param font A font family name.
725     */
726    public synchronized void setStandardFontFamily(String font) {
727        if (font != null && !font.equals(mStandardFontFamily)) {
728            mStandardFontFamily = font;
729            postSync();
730        }
731    }
732
733    /**
734     * Get the standard font family name. The default is "sans-serif".
735     * @return The standard font family name as a string.
736     */
737    public synchronized String getStandardFontFamily() {
738        return mStandardFontFamily;
739    }
740
741    /**
742     * Set the fixed font family name.
743     * @param font A font family name.
744     */
745    public synchronized void setFixedFontFamily(String font) {
746        if (font != null && !font.equals(mFixedFontFamily)) {
747            mFixedFontFamily = font;
748            postSync();
749        }
750    }
751
752    /**
753     * Get the fixed font family name. The default is "monospace".
754     * @return The fixed font family name as a string.
755     */
756    public synchronized String getFixedFontFamily() {
757        return mFixedFontFamily;
758    }
759
760    /**
761     * Set the sans-serif font family name.
762     * @param font A font family name.
763     */
764    public synchronized void setSansSerifFontFamily(String font) {
765        if (font != null && !font.equals(mSansSerifFontFamily)) {
766            mSansSerifFontFamily = font;
767            postSync();
768        }
769    }
770
771    /**
772     * Get the sans-serif font family name.
773     * @return The sans-serif font family name as a string.
774     */
775    public synchronized String getSansSerifFontFamily() {
776        return mSansSerifFontFamily;
777    }
778
779    /**
780     * Set the serif font family name. The default is "sans-serif".
781     * @param font A font family name.
782     */
783    public synchronized void setSerifFontFamily(String font) {
784        if (font != null && !font.equals(mSerifFontFamily)) {
785            mSerifFontFamily = font;
786            postSync();
787        }
788    }
789
790    /**
791     * Get the serif font family name. The default is "serif".
792     * @return The serif font family name as a string.
793     */
794    public synchronized String getSerifFontFamily() {
795        return mSerifFontFamily;
796    }
797
798    /**
799     * Set the cursive font family name.
800     * @param font A font family name.
801     */
802    public synchronized void setCursiveFontFamily(String font) {
803        if (font != null && !font.equals(mCursiveFontFamily)) {
804            mCursiveFontFamily = font;
805            postSync();
806        }
807    }
808
809    /**
810     * Get the cursive font family name. The default is "cursive".
811     * @return The cursive font family name as a string.
812     */
813    public synchronized String getCursiveFontFamily() {
814        return mCursiveFontFamily;
815    }
816
817    /**
818     * Set the fantasy font family name.
819     * @param font A font family name.
820     */
821    public synchronized void setFantasyFontFamily(String font) {
822        if (font != null && !font.equals(mFantasyFontFamily)) {
823            mFantasyFontFamily = font;
824            postSync();
825        }
826    }
827
828    /**
829     * Get the fantasy font family name. The default is "fantasy".
830     * @return The fantasy font family name as a string.
831     */
832    public synchronized String getFantasyFontFamily() {
833        return mFantasyFontFamily;
834    }
835
836    /**
837     * Set the minimum font size.
838     * @param size A non-negative integer between 1 and 72.
839     * Any number outside the specified range will be pinned.
840     */
841    public synchronized void setMinimumFontSize(int size) {
842        size = pin(size);
843        if (mMinimumFontSize != size) {
844            mMinimumFontSize = size;
845            postSync();
846        }
847    }
848
849    /**
850     * Get the minimum font size. The default is 8.
851     * @return A non-negative integer between 1 and 72.
852     */
853    public synchronized int getMinimumFontSize() {
854        return mMinimumFontSize;
855    }
856
857    /**
858     * Set the minimum logical font size.
859     * @param size A non-negative integer between 1 and 72.
860     * Any number outside the specified range will be pinned.
861     */
862    public synchronized void setMinimumLogicalFontSize(int size) {
863        size = pin(size);
864        if (mMinimumLogicalFontSize != size) {
865            mMinimumLogicalFontSize = size;
866            postSync();
867        }
868    }
869
870    /**
871     * Get the minimum logical font size. The default is 8.
872     * @return A non-negative integer between 1 and 72.
873     */
874    public synchronized int getMinimumLogicalFontSize() {
875        return mMinimumLogicalFontSize;
876    }
877
878    /**
879     * Set the default font size.
880     * @param size A non-negative integer between 1 and 72.
881     * Any number outside the specified range will be pinned.
882     */
883    public synchronized void setDefaultFontSize(int size) {
884        size = pin(size);
885        if (mDefaultFontSize != size) {
886            mDefaultFontSize = size;
887            postSync();
888        }
889    }
890
891    /**
892     * Get the default font size. The default is 16.
893     * @return A non-negative integer between 1 and 72.
894     */
895    public synchronized int getDefaultFontSize() {
896        return mDefaultFontSize;
897    }
898
899    /**
900     * Set the default fixed font size.
901     * @param size A non-negative integer between 1 and 72.
902     * Any number outside the specified range will be pinned.
903     */
904    public synchronized void setDefaultFixedFontSize(int size) {
905        size = pin(size);
906        if (mDefaultFixedFontSize != size) {
907            mDefaultFixedFontSize = size;
908            postSync();
909        }
910    }
911
912    /**
913     * Get the default fixed font size. The default is 16.
914     * @return A non-negative integer between 1 and 72.
915     */
916    public synchronized int getDefaultFixedFontSize() {
917        return mDefaultFixedFontSize;
918    }
919
920    /**
921     * Set the number of pages cached by the WebKit for the history navigation.
922     * @param size A non-negative integer between 0 (no cache) and 20 (max).
923     * @hide
924     */
925    public synchronized void setPageCacheCapacity(int size) {
926        if (size < 0) size = 0;
927        if (size > 20) size = 20;
928        if (mPageCacheCapacity != size) {
929            mPageCacheCapacity = size;
930            postSync();
931        }
932    }
933
934    /**
935     * Tell the WebView to load image resources automatically.
936     * @param flag True if the WebView should load images automatically.
937     */
938    public synchronized void setLoadsImagesAutomatically(boolean flag) {
939        if (mLoadsImagesAutomatically != flag) {
940            mLoadsImagesAutomatically = flag;
941            postSync();
942        }
943    }
944
945    /**
946     * Return true if the WebView will load image resources automatically.
947     * The default is true.
948     * @return True if the WebView loads images automatically.
949     */
950    public synchronized boolean getLoadsImagesAutomatically() {
951        return mLoadsImagesAutomatically;
952    }
953
954    /**
955     * Tell the WebView to block network images. This is only checked when
956     * {@link #getLoadsImagesAutomatically} is true. If you set the value to
957     * false, images will automatically be loaded. Use this api to reduce
958     * bandwidth only. Use {@link #setBlockNetworkLoads} if possible.
959     * @param flag True if the WebView should block network images.
960     * @see #setBlockNetworkLoads
961     */
962    public synchronized void setBlockNetworkImage(boolean flag) {
963        if (mBlockNetworkImage != flag) {
964            mBlockNetworkImage = flag;
965            postSync();
966        }
967    }
968
969    /**
970     * Return true if the WebView will block network images. The default is
971     * false.
972     * @return True if the WebView blocks network images.
973     */
974    public synchronized boolean getBlockNetworkImage() {
975        return mBlockNetworkImage;
976    }
977
978    /**
979     * Tell the WebView to block all network load requests. If you set the
980     * value to false, you must call {@link android.webkit.WebView#reload} to
981     * fetch remote resources. This flag supercedes the value passed to
982     * {@link #setBlockNetworkImage}.
983     * @param flag True if the WebView should block all network loads.
984     * @see android.webkit.WebView#reload
985     */
986    public synchronized void setBlockNetworkLoads(boolean flag) {
987        if (mBlockNetworkLoads != flag) {
988            mBlockNetworkLoads = flag;
989            verifyNetworkAccess();
990        }
991    }
992
993    /**
994     * Return true if the WebView will block all network loads. The default is
995     * false.
996     * @return True if the WebView blocks all network loads.
997     */
998    public synchronized boolean getBlockNetworkLoads() {
999        return mBlockNetworkLoads;
1000    }
1001
1002
1003    private void verifyNetworkAccess() {
1004        if (!mBlockNetworkLoads) {
1005            if (mContext.checkPermission("android.permission.INTERNET",
1006                    android.os.Process.myPid(), android.os.Process.myUid()) !=
1007                        PackageManager.PERMISSION_GRANTED) {
1008                throw new SecurityException
1009                        ("Permission denied - " +
1010                                "application missing INTERNET permission");
1011            }
1012        }
1013    }
1014
1015    /**
1016     * Tell the WebView to enable javascript execution.
1017     * @param flag True if the WebView should execute javascript.
1018     */
1019    public synchronized void setJavaScriptEnabled(boolean flag) {
1020        if (mJavaScriptEnabled != flag) {
1021            mJavaScriptEnabled = flag;
1022            postSync();
1023        }
1024    }
1025
1026    /**
1027     * Tell the WebView to enable plugins.
1028     * @param flag True if the WebView should load plugins.
1029     * @deprecated This method has been deprecated in favor of
1030     *             {@link #setPluginState}
1031     */
1032    @Deprecated
1033    public synchronized void setPluginsEnabled(boolean flag) {
1034        setPluginState(PluginState.ON);
1035    }
1036
1037    /**
1038     * Tell the WebView to enable, disable, or have plugins on demand. On
1039     * demand mode means that if a plugin exists that can handle the embedded
1040     * content, a placeholder icon will be shown instead of the plugin. When
1041     * the placeholder is clicked, the plugin will be enabled.
1042     * @param state One of the PluginState values.
1043     */
1044    public synchronized void setPluginState(PluginState state) {
1045        if (mPluginState != state) {
1046            mPluginState = state;
1047            postSync();
1048        }
1049    }
1050
1051    /**
1052     * Set a custom path to plugins used by the WebView. This method is
1053     * obsolete since each plugin is now loaded from its own package.
1054     * @param pluginsPath String path to the directory containing plugins.
1055     * @deprecated This method is no longer used as plugins are loaded from
1056     * their own APK via the system's package manager.
1057     */
1058    @Deprecated
1059    public synchronized void setPluginsPath(String pluginsPath) {
1060    }
1061
1062    /**
1063     * Set the path to where database storage API databases should be saved.
1064     * Nota that the WebCore Database Tracker only allows the path to be set once.
1065     * This will update WebCore when the Sync runs in the C++ side.
1066     * @param databasePath String path to the directory where databases should
1067     *     be saved. May be the empty string but should never be null.
1068     */
1069    public synchronized void setDatabasePath(String databasePath) {
1070        if (databasePath != null && !mDatabasePathHasBeenSet) {
1071            mDatabasePath = databasePath;
1072            mDatabasePathHasBeenSet = true;
1073            postSync();
1074        }
1075    }
1076
1077    /**
1078     * Set the path where the Geolocation permissions database should be saved.
1079     * This will update WebCore when the Sync runs in the C++ side.
1080     * @param databasePath String path to the directory where the Geolocation
1081     *     permissions database should be saved. May be the empty string but
1082     *     should never be null.
1083     */
1084    public synchronized void setGeolocationDatabasePath(String databasePath) {
1085        if (databasePath != null
1086                && !databasePath.equals(mGeolocationDatabasePath)) {
1087            mGeolocationDatabasePath = databasePath;
1088            postSync();
1089        }
1090    }
1091
1092    /**
1093     * Tell the WebView to enable Application Caches API.
1094     * @param flag True if the WebView should enable Application Caches.
1095     */
1096    public synchronized void setAppCacheEnabled(boolean flag) {
1097        if (mAppCacheEnabled != flag) {
1098            mAppCacheEnabled = flag;
1099            postSync();
1100        }
1101    }
1102
1103    /**
1104     * Set a custom path to the Application Caches files. The client
1105     * must ensure it exists before this call.
1106     * @param appCachePath String path to the directory containing Application
1107     * Caches files. The appCache path can be the empty string but should not
1108     * be null. Passing null for this parameter will result in a no-op.
1109     */
1110    public synchronized void setAppCachePath(String appCachePath) {
1111        if (appCachePath != null && !appCachePath.equals(mAppCachePath)) {
1112            mAppCachePath = appCachePath;
1113            postSync();
1114        }
1115    }
1116
1117    /**
1118     * Set the maximum size for the Application Caches content.
1119     * @param appCacheMaxSize the maximum size in bytes.
1120     */
1121    public synchronized void setAppCacheMaxSize(long appCacheMaxSize) {
1122        if (appCacheMaxSize != mAppCacheMaxSize) {
1123            mAppCacheMaxSize = appCacheMaxSize;
1124            postSync();
1125        }
1126    }
1127
1128    /**
1129     * Set whether the database storage API is enabled.
1130     * @param flag boolean True if the WebView should use the database storage
1131     *     API.
1132     */
1133    public synchronized void setDatabaseEnabled(boolean flag) {
1134       if (mDatabaseEnabled != flag) {
1135           mDatabaseEnabled = flag;
1136           postSync();
1137       }
1138    }
1139
1140    /**
1141     * Set whether the DOM storage API is enabled.
1142     * @param flag boolean True if the WebView should use the DOM storage
1143     *     API.
1144     */
1145    public synchronized void setDomStorageEnabled(boolean flag) {
1146       if (mDomStorageEnabled != flag) {
1147           mDomStorageEnabled = flag;
1148           postSync();
1149       }
1150    }
1151
1152    /**
1153     * Returns true if the DOM Storage API's are enabled.
1154     * @return True if the DOM Storage API's are enabled.
1155     */
1156    public synchronized boolean getDomStorageEnabled() {
1157       return mDomStorageEnabled;
1158    }
1159
1160    /**
1161     * Return the path to where database storage API databases are saved for
1162     * the current WebView.
1163     * @return the String path to the database storage API databases.
1164     */
1165    public synchronized String getDatabasePath() {
1166        return mDatabasePath;
1167    }
1168
1169    /**
1170     * Returns true if database storage API is enabled.
1171     * @return True if the database storage API is enabled.
1172     */
1173    public synchronized boolean getDatabaseEnabled() {
1174        return mDatabaseEnabled;
1175    }
1176
1177    /**
1178     * Tell the WebView to enable WebWorkers API.
1179     * @param flag True if the WebView should enable WebWorkers.
1180     * Note that this flag only affects V8. JSC does not have
1181     * an equivalent setting.
1182     * @hide pending api council approval
1183     */
1184    public synchronized void setWorkersEnabled(boolean flag) {
1185        if (mWorkersEnabled != flag) {
1186            mWorkersEnabled = flag;
1187            postSync();
1188        }
1189    }
1190
1191    /**
1192     * Sets whether Geolocation is enabled.
1193     * @param flag Whether Geolocation should be enabled.
1194     */
1195    public synchronized void setGeolocationEnabled(boolean flag) {
1196        if (mGeolocationEnabled != flag) {
1197            mGeolocationEnabled = flag;
1198            postSync();
1199        }
1200    }
1201
1202    /**
1203     * Return true if javascript is enabled. <b>Note: The default is false.</b>
1204     * @return True if javascript is enabled.
1205     */
1206    public synchronized boolean getJavaScriptEnabled() {
1207        return mJavaScriptEnabled;
1208    }
1209
1210    /**
1211     * Return true if plugins are enabled.
1212     * @return True if plugins are enabled.
1213     * @deprecated This method has been replaced by {@link #getPluginState}
1214     */
1215    @Deprecated
1216    public synchronized boolean getPluginsEnabled() {
1217        return mPluginState == PluginState.ON;
1218    }
1219
1220    /**
1221     * Return the current plugin state.
1222     * @return A value corresponding to the enum PluginState.
1223     */
1224    public synchronized PluginState getPluginState() {
1225        return mPluginState;
1226    }
1227
1228    /**
1229     * Returns the directory that contains the plugin libraries. This method is
1230     * obsolete since each plugin is now loaded from its own package.
1231     * @return An empty string.
1232     * @deprecated This method is no longer used as plugins are loaded from
1233     * their own APK via the system's package manager.
1234     */
1235    @Deprecated
1236    public synchronized String getPluginsPath() {
1237        return "";
1238    }
1239
1240    /**
1241     * Tell javascript to open windows automatically. This applies to the
1242     * javascript function window.open().
1243     * @param flag True if javascript can open windows automatically.
1244     */
1245    public synchronized void setJavaScriptCanOpenWindowsAutomatically(
1246            boolean flag) {
1247        if (mJavaScriptCanOpenWindowsAutomatically != flag) {
1248            mJavaScriptCanOpenWindowsAutomatically = flag;
1249            postSync();
1250        }
1251    }
1252
1253    /**
1254     * Return true if javascript can open windows automatically. The default
1255     * is false.
1256     * @return True if javascript can open windows automatically during
1257     *         window.open().
1258     */
1259    public synchronized boolean getJavaScriptCanOpenWindowsAutomatically() {
1260        return mJavaScriptCanOpenWindowsAutomatically;
1261    }
1262
1263    /**
1264     * Set the default text encoding name to use when decoding html pages.
1265     * @param encoding The text encoding name.
1266     */
1267    public synchronized void setDefaultTextEncodingName(String encoding) {
1268        if (encoding != null && !encoding.equals(mDefaultTextEncoding)) {
1269            mDefaultTextEncoding = encoding;
1270            postSync();
1271        }
1272    }
1273
1274    /**
1275     * Get the default text encoding name. The default is "Latin-1".
1276     * @return The default text encoding name as a string.
1277     */
1278    public synchronized String getDefaultTextEncodingName() {
1279        return mDefaultTextEncoding;
1280    }
1281
1282    /**
1283     * Set the WebView's user-agent string. If the string "ua" is null or empty,
1284     * it will use the system default user-agent string.
1285     */
1286    public synchronized void setUserAgentString(String ua) {
1287        if (ua == null || ua.length() == 0) {
1288            synchronized(sLockForLocaleSettings) {
1289                Locale currentLocale = Locale.getDefault();
1290                if (!sLocale.equals(currentLocale)) {
1291                    sLocale = currentLocale;
1292                    mAcceptLanguage = getCurrentAcceptLanguage();
1293                }
1294            }
1295            ua = getCurrentUserAgent();
1296            mUseDefaultUserAgent = true;
1297        } else  {
1298            mUseDefaultUserAgent = false;
1299        }
1300
1301        if (!ua.equals(mUserAgent)) {
1302            mUserAgent = ua;
1303            postSync();
1304        }
1305    }
1306
1307    /**
1308     * Return the WebView's user-agent string.
1309     */
1310    public synchronized String getUserAgentString() {
1311        if (DESKTOP_USERAGENT.equals(mUserAgent) ||
1312                IPHONE_USERAGENT.equals(mUserAgent) ||
1313                !mUseDefaultUserAgent) {
1314            return mUserAgent;
1315        }
1316
1317        boolean doPostSync = false;
1318        synchronized(sLockForLocaleSettings) {
1319            Locale currentLocale = Locale.getDefault();
1320            if (!sLocale.equals(currentLocale)) {
1321                sLocale = currentLocale;
1322                mUserAgent = getCurrentUserAgent();
1323                mAcceptLanguage = getCurrentAcceptLanguage();
1324                doPostSync = true;
1325            }
1326        }
1327        if (doPostSync) {
1328            postSync();
1329        }
1330        return mUserAgent;
1331    }
1332
1333    /* package api to grab the Accept Language string. */
1334    /*package*/ synchronized String getAcceptLanguage() {
1335        synchronized(sLockForLocaleSettings) {
1336            Locale currentLocale = Locale.getDefault();
1337            if (!sLocale.equals(currentLocale)) {
1338                sLocale = currentLocale;
1339                mAcceptLanguage = getCurrentAcceptLanguage();
1340            }
1341        }
1342        return mAcceptLanguage;
1343    }
1344
1345    /**
1346     * Tell the WebView whether it needs to set a node to have focus when
1347     * {@link WebView#requestFocus(int, android.graphics.Rect)} is called.
1348     *
1349     * @param flag
1350     */
1351    public void setNeedInitialFocus(boolean flag) {
1352        if (mNeedInitialFocus != flag) {
1353            mNeedInitialFocus = flag;
1354        }
1355    }
1356
1357    /* Package api to get the choice whether it needs to set initial focus. */
1358    /* package */ boolean getNeedInitialFocus() {
1359        return mNeedInitialFocus;
1360    }
1361
1362    /**
1363     * Set the priority of the Render thread. Unlike the other settings, this
1364     * one only needs to be called once per process. The default is NORMAL.
1365     *
1366     * @param priority RenderPriority, can be normal, high or low.
1367     */
1368    public synchronized void setRenderPriority(RenderPriority priority) {
1369        if (mRenderPriority != priority) {
1370            mRenderPriority = priority;
1371            mEventHandler.sendMessage(Message.obtain(null,
1372                    EventHandler.PRIORITY));
1373        }
1374    }
1375
1376    /**
1377     * Override the way the cache is used. The way the cache is used is based
1378     * on the navigation option. For a normal page load, the cache is checked
1379     * and content is re-validated as needed. When navigating back, content is
1380     * not revalidated, instead the content is just pulled from the cache.
1381     * This function allows the client to override this behavior.
1382     * @param mode One of the LOAD_ values.
1383     */
1384    public void setCacheMode(int mode) {
1385        if (mode != mOverrideCacheMode) {
1386            mOverrideCacheMode = mode;
1387        }
1388    }
1389
1390    /**
1391     * Return the current setting for overriding the cache mode. For a full
1392     * description, see the {@link #setCacheMode(int)} function.
1393     */
1394    public int getCacheMode() {
1395        return mOverrideCacheMode;
1396    }
1397
1398    /**
1399     * If set, webkit alternately shrinks and expands images viewed outside
1400     * of an HTML page to fit the screen. This conflicts with attempts by
1401     * the UI to zoom in and out of an image, so it is set false by default.
1402     * @param shrink Set true to let webkit shrink the standalone image to fit.
1403     * {@hide}
1404     */
1405    public void setShrinksStandaloneImagesToFit(boolean shrink) {
1406        if (mShrinksStandaloneImagesToFit != shrink) {
1407            mShrinksStandaloneImagesToFit = shrink;
1408            postSync();
1409        }
1410     }
1411
1412    int getDoubleTapToastCount() {
1413        return mDoubleTapToastCount;
1414    }
1415
1416    void setDoubleTapToastCount(int count) {
1417        if (mDoubleTapToastCount != count) {
1418            mDoubleTapToastCount = count;
1419            // write the settings in the non-UI thread
1420            mEventHandler.sendMessage(Message.obtain(null,
1421                    EventHandler.SET_DOUBLE_TAP_TOAST_COUNT));
1422        }
1423    }
1424
1425    /**
1426     * Transfer messages from the queue to the new WebCoreThread. Called from
1427     * WebCore thread.
1428     */
1429    /*package*/
1430    synchronized void syncSettingsAndCreateHandler(BrowserFrame frame) {
1431        mBrowserFrame = frame;
1432        if (DebugFlags.WEB_SETTINGS) {
1433            junit.framework.Assert.assertTrue(frame.mNativeFrame != 0);
1434        }
1435
1436        SharedPreferences sp = mContext.getSharedPreferences(PREF_FILE,
1437                Context.MODE_PRIVATE);
1438        if (mDoubleTapToastCount > 0) {
1439            mDoubleTapToastCount = sp.getInt(DOUBLE_TAP_TOAST_COUNT,
1440                    mDoubleTapToastCount);
1441        }
1442        nativeSync(frame.mNativeFrame);
1443        mSyncPending = false;
1444        mEventHandler.createHandler();
1445    }
1446
1447    /**
1448     * Let the Settings object know that our owner is being destroyed.
1449     */
1450    /*package*/
1451    synchronized void onDestroyed() {
1452    }
1453
1454    private int pin(int size) {
1455        // FIXME: 72 is just an arbitrary max text size value.
1456        if (size < 1) {
1457            return 1;
1458        } else if (size > 72) {
1459            return 72;
1460        }
1461        return size;
1462    }
1463
1464    /* Post a SYNC message to handle syncing the native settings. */
1465    private synchronized void postSync() {
1466        // Only post if a sync is not pending
1467        if (!mSyncPending) {
1468            mSyncPending = mEventHandler.sendMessage(
1469                    Message.obtain(null, EventHandler.SYNC));
1470        }
1471    }
1472
1473    // Synchronize the native and java settings.
1474    private native void nativeSync(int nativeFrame);
1475}
1476