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