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