WebSettingsClassic.java revision 4635dc23dc14ad6d67be711c463ca60d850bac2d
1/*
2 * Copyright (C) 2012 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.provider.Settings;
26import android.provider.Settings.SettingNotFoundException;
27import android.util.EventLog;
28
29import java.util.Locale;
30
31/**
32 * WebSettings implementation for the WebViewClassic implementation of WebView.
33 * @hide
34 */
35public class WebSettingsClassic extends WebSettings {
36    // TODO: Keep this up to date
37    private static final String PREVIOUS_VERSION = "4.1.1";
38
39    // WebView associated with this WebSettings.
40    private WebViewClassic mWebView;
41    // BrowserFrame used to access the native frame pointer.
42    private BrowserFrame mBrowserFrame;
43    // Flag to prevent multiple SYNC messages at one time.
44    private boolean mSyncPending = false;
45    // Custom handler that queues messages until the WebCore thread is active.
46    private final EventHandler mEventHandler;
47
48    // Private settings so we don't have to go into native code to
49    // retrieve the values. After setXXX, postSync() needs to be called.
50    //
51    // The default values need to match those in WebSettings.cpp
52    // If the defaults change, please also update the JavaDocs so developers
53    // know what they are.
54    private LayoutAlgorithm mLayoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS;
55    private Context         mContext;
56    private int             mTextSize = 100;
57    private String          mStandardFontFamily = "sans-serif";
58    private String          mFixedFontFamily = "monospace";
59    private String          mSansSerifFontFamily = "sans-serif";
60    private String          mSerifFontFamily = "serif";
61    private String          mCursiveFontFamily = "cursive";
62    private String          mFantasyFontFamily = "fantasy";
63    private String          mDefaultTextEncoding;
64    private String          mUserAgent;
65    private boolean         mUseDefaultUserAgent;
66    private String          mAcceptLanguage;
67    private int             mMinimumFontSize = 8;
68    private int             mMinimumLogicalFontSize = 8;
69    private int             mDefaultFontSize = 16;
70    private int             mDefaultFixedFontSize = 13;
71    private int             mPageCacheCapacity = 0;
72    private boolean         mLoadsImagesAutomatically = true;
73    private boolean         mBlockNetworkImage = false;
74    private boolean         mBlockNetworkLoads;
75    private boolean         mJavaScriptEnabled = false;
76    private boolean         mAllowUniversalAccessFromFileURLs = false;
77    private boolean         mAllowFileAccessFromFileURLs = false;
78    private boolean         mHardwareAccelSkia = false;
79    private boolean         mShowVisualIndicator = false;
80    private PluginState     mPluginState = PluginState.OFF;
81    private boolean         mJavaScriptCanOpenWindowsAutomatically = false;
82    private boolean         mUseDoubleTree = false;
83    private boolean         mUseWideViewport = false;
84    private boolean         mSupportMultipleWindows = false;
85    private boolean         mShrinksStandaloneImagesToFit = false;
86    private long            mMaximumDecodedImageSize = 0; // 0 means default
87    private boolean         mPrivateBrowsingEnabled = false;
88    private boolean         mSyntheticLinksEnabled = true;
89    // HTML5 API flags
90    private boolean         mAppCacheEnabled = false;
91    private boolean         mDatabaseEnabled = false;
92    private boolean         mDomStorageEnabled = false;
93    private boolean         mWorkersEnabled = false;  // only affects V8.
94    private boolean         mGeolocationEnabled = true;
95    private boolean         mXSSAuditorEnabled = false;
96    private boolean         mLinkPrefetchEnabled = false;
97    // HTML5 configuration parameters
98    private long            mAppCacheMaxSize = Long.MAX_VALUE;
99    private String          mAppCachePath = null;
100    private String          mDatabasePath = "";
101    // The WebCore DatabaseTracker only allows the database path to be set
102    // once. Keep track of when the path has been set.
103    private boolean         mDatabasePathHasBeenSet = false;
104    private String          mGeolocationDatabasePath = "";
105    // Don't need to synchronize the get/set methods as they
106    // are basic types, also none of these values are used in
107    // native WebCore code.
108    private ZoomDensity     mDefaultZoom = ZoomDensity.MEDIUM;
109    private RenderPriority  mRenderPriority = RenderPriority.NORMAL;
110    private int             mOverrideCacheMode = LOAD_DEFAULT;
111    private int             mDoubleTapZoom = 100;
112    private boolean         mSaveFormData = true;
113    private boolean         mAutoFillEnabled = false;
114    private boolean         mSavePassword = true;
115    private boolean         mLightTouchEnabled = false;
116    private boolean         mNeedInitialFocus = true;
117    private boolean         mNavDump = false;
118    private boolean         mSupportZoom = true;
119    private boolean         mBuiltInZoomControls = false;
120    private boolean         mDisplayZoomControls = true;
121    private boolean         mAllowFileAccess = true;
122    private boolean         mAllowContentAccess = true;
123    private boolean         mLoadWithOverviewMode = false;
124    private boolean         mEnableSmoothTransition = false;
125    private boolean         mForceUserScalable = false;
126    private boolean         mPasswordEchoEnabled = true;
127
128    // AutoFill Profile data
129    public static class AutoFillProfile {
130        private int mUniqueId;
131        private String mFullName;
132        private String mEmailAddress;
133        private String mCompanyName;
134        private String mAddressLine1;
135        private String mAddressLine2;
136        private String mCity;
137        private String mState;
138        private String mZipCode;
139        private String mCountry;
140        private String mPhoneNumber;
141
142        public AutoFillProfile(int uniqueId, String fullName, String email,
143                String companyName, String addressLine1, String addressLine2,
144                String city, String state, String zipCode, String country,
145                String phoneNumber) {
146            mUniqueId = uniqueId;
147            mFullName = fullName;
148            mEmailAddress = email;
149            mCompanyName = companyName;
150            mAddressLine1 = addressLine1;
151            mAddressLine2 = addressLine2;
152            mCity = city;
153            mState = state;
154            mZipCode = zipCode;
155            mCountry = country;
156            mPhoneNumber = phoneNumber;
157        }
158
159        public int getUniqueId() { return mUniqueId; }
160        public String getFullName() { return mFullName; }
161        public String getEmailAddress() { return mEmailAddress; }
162        public String getCompanyName() { return mCompanyName; }
163        public String getAddressLine1() { return mAddressLine1; }
164        public String getAddressLine2() { return mAddressLine2; }
165        public String getCity() { return mCity; }
166        public String getState() { return mState; }
167        public String getZipCode() { return mZipCode; }
168        public String getCountry() { return mCountry; }
169        public String getPhoneNumber() { return mPhoneNumber; }
170    }
171
172
173    private AutoFillProfile mAutoFillProfile;
174
175    private boolean         mUseWebViewBackgroundForOverscroll = true;
176
177    // private WebSettings, not accessible by the host activity
178    static private int      mDoubleTapToastCount = 3;
179
180    private static final String PREF_FILE = "WebViewSettings";
181    private static final String DOUBLE_TAP_TOAST_COUNT = "double_tap_toast_count";
182
183    // Class to handle messages before WebCore is ready.
184    private class EventHandler {
185        // Message id for syncing
186        static final int SYNC = 0;
187        // Message id for setting priority
188        static final int PRIORITY = 1;
189        // Message id for writing double-tap toast count
190        static final int SET_DOUBLE_TAP_TOAST_COUNT = 2;
191        // Actual WebCore thread handler
192        private Handler mHandler;
193
194        private synchronized void createHandler() {
195            // as mRenderPriority can be set before thread is running, sync up
196            setRenderPriority();
197
198            // create a new handler
199            mHandler = new Handler() {
200                @Override
201                public void handleMessage(Message msg) {
202                    switch (msg.what) {
203                        case SYNC:
204                            synchronized (WebSettingsClassic.this) {
205                                if (mBrowserFrame.mNativeFrame != 0) {
206                                    nativeSync(mBrowserFrame.mNativeFrame);
207                                }
208                                mSyncPending = false;
209                            }
210                            break;
211
212                        case PRIORITY: {
213                            setRenderPriority();
214                            break;
215                        }
216
217                        case SET_DOUBLE_TAP_TOAST_COUNT: {
218                            SharedPreferences.Editor editor = mContext
219                                    .getSharedPreferences(PREF_FILE,
220                                            Context.MODE_PRIVATE).edit();
221                            editor.putInt(DOUBLE_TAP_TOAST_COUNT,
222                                    mDoubleTapToastCount);
223                            editor.commit();
224                            break;
225                        }
226                    }
227                }
228            };
229        }
230
231        private void setRenderPriority() {
232            synchronized (WebSettingsClassic.this) {
233                if (mRenderPriority == RenderPriority.NORMAL) {
234                    android.os.Process.setThreadPriority(
235                            android.os.Process.THREAD_PRIORITY_DEFAULT);
236                } else if (mRenderPriority == RenderPriority.HIGH) {
237                    android.os.Process.setThreadPriority(
238                            android.os.Process.THREAD_PRIORITY_FOREGROUND +
239                            android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE);
240                } else if (mRenderPriority == RenderPriority.LOW) {
241                    android.os.Process.setThreadPriority(
242                            android.os.Process.THREAD_PRIORITY_BACKGROUND);
243                }
244            }
245        }
246
247        /**
248         * Send a message to the private queue or handler.
249         */
250        private synchronized boolean sendMessage(Message msg) {
251            if (mHandler != null) {
252                mHandler.sendMessage(msg);
253                return true;
254            } else {
255                return false;
256            }
257        }
258    }
259
260    // User agent strings.
261    private static final String DESKTOP_USERAGENT = "Mozilla/5.0 (X11; " +
262        "Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) " +
263        "Chrome/11.0.696.34 Safari/534.24";
264    private static final String IPHONE_USERAGENT =
265            "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us)"
266            + " AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0"
267            + " Mobile/7A341 Safari/528.16";
268    private static Locale sLocale;
269    private static Object sLockForLocaleSettings;
270
271    /**
272     * Package constructor to prevent clients from creating a new settings
273     * instance.
274     */
275    WebSettingsClassic(Context context, WebViewClassic webview) {
276        mEventHandler = new EventHandler();
277        mContext = context;
278        mWebView = webview;
279        mDefaultTextEncoding = context.getString(com.android.internal.
280                                                 R.string.default_text_encoding);
281
282        if (sLockForLocaleSettings == null) {
283            sLockForLocaleSettings = new Object();
284            sLocale = Locale.getDefault();
285        }
286        mAcceptLanguage = getCurrentAcceptLanguage();
287        mUserAgent = getCurrentUserAgent();
288        mUseDefaultUserAgent = true;
289
290        mBlockNetworkLoads = mContext.checkPermission(
291                "android.permission.INTERNET", android.os.Process.myPid(),
292                android.os.Process.myUid()) != PackageManager.PERMISSION_GRANTED;
293
294        // SDK specific settings. See issue 6212665
295        if (mContext.getApplicationInfo().targetSdkVersion <
296                Build.VERSION_CODES.JELLY_BEAN) {
297            mAllowUniversalAccessFromFileURLs = true;
298            mAllowFileAccessFromFileURLs = true;
299        }
300        try {
301            mPasswordEchoEnabled =
302                    Settings.System.getInt(context.getContentResolver(),
303                        Settings.System.TEXT_SHOW_PASSWORD) != 0;
304        } catch (SettingNotFoundException e) {
305            mPasswordEchoEnabled = true;
306        }
307    }
308
309    private static final String ACCEPT_LANG_FOR_US_LOCALE = "en-US";
310
311    /**
312     * Looks at sLocale and returns current AcceptLanguage String.
313     * @return Current AcceptLanguage String.
314     */
315    private String getCurrentAcceptLanguage() {
316        Locale locale;
317        synchronized(sLockForLocaleSettings) {
318            locale = sLocale;
319        }
320        StringBuilder buffer = new StringBuilder();
321        addLocaleToHttpAcceptLanguage(buffer, locale);
322
323        if (!Locale.US.equals(locale)) {
324            if (buffer.length() > 0) {
325                buffer.append(", ");
326            }
327            buffer.append(ACCEPT_LANG_FOR_US_LOCALE);
328        }
329
330        return buffer.toString();
331    }
332
333    /**
334     * Convert obsolete language codes, including Hebrew/Indonesian/Yiddish,
335     * to new standard.
336     */
337    private static String convertObsoleteLanguageCodeToNew(String langCode) {
338        if (langCode == null) {
339            return null;
340        }
341        if ("iw".equals(langCode)) {
342            // Hebrew
343            return "he";
344        } else if ("in".equals(langCode)) {
345            // Indonesian
346            return "id";
347        } else if ("ji".equals(langCode)) {
348            // Yiddish
349            return "yi";
350        }
351        return langCode;
352    }
353
354    private static void addLocaleToHttpAcceptLanguage(StringBuilder builder,
355                                                      Locale locale) {
356        String language = convertObsoleteLanguageCodeToNew(locale.getLanguage());
357        if (language != null) {
358            builder.append(language);
359            String country = locale.getCountry();
360            if (country != null) {
361                builder.append("-");
362                builder.append(country);
363            }
364        }
365    }
366
367    /**
368     * Looks at sLocale and mContext and returns current UserAgent String.
369     * @return Current UserAgent String.
370     */
371    private synchronized String getCurrentUserAgent() {
372        Locale locale;
373        synchronized(sLockForLocaleSettings) {
374            locale = sLocale;
375        }
376        StringBuffer buffer = new StringBuffer();
377        // Add version
378        final String version = Build.VERSION.RELEASE;
379        if (version.length() > 0) {
380            if (Character.isDigit(version.charAt(0))) {
381                // Release is a version, eg "3.1"
382                buffer.append(version);
383            } else {
384                // Release is a codename, eg "Honeycomb"
385                // In this case, use the previous release's version
386                buffer.append(PREVIOUS_VERSION);
387            }
388        } else {
389            // default to "1.0"
390            buffer.append("1.0");
391        }
392        buffer.append("; ");
393        final String language = locale.getLanguage();
394        if (language != null) {
395            buffer.append(convertObsoleteLanguageCodeToNew(language));
396            final String country = locale.getCountry();
397            if (country != null) {
398                buffer.append("-");
399                buffer.append(country.toLowerCase());
400            }
401        } else {
402            // default to "en"
403            buffer.append("en");
404        }
405        buffer.append(";");
406        // add the model for the release build
407        if ("REL".equals(Build.VERSION.CODENAME)) {
408            final String model = Build.MODEL;
409            if (model.length() > 0) {
410                buffer.append(" ");
411                buffer.append(model);
412            }
413        }
414        final String id = Build.ID;
415        if (id.length() > 0) {
416            buffer.append(" Build/");
417            buffer.append(id);
418        }
419        String mobile = mContext.getResources().getText(
420            com.android.internal.R.string.web_user_agent_target_content).toString();
421        final String base = mContext.getResources().getText(
422                com.android.internal.R.string.web_user_agent).toString();
423        return String.format(base, buffer, mobile);
424    }
425
426    /**
427     * @see android.webkit.WebSettings#setNavDump(boolean)
428     */
429    @Override
430    @Deprecated
431    public void setNavDump(boolean enabled) {
432        mNavDump = enabled;
433    }
434
435    /**
436     * @see android.webkit.WebSettings#getNavDump()
437     */
438    @Override
439    @Deprecated
440    public boolean getNavDump() {
441        return mNavDump;
442    }
443
444    /**
445     * @see android.webkit.WebSettings#setSupportZoom(boolean)
446     */
447    @Override
448    public void setSupportZoom(boolean support) {
449        mSupportZoom = support;
450        mWebView.updateMultiTouchSupport(mContext);
451    }
452
453    /**
454     * @see android.webkit.WebSettings#supportZoom()
455     */
456    @Override
457    public boolean supportZoom() {
458        return mSupportZoom;
459    }
460
461    /**
462     * @see android.webkit.WebSettings#setBuiltInZoomControls(boolean)
463     */
464    @Override
465    public void setBuiltInZoomControls(boolean enabled) {
466        mBuiltInZoomControls = enabled;
467        mWebView.updateMultiTouchSupport(mContext);
468    }
469
470    /**
471     * @see android.webkit.WebSettings#getBuiltInZoomControls()
472     */
473    @Override
474    public boolean getBuiltInZoomControls() {
475        return mBuiltInZoomControls;
476    }
477
478    /**
479     * @see android.webkit.WebSettings#setDisplayZoomControls(boolean)
480     */
481    @Override
482    public void setDisplayZoomControls(boolean enabled) {
483        mDisplayZoomControls = enabled;
484        mWebView.updateMultiTouchSupport(mContext);
485    }
486
487    /**
488     * @see android.webkit.WebSettings#getDisplayZoomControls()
489     */
490    @Override
491    public boolean getDisplayZoomControls() {
492        return mDisplayZoomControls;
493    }
494
495    /**
496     * @see android.webkit.WebSettings#setAllowFileAccess(boolean)
497     */
498    @Override
499    public void setAllowFileAccess(boolean allow) {
500        mAllowFileAccess = allow;
501    }
502
503    /**
504     * @see android.webkit.WebSettings#getAllowFileAccess()
505     */
506    @Override
507    public boolean getAllowFileAccess() {
508        return mAllowFileAccess;
509    }
510
511    /**
512     * @see android.webkit.WebSettings#setAllowContentAccess(boolean)
513     */
514    @Override
515    public void setAllowContentAccess(boolean allow) {
516        mAllowContentAccess = allow;
517    }
518
519    /**
520     * @see android.webkit.WebSettings#getAllowContentAccess()
521     */
522    @Override
523    public boolean getAllowContentAccess() {
524        return mAllowContentAccess;
525    }
526
527    /**
528     * @see android.webkit.WebSettings#setLoadWithOverviewMode(boolean)
529     */
530    @Override
531    public void setLoadWithOverviewMode(boolean overview) {
532        mLoadWithOverviewMode = overview;
533    }
534
535    /**
536     * @see android.webkit.WebSettings#getLoadWithOverviewMode()
537     */
538    @Override
539    public boolean getLoadWithOverviewMode() {
540        return mLoadWithOverviewMode;
541    }
542
543    /**
544     * @see android.webkit.WebSettings#setEnableSmoothTransition(boolean)
545     */
546    @Override
547    public void setEnableSmoothTransition(boolean enable) {
548        mEnableSmoothTransition = enable;
549    }
550
551    /**
552     * @see android.webkit.WebSettings#enableSmoothTransition()
553     */
554    @Override
555    public boolean enableSmoothTransition() {
556        return mEnableSmoothTransition;
557    }
558
559    /**
560     * @see android.webkit.WebSettings#setUseWebViewBackgroundForOverscrollBackground(boolean)
561     */
562    @Override
563    @Deprecated
564    public void setUseWebViewBackgroundForOverscrollBackground(boolean view) {
565        mUseWebViewBackgroundForOverscroll = view;
566    }
567
568    /**
569     * @see android.webkit.WebSettings#getUseWebViewBackgroundForOverscrollBackground()
570     */
571    @Override
572    @Deprecated
573    public boolean getUseWebViewBackgroundForOverscrollBackground() {
574        return mUseWebViewBackgroundForOverscroll;
575    }
576
577    /**
578     * @see android.webkit.WebSettings#setSaveFormData(boolean)
579     */
580    @Override
581    public void setSaveFormData(boolean save) {
582        mSaveFormData = save;
583    }
584
585    /**
586     * @see android.webkit.WebSettings#getSaveFormData()
587     */
588    @Override
589    public boolean getSaveFormData() {
590        return mSaveFormData && !mPrivateBrowsingEnabled;
591    }
592
593    /**
594     * @see android.webkit.WebSettings#setSavePassword(boolean)
595     */
596    @Override
597    public void setSavePassword(boolean save) {
598        mSavePassword = save;
599    }
600
601    /**
602     * @see android.webkit.WebSettings#getSavePassword()
603     */
604    @Override
605    public boolean getSavePassword() {
606        return mSavePassword;
607    }
608
609    /**
610     * @see android.webkit.WebSettings#setTextZoom(int)
611     */
612    @Override
613    public synchronized void setTextZoom(int textZoom) {
614        if (mTextSize != textZoom) {
615            if (WebViewClassic.mLogEvent) {
616                EventLog.writeEvent(EventLogTags.BROWSER_TEXT_SIZE_CHANGE,
617                        mTextSize, textZoom);
618            }
619            mTextSize = textZoom;
620            postSync();
621        }
622    }
623
624    /**
625     * @see android.webkit.WebSettings#getTextZoom()
626     */
627    @Override
628    public synchronized int getTextZoom() {
629        return mTextSize;
630    }
631
632    /**
633     * @see android.webkit.WebSettings#setTextSize(android.webkit.WebSettingsClassic.TextSize)
634     */
635    @Override
636    public synchronized void setTextSize(TextSize t) {
637        setTextZoom(t.value);
638    }
639
640    /**
641     * @see android.webkit.WebSettings#getTextSize()
642     */
643    @Override
644    public synchronized TextSize getTextSize() {
645        TextSize closestSize = null;
646        int smallestDelta = Integer.MAX_VALUE;
647        for (TextSize size : TextSize.values()) {
648            int delta = Math.abs(mTextSize - size.value);
649            if (delta == 0) {
650                return size;
651            }
652            if (delta < smallestDelta) {
653                smallestDelta = delta;
654                closestSize = size;
655            }
656        }
657        return closestSize != null ? closestSize : TextSize.NORMAL;
658    }
659
660    /**
661     * Set the double-tap zoom of the page in percent. Default is 100.
662     * @param doubleTapZoom A percent value for increasing or decreasing the double-tap zoom.
663     */
664    public void setDoubleTapZoom(int doubleTapZoom) {
665        if (mDoubleTapZoom != doubleTapZoom) {
666            mDoubleTapZoom = doubleTapZoom;
667            mWebView.updateDoubleTapZoom(doubleTapZoom);
668        }
669    }
670
671    /**
672     * Get the double-tap zoom of the page in percent.
673     * @return A percent value describing the double-tap zoom.
674     */
675    public int getDoubleTapZoom() {
676        return mDoubleTapZoom;
677    }
678
679    /**
680     * @see android.webkit.WebSettings#setDefaultZoom(android.webkit.WebSettingsClassic.ZoomDensity)
681     */
682    @Override
683    public void setDefaultZoom(ZoomDensity zoom) {
684        if (mDefaultZoom != zoom) {
685            mDefaultZoom = zoom;
686            mWebView.adjustDefaultZoomDensity(zoom.value);
687        }
688    }
689
690    /**
691     * @see android.webkit.WebSettings#getDefaultZoom()
692     */
693    @Override
694    public ZoomDensity getDefaultZoom() {
695        return mDefaultZoom;
696    }
697
698    /**
699     * @see android.webkit.WebSettings#setLightTouchEnabled(boolean)
700     */
701    @Override
702    public void setLightTouchEnabled(boolean enabled) {
703        mLightTouchEnabled = enabled;
704    }
705
706    /**
707     * @see android.webkit.WebSettings#getLightTouchEnabled()
708     */
709    @Override
710    public boolean getLightTouchEnabled() {
711        return mLightTouchEnabled;
712    }
713
714    /**
715     * @see android.webkit.WebSettings#setUseDoubleTree(boolean)
716     */
717    @Override
718    @Deprecated
719    public synchronized void setUseDoubleTree(boolean use) {
720        return;
721    }
722
723    /**
724     * @see android.webkit.WebSettings#getUseDoubleTree()
725     */
726    @Override
727    @Deprecated
728    public synchronized boolean getUseDoubleTree() {
729        return false;
730    }
731
732    /**
733     * @see android.webkit.WebSettings#setUserAgent(int)
734     */
735    @Override
736    @Deprecated
737    public synchronized void setUserAgent(int ua) {
738        String uaString = null;
739        if (ua == 1) {
740            if (DESKTOP_USERAGENT.equals(mUserAgent)) {
741                return; // do nothing
742            } else {
743                uaString = DESKTOP_USERAGENT;
744            }
745        } else if (ua == 2) {
746            if (IPHONE_USERAGENT.equals(mUserAgent)) {
747                return; // do nothing
748            } else {
749                uaString = IPHONE_USERAGENT;
750            }
751        } else if (ua != 0) {
752            return; // do nothing
753        }
754        setUserAgentString(uaString);
755    }
756
757    /**
758     * @see android.webkit.WebSettings#getUserAgent()
759     */
760    @Override
761    @Deprecated
762    public synchronized int getUserAgent() {
763        if (DESKTOP_USERAGENT.equals(mUserAgent)) {
764            return 1;
765        } else if (IPHONE_USERAGENT.equals(mUserAgent)) {
766            return 2;
767        } else if (mUseDefaultUserAgent) {
768            return 0;
769        }
770        return -1;
771    }
772
773    /**
774     * @see android.webkit.WebSettings#setUseWideViewPort(boolean)
775     */
776    @Override
777    public synchronized void setUseWideViewPort(boolean use) {
778        if (mUseWideViewport != use) {
779            mUseWideViewport = use;
780            postSync();
781        }
782    }
783
784    /**
785     * @see android.webkit.WebSettings#getUseWideViewPort()
786     */
787    @Override
788    public synchronized boolean getUseWideViewPort() {
789        return mUseWideViewport;
790    }
791
792    /**
793     * @see android.webkit.WebSettings#setSupportMultipleWindows(boolean)
794     */
795    @Override
796    public synchronized void setSupportMultipleWindows(boolean support) {
797        if (mSupportMultipleWindows != support) {
798            mSupportMultipleWindows = support;
799            postSync();
800        }
801    }
802
803    /**
804     * @see android.webkit.WebSettings#supportMultipleWindows()
805     */
806    @Override
807    public synchronized boolean supportMultipleWindows() {
808        return mSupportMultipleWindows;
809    }
810
811    /**
812     * @see android.webkit.WebSettings#setLayoutAlgorithm(android.webkit.WebSettingsClassic.LayoutAlgorithm)
813     */
814    @Override
815    public synchronized void setLayoutAlgorithm(LayoutAlgorithm l) {
816        // XXX: This will only be affective if libwebcore was built with
817        // ANDROID_LAYOUT defined.
818        if (mLayoutAlgorithm != l) {
819            mLayoutAlgorithm = l;
820            postSync();
821        }
822    }
823
824    /**
825     * @see android.webkit.WebSettings#getLayoutAlgorithm()
826     */
827    @Override
828    public synchronized LayoutAlgorithm getLayoutAlgorithm() {
829        return mLayoutAlgorithm;
830    }
831
832    /**
833     * @see android.webkit.WebSettings#setStandardFontFamily(java.lang.String)
834     */
835    @Override
836    public synchronized void setStandardFontFamily(String font) {
837        if (font != null && !font.equals(mStandardFontFamily)) {
838            mStandardFontFamily = font;
839            postSync();
840        }
841    }
842
843    /**
844     * @see android.webkit.WebSettings#getStandardFontFamily()
845     */
846    @Override
847    public synchronized String getStandardFontFamily() {
848        return mStandardFontFamily;
849    }
850
851    /**
852     * @see android.webkit.WebSettings#setFixedFontFamily(java.lang.String)
853     */
854    @Override
855    public synchronized void setFixedFontFamily(String font) {
856        if (font != null && !font.equals(mFixedFontFamily)) {
857            mFixedFontFamily = font;
858            postSync();
859        }
860    }
861
862    /**
863     * @see android.webkit.WebSettings#getFixedFontFamily()
864     */
865    @Override
866    public synchronized String getFixedFontFamily() {
867        return mFixedFontFamily;
868    }
869
870    /**
871     * @see android.webkit.WebSettings#setSansSerifFontFamily(java.lang.String)
872     */
873    @Override
874    public synchronized void setSansSerifFontFamily(String font) {
875        if (font != null && !font.equals(mSansSerifFontFamily)) {
876            mSansSerifFontFamily = font;
877            postSync();
878        }
879    }
880
881    /**
882     * @see android.webkit.WebSettings#getSansSerifFontFamily()
883     */
884    @Override
885    public synchronized String getSansSerifFontFamily() {
886        return mSansSerifFontFamily;
887    }
888
889    /**
890     * @see android.webkit.WebSettings#setSerifFontFamily(java.lang.String)
891     */
892    @Override
893    public synchronized void setSerifFontFamily(String font) {
894        if (font != null && !font.equals(mSerifFontFamily)) {
895            mSerifFontFamily = font;
896            postSync();
897        }
898    }
899
900    /**
901     * @see android.webkit.WebSettings#getSerifFontFamily()
902     */
903    @Override
904    public synchronized String getSerifFontFamily() {
905        return mSerifFontFamily;
906    }
907
908    /**
909     * @see android.webkit.WebSettings#setCursiveFontFamily(java.lang.String)
910     */
911    @Override
912    public synchronized void setCursiveFontFamily(String font) {
913        if (font != null && !font.equals(mCursiveFontFamily)) {
914            mCursiveFontFamily = font;
915            postSync();
916        }
917    }
918
919    /**
920     * @see android.webkit.WebSettings#getCursiveFontFamily()
921     */
922    @Override
923    public synchronized String getCursiveFontFamily() {
924        return mCursiveFontFamily;
925    }
926
927    /**
928     * @see android.webkit.WebSettings#setFantasyFontFamily(java.lang.String)
929     */
930    @Override
931    public synchronized void setFantasyFontFamily(String font) {
932        if (font != null && !font.equals(mFantasyFontFamily)) {
933            mFantasyFontFamily = font;
934            postSync();
935        }
936    }
937
938    /**
939     * @see android.webkit.WebSettings#getFantasyFontFamily()
940     */
941    @Override
942    public synchronized String getFantasyFontFamily() {
943        return mFantasyFontFamily;
944    }
945
946    /**
947     * @see android.webkit.WebSettings#setMinimumFontSize(int)
948     */
949    @Override
950    public synchronized void setMinimumFontSize(int size) {
951        size = pin(size);
952        if (mMinimumFontSize != size) {
953            mMinimumFontSize = size;
954            postSync();
955        }
956    }
957
958    /**
959     * @see android.webkit.WebSettings#getMinimumFontSize()
960     */
961    @Override
962    public synchronized int getMinimumFontSize() {
963        return mMinimumFontSize;
964    }
965
966    /**
967     * @see android.webkit.WebSettings#setMinimumLogicalFontSize(int)
968     */
969    @Override
970    public synchronized void setMinimumLogicalFontSize(int size) {
971        size = pin(size);
972        if (mMinimumLogicalFontSize != size) {
973            mMinimumLogicalFontSize = size;
974            postSync();
975        }
976    }
977
978    /**
979     * @see android.webkit.WebSettings#getMinimumLogicalFontSize()
980     */
981    @Override
982    public synchronized int getMinimumLogicalFontSize() {
983        return mMinimumLogicalFontSize;
984    }
985
986    /**
987     * @see android.webkit.WebSettings#setDefaultFontSize(int)
988     */
989    @Override
990    public synchronized void setDefaultFontSize(int size) {
991        size = pin(size);
992        if (mDefaultFontSize != size) {
993            mDefaultFontSize = size;
994            postSync();
995        }
996    }
997
998    /**
999     * @see android.webkit.WebSettings#getDefaultFontSize()
1000     */
1001    @Override
1002    public synchronized int getDefaultFontSize() {
1003        return mDefaultFontSize;
1004    }
1005
1006    /**
1007     * @see android.webkit.WebSettings#setDefaultFixedFontSize(int)
1008     */
1009    @Override
1010    public synchronized void setDefaultFixedFontSize(int size) {
1011        size = pin(size);
1012        if (mDefaultFixedFontSize != size) {
1013            mDefaultFixedFontSize = size;
1014            postSync();
1015        }
1016    }
1017
1018    /**
1019     * @see android.webkit.WebSettings#getDefaultFixedFontSize()
1020     */
1021    @Override
1022    public synchronized int getDefaultFixedFontSize() {
1023        return mDefaultFixedFontSize;
1024    }
1025
1026    /**
1027     * Set the number of pages cached by the WebKit for the history navigation.
1028     * @param size A non-negative integer between 0 (no cache) and 20 (max).
1029     */
1030    public synchronized void setPageCacheCapacity(int size) {
1031        if (size < 0) size = 0;
1032        if (size > 20) size = 20;
1033        if (mPageCacheCapacity != size) {
1034            mPageCacheCapacity = size;
1035            postSync();
1036        }
1037    }
1038
1039    /**
1040     * @see android.webkit.WebSettings#setLoadsImagesAutomatically(boolean)
1041     */
1042    @Override
1043    public synchronized void setLoadsImagesAutomatically(boolean flag) {
1044        if (mLoadsImagesAutomatically != flag) {
1045            mLoadsImagesAutomatically = flag;
1046            postSync();
1047        }
1048    }
1049
1050    /**
1051     * @see android.webkit.WebSettings#getLoadsImagesAutomatically()
1052     */
1053    @Override
1054    public synchronized boolean getLoadsImagesAutomatically() {
1055        return mLoadsImagesAutomatically;
1056    }
1057
1058    /**
1059     * @see android.webkit.WebSettings#setBlockNetworkImage(boolean)
1060     */
1061    @Override
1062    public synchronized void setBlockNetworkImage(boolean flag) {
1063        if (mBlockNetworkImage != flag) {
1064            mBlockNetworkImage = flag;
1065            postSync();
1066        }
1067    }
1068
1069    /**
1070     * @see android.webkit.WebSettings#getBlockNetworkImage()
1071     */
1072    @Override
1073    public synchronized boolean getBlockNetworkImage() {
1074        return mBlockNetworkImage;
1075    }
1076
1077    /**
1078     * @see android.webkit.WebSettings#setBlockNetworkLoads(boolean)
1079     */
1080    @Override
1081    public synchronized void setBlockNetworkLoads(boolean flag) {
1082        if (mBlockNetworkLoads != flag) {
1083            mBlockNetworkLoads = flag;
1084            verifyNetworkAccess();
1085            postSync();
1086        }
1087    }
1088
1089    /**
1090     * @see android.webkit.WebSettings#getBlockNetworkLoads()
1091     */
1092    @Override
1093    public synchronized boolean getBlockNetworkLoads() {
1094        return mBlockNetworkLoads;
1095    }
1096
1097
1098    private void verifyNetworkAccess() {
1099        if (!mBlockNetworkLoads) {
1100            if (mContext.checkPermission("android.permission.INTERNET",
1101                    android.os.Process.myPid(), android.os.Process.myUid()) !=
1102                        PackageManager.PERMISSION_GRANTED) {
1103                throw new SecurityException
1104                        ("Permission denied - " +
1105                                "application missing INTERNET permission");
1106            }
1107        }
1108    }
1109
1110    /**
1111     * @see android.webkit.WebSettings#setJavaScriptEnabled(boolean)
1112     */
1113    @Override
1114    public synchronized void setJavaScriptEnabled(boolean flag) {
1115        if (mJavaScriptEnabled != flag) {
1116            mJavaScriptEnabled = flag;
1117            postSync();
1118        }
1119    }
1120
1121    /**
1122     * @see android.webkit.WebSettings#setAllowUniversalAccessFromFileURLs
1123     */
1124    @Override
1125    public synchronized void setAllowUniversalAccessFromFileURLs(boolean flag) {
1126        if (mAllowUniversalAccessFromFileURLs != flag) {
1127            mAllowUniversalAccessFromFileURLs = flag;
1128            postSync();
1129        }
1130    }
1131
1132    /**
1133     * @see android.webkit.WebSettings#setAllowFileAccessFromFileURLs
1134     */
1135    @Override
1136    public synchronized void setAllowFileAccessFromFileURLs(boolean flag) {
1137        if (mAllowFileAccessFromFileURLs != flag) {
1138            mAllowFileAccessFromFileURLs = flag;
1139            postSync();
1140        }
1141    }
1142
1143    /**
1144     * Tell the WebView to use Skia's hardware accelerated rendering path
1145     * @param flag True if the WebView should use Skia's hw-accel path
1146     */
1147    public synchronized void setHardwareAccelSkiaEnabled(boolean flag) {
1148        if (mHardwareAccelSkia != flag) {
1149            mHardwareAccelSkia = flag;
1150            postSync();
1151        }
1152    }
1153
1154    /**
1155     * @return True if the WebView is using hardware accelerated skia
1156     */
1157    public synchronized boolean getHardwareAccelSkiaEnabled() {
1158        return mHardwareAccelSkia;
1159    }
1160
1161    /**
1162     * Tell the WebView to show the visual indicator
1163     * @param flag True if the WebView should show the visual indicator
1164     */
1165    public synchronized void setShowVisualIndicator(boolean flag) {
1166        if (mShowVisualIndicator != flag) {
1167            mShowVisualIndicator = flag;
1168            postSync();
1169        }
1170    }
1171
1172    /**
1173     * @return True if the WebView is showing the visual indicator
1174     */
1175    public synchronized boolean getShowVisualIndicator() {
1176        return mShowVisualIndicator;
1177    }
1178
1179    /**
1180     * @see android.webkit.WebSettings#setPluginsEnabled(boolean)
1181     */
1182    @Override
1183    @Deprecated
1184    public synchronized void setPluginsEnabled(boolean flag) {
1185        setPluginState(flag ? PluginState.ON : PluginState.OFF);
1186    }
1187
1188    /**
1189     * @see android.webkit.WebSettings#setPluginState(android.webkit.WebSettingsClassic.PluginState)
1190     */
1191    @Override
1192    public synchronized void setPluginState(PluginState state) {
1193        if (mPluginState != state) {
1194            mPluginState = state;
1195            postSync();
1196        }
1197    }
1198
1199    /**
1200     * @see android.webkit.WebSettings#setPluginsPath(java.lang.String)
1201     */
1202    @Override
1203    @Deprecated
1204    public synchronized void setPluginsPath(String pluginsPath) {
1205    }
1206
1207    /**
1208     * @see android.webkit.WebSettings#setDatabasePath(java.lang.String)
1209     */
1210    @Override
1211    public synchronized void setDatabasePath(String databasePath) {
1212        if (databasePath != null && !mDatabasePathHasBeenSet) {
1213            mDatabasePath = databasePath;
1214            mDatabasePathHasBeenSet = true;
1215            postSync();
1216        }
1217    }
1218
1219    /**
1220     * @see android.webkit.WebSettings#setGeolocationDatabasePath(java.lang.String)
1221     */
1222    @Override
1223    public synchronized void setGeolocationDatabasePath(String databasePath) {
1224        if (databasePath != null
1225                && !databasePath.equals(mGeolocationDatabasePath)) {
1226            mGeolocationDatabasePath = databasePath;
1227            postSync();
1228        }
1229    }
1230
1231    /**
1232     * @see android.webkit.WebSettings#setAppCacheEnabled(boolean)
1233     */
1234    @Override
1235    public synchronized void setAppCacheEnabled(boolean flag) {
1236        if (mAppCacheEnabled != flag) {
1237            mAppCacheEnabled = flag;
1238            postSync();
1239        }
1240    }
1241
1242    /**
1243     * @see android.webkit.WebSettings#setAppCachePath(java.lang.String)
1244     */
1245    @Override
1246    public synchronized void setAppCachePath(String path) {
1247        // We test for a valid path and for repeated setting on the native
1248        // side, but we can avoid syncing in some simple cases.
1249        if (mAppCachePath == null && path != null && !path.isEmpty()) {
1250            mAppCachePath = path;
1251            postSync();
1252        }
1253    }
1254
1255    /**
1256     * @see android.webkit.WebSettings#setAppCacheMaxSize(long)
1257     */
1258    @Override
1259    public synchronized void setAppCacheMaxSize(long appCacheMaxSize) {
1260        if (appCacheMaxSize != mAppCacheMaxSize) {
1261            mAppCacheMaxSize = appCacheMaxSize;
1262            postSync();
1263        }
1264    }
1265
1266    /**
1267     * @see android.webkit.WebSettings#setDatabaseEnabled(boolean)
1268     */
1269    @Override
1270    public synchronized void setDatabaseEnabled(boolean flag) {
1271       if (mDatabaseEnabled != flag) {
1272           mDatabaseEnabled = flag;
1273           postSync();
1274       }
1275    }
1276
1277    /**
1278     * @see android.webkit.WebSettings#setDomStorageEnabled(boolean)
1279     */
1280    @Override
1281    public synchronized void setDomStorageEnabled(boolean flag) {
1282       if (mDomStorageEnabled != flag) {
1283           mDomStorageEnabled = flag;
1284           postSync();
1285       }
1286    }
1287
1288    /**
1289     * @see android.webkit.WebSettings#getDomStorageEnabled()
1290     */
1291    @Override
1292    public synchronized boolean getDomStorageEnabled() {
1293       return mDomStorageEnabled;
1294    }
1295
1296    /**
1297     * @see android.webkit.WebSettings#getDatabasePath()
1298     */
1299    @Override
1300    public synchronized String getDatabasePath() {
1301        return mDatabasePath;
1302    }
1303
1304    /**
1305     * @see android.webkit.WebSettings#getDatabaseEnabled()
1306     */
1307    @Override
1308    public synchronized boolean getDatabaseEnabled() {
1309        return mDatabaseEnabled;
1310    }
1311
1312    /**
1313     * Tell the WebView to enable WebWorkers API.
1314     * @param flag True if the WebView should enable WebWorkers.
1315     * Note that this flag only affects V8. JSC does not have
1316     * an equivalent setting.
1317     */
1318    public synchronized void setWorkersEnabled(boolean flag) {
1319        if (mWorkersEnabled != flag) {
1320            mWorkersEnabled = flag;
1321            postSync();
1322        }
1323    }
1324
1325    /**
1326     * @see android.webkit.WebSettings#setGeolocationEnabled(boolean)
1327     */
1328    @Override
1329    public synchronized void setGeolocationEnabled(boolean flag) {
1330        if (mGeolocationEnabled != flag) {
1331            mGeolocationEnabled = flag;
1332            postSync();
1333        }
1334    }
1335
1336    /**
1337     * Sets whether XSS Auditor is enabled.
1338     * Only used by LayoutTestController.
1339     * @param flag Whether XSS Auditor should be enabled.
1340     */
1341    public synchronized void setXSSAuditorEnabled(boolean flag) {
1342        if (mXSSAuditorEnabled != flag) {
1343            mXSSAuditorEnabled = flag;
1344            postSync();
1345        }
1346    }
1347
1348    /**
1349     * Enables/disables HTML5 link "prefetch" parameter.
1350     */
1351    public synchronized void setLinkPrefetchEnabled(boolean flag) {
1352        if (mLinkPrefetchEnabled != flag) {
1353            mLinkPrefetchEnabled = flag;
1354            postSync();
1355        }
1356    }
1357
1358    /**
1359     * @see android.webkit.WebSettings#getJavaScriptEnabled()
1360     */
1361    @Override
1362    public synchronized boolean getJavaScriptEnabled() {
1363        return mJavaScriptEnabled;
1364    }
1365
1366    /**
1367     * @see android.webkit.WebSettings#getAllowUniversalFileAccessFromFileURLs
1368     */
1369    @Override
1370    public synchronized boolean getAllowUniversalAccessFromFileURLs() {
1371        return mAllowUniversalAccessFromFileURLs;
1372    }
1373
1374    /**
1375     * @see android.webkit.WebSettings#getAllowFileAccessFromFileURLs
1376     */
1377    @Override
1378    public synchronized boolean getAllowFileAccessFromFileURLs() {
1379        return mAllowFileAccessFromFileURLs;
1380    }
1381
1382    /**
1383     * @see android.webkit.WebSettings#getPluginsEnabled()
1384     */
1385    @Override
1386    @Deprecated
1387    public synchronized boolean getPluginsEnabled() {
1388        return mPluginState == PluginState.ON;
1389    }
1390
1391    /**
1392     * @see android.webkit.WebSettings#getPluginState()
1393     */
1394    @Override
1395    public synchronized PluginState getPluginState() {
1396        return mPluginState;
1397    }
1398
1399    /**
1400     * @see android.webkit.WebSettings#getPluginsPath()
1401     */
1402    @Override
1403    @Deprecated
1404    public synchronized String getPluginsPath() {
1405        return "";
1406    }
1407
1408    /**
1409     * @see android.webkit.WebSettings#setJavaScriptCanOpenWindowsAutomatically(boolean)
1410     */
1411    @Override
1412    public synchronized void setJavaScriptCanOpenWindowsAutomatically(
1413            boolean flag) {
1414        if (mJavaScriptCanOpenWindowsAutomatically != flag) {
1415            mJavaScriptCanOpenWindowsAutomatically = flag;
1416            postSync();
1417        }
1418    }
1419
1420    /**
1421     * @see android.webkit.WebSettings#getJavaScriptCanOpenWindowsAutomatically()
1422     */
1423    @Override
1424    public synchronized boolean getJavaScriptCanOpenWindowsAutomatically() {
1425        return mJavaScriptCanOpenWindowsAutomatically;
1426    }
1427
1428    /**
1429     * @see android.webkit.WebSettings#setDefaultTextEncodingName(java.lang.String)
1430     */
1431    @Override
1432    public synchronized void setDefaultTextEncodingName(String encoding) {
1433        if (encoding != null && !encoding.equals(mDefaultTextEncoding)) {
1434            mDefaultTextEncoding = encoding;
1435            postSync();
1436        }
1437    }
1438
1439    /**
1440     * @see android.webkit.WebSettings#getDefaultTextEncodingName()
1441     */
1442    @Override
1443    public synchronized String getDefaultTextEncodingName() {
1444        return mDefaultTextEncoding;
1445    }
1446
1447    /**
1448     * @see android.webkit.WebSettings#setUserAgentString(java.lang.String)
1449     */
1450    @Override
1451    public synchronized void setUserAgentString(String ua) {
1452        if (ua == null || ua.length() == 0) {
1453            synchronized(sLockForLocaleSettings) {
1454                Locale currentLocale = Locale.getDefault();
1455                if (!sLocale.equals(currentLocale)) {
1456                    sLocale = currentLocale;
1457                    mAcceptLanguage = getCurrentAcceptLanguage();
1458                }
1459            }
1460            ua = getCurrentUserAgent();
1461            mUseDefaultUserAgent = true;
1462        } else  {
1463            mUseDefaultUserAgent = false;
1464        }
1465
1466        if (!ua.equals(mUserAgent)) {
1467            mUserAgent = ua;
1468            postSync();
1469        }
1470    }
1471
1472    /**
1473     * @see android.webkit.WebSettings#getUserAgentString()
1474     */
1475    @Override
1476    public synchronized String getUserAgentString() {
1477        if (DESKTOP_USERAGENT.equals(mUserAgent) ||
1478                IPHONE_USERAGENT.equals(mUserAgent) ||
1479                !mUseDefaultUserAgent) {
1480            return mUserAgent;
1481        }
1482
1483        boolean doPostSync = false;
1484        synchronized(sLockForLocaleSettings) {
1485            Locale currentLocale = Locale.getDefault();
1486            if (!sLocale.equals(currentLocale)) {
1487                sLocale = currentLocale;
1488                mUserAgent = getCurrentUserAgent();
1489                mAcceptLanguage = getCurrentAcceptLanguage();
1490                doPostSync = true;
1491            }
1492        }
1493        if (doPostSync) {
1494            postSync();
1495        }
1496        return mUserAgent;
1497    }
1498
1499    /* package api to grab the Accept Language string. */
1500    /*package*/ synchronized String getAcceptLanguage() {
1501        synchronized(sLockForLocaleSettings) {
1502            Locale currentLocale = Locale.getDefault();
1503            if (!sLocale.equals(currentLocale)) {
1504                sLocale = currentLocale;
1505                mAcceptLanguage = getCurrentAcceptLanguage();
1506            }
1507        }
1508        return mAcceptLanguage;
1509    }
1510
1511    /* package */ boolean isNarrowColumnLayout() {
1512        return getLayoutAlgorithm() == LayoutAlgorithm.NARROW_COLUMNS;
1513    }
1514
1515    /**
1516     * @see android.webkit.WebSettings#setNeedInitialFocus(boolean)
1517     */
1518    @Override
1519    public void setNeedInitialFocus(boolean flag) {
1520        if (mNeedInitialFocus != flag) {
1521            mNeedInitialFocus = flag;
1522        }
1523    }
1524
1525    /* Package api to get the choice whether it needs to set initial focus. */
1526    /* package */ boolean getNeedInitialFocus() {
1527        return mNeedInitialFocus;
1528    }
1529
1530    /**
1531     * @see android.webkit.WebSettings#setRenderPriority(android.webkit.WebSettingsClassic.RenderPriority)
1532     */
1533    @Override
1534    public synchronized void setRenderPriority(RenderPriority priority) {
1535        if (mRenderPriority != priority) {
1536            mRenderPriority = priority;
1537            mEventHandler.sendMessage(Message.obtain(null,
1538                    EventHandler.PRIORITY));
1539        }
1540    }
1541
1542    /**
1543     * @see android.webkit.WebSettings#setCacheMode(int)
1544     */
1545    @Override
1546    public void setCacheMode(int mode) {
1547        if (mode != mOverrideCacheMode) {
1548            mOverrideCacheMode = mode;
1549            postSync();
1550        }
1551    }
1552
1553    /**
1554     * @see android.webkit.WebSettings#getCacheMode()
1555     */
1556    @Override
1557    public int getCacheMode() {
1558        return mOverrideCacheMode;
1559    }
1560
1561    /**
1562     * If set, webkit alternately shrinks and expands images viewed outside
1563     * of an HTML page to fit the screen. This conflicts with attempts by
1564     * the UI to zoom in and out of an image, so it is set false by default.
1565     * @param shrink Set true to let webkit shrink the standalone image to fit.
1566     */
1567    public void setShrinksStandaloneImagesToFit(boolean shrink) {
1568        if (mShrinksStandaloneImagesToFit != shrink) {
1569            mShrinksStandaloneImagesToFit = shrink;
1570            postSync();
1571        }
1572     }
1573
1574    /**
1575     * Specify the maximum decoded image size. The default is
1576     * 2 megs for small memory devices and 8 megs for large memory devices.
1577     * @param size The maximum decoded size, or zero to set to the default.
1578     */
1579    public void setMaximumDecodedImageSize(long size) {
1580        if (mMaximumDecodedImageSize != size) {
1581            mMaximumDecodedImageSize = size;
1582            postSync();
1583        }
1584    }
1585
1586    /**
1587     * Returns whether to use fixed viewport.  Use fixed viewport
1588     * whenever wide viewport is on.
1589     */
1590    /* package */ boolean getUseFixedViewport() {
1591        return getUseWideViewPort();
1592    }
1593
1594    /**
1595     * Returns whether private browsing is enabled.
1596     */
1597    /* package */ boolean isPrivateBrowsingEnabled() {
1598        return mPrivateBrowsingEnabled;
1599    }
1600
1601    /**
1602     * Sets whether private browsing is enabled.
1603     * @param flag Whether private browsing should be enabled.
1604     */
1605    /* package */ synchronized void setPrivateBrowsingEnabled(boolean flag) {
1606        if (mPrivateBrowsingEnabled != flag) {
1607            mPrivateBrowsingEnabled = flag;
1608
1609            // AutoFill is dependant on private browsing being enabled so
1610            // reset it to take account of the new value of mPrivateBrowsingEnabled.
1611            setAutoFillEnabled(mAutoFillEnabled);
1612
1613            postSync();
1614        }
1615    }
1616
1617    /**
1618     * Returns whether the viewport metatag can disable zooming
1619     */
1620    public boolean forceUserScalable() {
1621        return mForceUserScalable;
1622    }
1623
1624    /**
1625     * Sets whether viewport metatag can disable zooming.
1626     * @param flag Whether or not to forceably enable user scalable.
1627     */
1628    public synchronized void setForceUserScalable(boolean flag) {
1629        mForceUserScalable = flag;
1630    }
1631
1632    synchronized void setSyntheticLinksEnabled(boolean flag) {
1633        if (mSyntheticLinksEnabled != flag) {
1634            mSyntheticLinksEnabled = flag;
1635            postSync();
1636        }
1637    }
1638
1639    public synchronized void setAutoFillEnabled(boolean enabled) {
1640        // AutoFill is always disabled in private browsing mode.
1641        boolean autoFillEnabled = enabled && !mPrivateBrowsingEnabled;
1642        if (mAutoFillEnabled != autoFillEnabled) {
1643            mAutoFillEnabled = autoFillEnabled;
1644            postSync();
1645        }
1646    }
1647
1648    public synchronized boolean getAutoFillEnabled() {
1649        return mAutoFillEnabled;
1650    }
1651
1652    public synchronized void setAutoFillProfile(AutoFillProfile profile) {
1653        if (mAutoFillProfile != profile) {
1654            mAutoFillProfile = profile;
1655            postSync();
1656        }
1657    }
1658
1659    public synchronized AutoFillProfile getAutoFillProfile() {
1660        return mAutoFillProfile;
1661    }
1662
1663    int getDoubleTapToastCount() {
1664        return mDoubleTapToastCount;
1665    }
1666
1667    void setDoubleTapToastCount(int count) {
1668        if (mDoubleTapToastCount != count) {
1669            mDoubleTapToastCount = count;
1670            // write the settings in the non-UI thread
1671            mEventHandler.sendMessage(Message.obtain(null,
1672                    EventHandler.SET_DOUBLE_TAP_TOAST_COUNT));
1673        }
1674    }
1675
1676    public void setProperty(String key, String value) {
1677        if (mWebView.nativeSetProperty(key, value)) {
1678            mWebView.invalidate();
1679        }
1680    }
1681
1682    public String getProperty(String key) {
1683        return mWebView.nativeGetProperty(key);
1684    }
1685
1686    /**
1687     * Transfer messages from the queue to the new WebCoreThread. Called from
1688     * WebCore thread.
1689     */
1690    /*package*/
1691    synchronized void syncSettingsAndCreateHandler(BrowserFrame frame) {
1692        mBrowserFrame = frame;
1693        if (DebugFlags.WEB_SETTINGS) {
1694            junit.framework.Assert.assertTrue(frame.mNativeFrame != 0);
1695        }
1696
1697        SharedPreferences sp = mContext.getSharedPreferences(PREF_FILE,
1698                Context.MODE_PRIVATE);
1699        if (mDoubleTapToastCount > 0) {
1700            mDoubleTapToastCount = sp.getInt(DOUBLE_TAP_TOAST_COUNT,
1701                    mDoubleTapToastCount);
1702        }
1703        nativeSync(frame.mNativeFrame);
1704        mSyncPending = false;
1705        mEventHandler.createHandler();
1706    }
1707
1708    /**
1709     * Let the Settings object know that our owner is being destroyed.
1710     */
1711    /*package*/
1712    synchronized void onDestroyed() {
1713    }
1714
1715    private int pin(int size) {
1716        // FIXME: 72 is just an arbitrary max text size value.
1717        if (size < 1) {
1718            return 1;
1719        } else if (size > 72) {
1720            return 72;
1721        }
1722        return size;
1723    }
1724
1725    /* Post a SYNC message to handle syncing the native settings. */
1726    private synchronized void postSync() {
1727        // Only post if a sync is not pending
1728        if (!mSyncPending) {
1729            mSyncPending = mEventHandler.sendMessage(
1730                    Message.obtain(null, EventHandler.SYNC));
1731        }
1732    }
1733
1734    // Synchronize the native and java settings.
1735    private native void nativeSync(int nativeFrame);
1736}
1737