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