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