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