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