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