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