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