Home | History | Annotate | Download | only in webkit
      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 
     17 package android.webkit;
     18 
     19 import android.content.Context;
     20 import android.content.SharedPreferences;
     21 import android.content.pm.PackageManager;
     22 import android.os.Build;
     23 import android.os.Handler;
     24 import android.os.Message;
     25 import android.provider.Settings;
     26 import android.provider.Settings.SettingNotFoundException;
     27 import android.util.EventLog;
     28 
     29 import java.util.Locale;
     30 
     31 /**
     32  * WebSettings implementation for the WebViewClassic implementation of WebView.
     33  * @hide
     34  */
     35 public 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             mTextSize = textZoom;
    651             postSync();
    652         }
    653     }
    654 
    655     /**
    656      * @see android.webkit.WebSettings#getTextZoom()
    657      */
    658     @Override
    659     public synchronized int getTextZoom() {
    660         return mTextSize;
    661     }
    662 
    663     /**
    664      * Set the double-tap zoom of the page in percent. Default is 100.
    665      * @param doubleTapZoom A percent value for increasing or decreasing the double-tap zoom.
    666      */
    667     public void setDoubleTapZoom(int doubleTapZoom) {
    668         if (mDoubleTapZoom != doubleTapZoom) {
    669             mDoubleTapZoom = doubleTapZoom;
    670             mWebView.updateDoubleTapZoom(doubleTapZoom);
    671         }
    672     }
    673 
    674     /**
    675      * Get the double-tap zoom of the page in percent.
    676      * @return A percent value describing the double-tap zoom.
    677      */
    678     public int getDoubleTapZoom() {
    679         return mDoubleTapZoom;
    680     }
    681 
    682     /**
    683      * @see android.webkit.WebSettings#setDefaultZoom(android.webkit.WebSettingsClassic.ZoomDensity)
    684      */
    685     @Override
    686     public void setDefaultZoom(ZoomDensity zoom) {
    687         if (mDefaultZoom != zoom) {
    688             mDefaultZoom = zoom;
    689             mWebView.adjustDefaultZoomDensity(zoom.value);
    690         }
    691     }
    692 
    693     /**
    694      * @see android.webkit.WebSettings#getDefaultZoom()
    695      */
    696     @Override
    697     public ZoomDensity getDefaultZoom() {
    698         return mDefaultZoom;
    699     }
    700 
    701     /**
    702      * @see android.webkit.WebSettings#setLightTouchEnabled(boolean)
    703      */
    704     @Override
    705     public void setLightTouchEnabled(boolean enabled) {
    706         mLightTouchEnabled = enabled;
    707     }
    708 
    709     /**
    710      * @see android.webkit.WebSettings#getLightTouchEnabled()
    711      */
    712     @Override
    713     public boolean getLightTouchEnabled() {
    714         return mLightTouchEnabled;
    715     }
    716 
    717     /**
    718      * @see android.webkit.WebSettings#setUseDoubleTree(boolean)
    719      */
    720     @Override
    721     @Deprecated
    722     public synchronized void setUseDoubleTree(boolean use) {
    723         return;
    724     }
    725 
    726     /**
    727      * @see android.webkit.WebSettings#getUseDoubleTree()
    728      */
    729     @Override
    730     @Deprecated
    731     public synchronized boolean getUseDoubleTree() {
    732         return false;
    733     }
    734 
    735     /**
    736      * @see android.webkit.WebSettings#setUserAgent(int)
    737      */
    738     @Override
    739     @Deprecated
    740     public synchronized void setUserAgent(int ua) {
    741         String uaString = null;
    742         if (ua == 1) {
    743             if (DESKTOP_USERAGENT.equals(mUserAgent)) {
    744                 return; // do nothing
    745             } else {
    746                 uaString = DESKTOP_USERAGENT;
    747             }
    748         } else if (ua == 2) {
    749             if (IPHONE_USERAGENT.equals(mUserAgent)) {
    750                 return; // do nothing
    751             } else {
    752                 uaString = IPHONE_USERAGENT;
    753             }
    754         } else if (ua != 0) {
    755             return; // do nothing
    756         }
    757         setUserAgentString(uaString);
    758     }
    759 
    760     /**
    761      * @see android.webkit.WebSettings#getUserAgent()
    762      */
    763     @Override
    764     @Deprecated
    765     public synchronized int getUserAgent() {
    766         if (DESKTOP_USERAGENT.equals(mUserAgent)) {
    767             return 1;
    768         } else if (IPHONE_USERAGENT.equals(mUserAgent)) {
    769             return 2;
    770         } else if (mUseDefaultUserAgent) {
    771             return 0;
    772         }
    773         return -1;
    774     }
    775 
    776     /**
    777      * @see android.webkit.WebSettings#setUseWideViewPort(boolean)
    778      */
    779     @Override
    780     public synchronized void setUseWideViewPort(boolean use) {
    781         if (mUseWideViewport != use) {
    782             mUseWideViewport = use;
    783             postSync();
    784         }
    785     }
    786 
    787     /**
    788      * @see android.webkit.WebSettings#getUseWideViewPort()
    789      */
    790     @Override
    791     public synchronized boolean getUseWideViewPort() {
    792         return mUseWideViewport;
    793     }
    794 
    795     /**
    796      * @see android.webkit.WebSettings#setSupportMultipleWindows(boolean)
    797      */
    798     @Override
    799     public synchronized void setSupportMultipleWindows(boolean support) {
    800         if (mSupportMultipleWindows != support) {
    801             mSupportMultipleWindows = support;
    802             postSync();
    803         }
    804     }
    805 
    806     /**
    807      * @see android.webkit.WebSettings#supportMultipleWindows()
    808      */
    809     @Override
    810     public synchronized boolean supportMultipleWindows() {
    811         return mSupportMultipleWindows;
    812     }
    813 
    814     /**
    815      * @see android.webkit.WebSettings#setLayoutAlgorithm(android.webkit.WebSettingsClassic.LayoutAlgorithm)
    816      */
    817     @Override
    818     public synchronized void setLayoutAlgorithm(LayoutAlgorithm l) {
    819         if (l == LayoutAlgorithm.TEXT_AUTOSIZING) {
    820             throw new IllegalArgumentException(
    821                     "WebViewClassic does not support TEXT_AUTOSIZING layout mode");
    822         }
    823         // XXX: This will only be affective if libwebcore was built with
    824         // ANDROID_LAYOUT defined.
    825         if (mLayoutAlgorithm != l) {
    826             mLayoutAlgorithm = l;
    827             postSync();
    828         }
    829     }
    830 
    831     /**
    832      * @see android.webkit.WebSettings#getLayoutAlgorithm()
    833      */
    834     @Override
    835     public synchronized LayoutAlgorithm getLayoutAlgorithm() {
    836         return mLayoutAlgorithm;
    837     }
    838 
    839     /**
    840      * @see android.webkit.WebSettings#setStandardFontFamily(java.lang.String)
    841      */
    842     @Override
    843     public synchronized void setStandardFontFamily(String font) {
    844         if (font != null && !font.equals(mStandardFontFamily)) {
    845             mStandardFontFamily = font;
    846             postSync();
    847         }
    848     }
    849 
    850     /**
    851      * @see android.webkit.WebSettings#getStandardFontFamily()
    852      */
    853     @Override
    854     public synchronized String getStandardFontFamily() {
    855         return mStandardFontFamily;
    856     }
    857 
    858     /**
    859      * @see android.webkit.WebSettings#setFixedFontFamily(java.lang.String)
    860      */
    861     @Override
    862     public synchronized void setFixedFontFamily(String font) {
    863         if (font != null && !font.equals(mFixedFontFamily)) {
    864             mFixedFontFamily = font;
    865             postSync();
    866         }
    867     }
    868 
    869     /**
    870      * @see android.webkit.WebSettings#getFixedFontFamily()
    871      */
    872     @Override
    873     public synchronized String getFixedFontFamily() {
    874         return mFixedFontFamily;
    875     }
    876 
    877     /**
    878      * @see android.webkit.WebSettings#setSansSerifFontFamily(java.lang.String)
    879      */
    880     @Override
    881     public synchronized void setSansSerifFontFamily(String font) {
    882         if (font != null && !font.equals(mSansSerifFontFamily)) {
    883             mSansSerifFontFamily = font;
    884             postSync();
    885         }
    886     }
    887 
    888     /**
    889      * @see android.webkit.WebSettings#getSansSerifFontFamily()
    890      */
    891     @Override
    892     public synchronized String getSansSerifFontFamily() {
    893         return mSansSerifFontFamily;
    894     }
    895 
    896     /**
    897      * @see android.webkit.WebSettings#setSerifFontFamily(java.lang.String)
    898      */
    899     @Override
    900     public synchronized void setSerifFontFamily(String font) {
    901         if (font != null && !font.equals(mSerifFontFamily)) {
    902             mSerifFontFamily = font;
    903             postSync();
    904         }
    905     }
    906 
    907     /**
    908      * @see android.webkit.WebSettings#getSerifFontFamily()
    909      */
    910     @Override
    911     public synchronized String getSerifFontFamily() {
    912         return mSerifFontFamily;
    913     }
    914 
    915     /**
    916      * @see android.webkit.WebSettings#setCursiveFontFamily(java.lang.String)
    917      */
    918     @Override
    919     public synchronized void setCursiveFontFamily(String font) {
    920         if (font != null && !font.equals(mCursiveFontFamily)) {
    921             mCursiveFontFamily = font;
    922             postSync();
    923         }
    924     }
    925 
    926     /**
    927      * @see android.webkit.WebSettings#getCursiveFontFamily()
    928      */
    929     @Override
    930     public synchronized String getCursiveFontFamily() {
    931         return mCursiveFontFamily;
    932     }
    933 
    934     /**
    935      * @see android.webkit.WebSettings#setFantasyFontFamily(java.lang.String)
    936      */
    937     @Override
    938     public synchronized void setFantasyFontFamily(String font) {
    939         if (font != null && !font.equals(mFantasyFontFamily)) {
    940             mFantasyFontFamily = font;
    941             postSync();
    942         }
    943     }
    944 
    945     /**
    946      * @see android.webkit.WebSettings#getFantasyFontFamily()
    947      */
    948     @Override
    949     public synchronized String getFantasyFontFamily() {
    950         return mFantasyFontFamily;
    951     }
    952 
    953     /**
    954      * @see android.webkit.WebSettings#setMinimumFontSize(int)
    955      */
    956     @Override
    957     public synchronized void setMinimumFontSize(int size) {
    958         size = pin(size);
    959         if (mMinimumFontSize != size) {
    960             mMinimumFontSize = size;
    961             postSync();
    962         }
    963     }
    964 
    965     /**
    966      * @see android.webkit.WebSettings#getMinimumFontSize()
    967      */
    968     @Override
    969     public synchronized int getMinimumFontSize() {
    970         return mMinimumFontSize;
    971     }
    972 
    973     /**
    974      * @see android.webkit.WebSettings#setMinimumLogicalFontSize(int)
    975      */
    976     @Override
    977     public synchronized void setMinimumLogicalFontSize(int size) {
    978         size = pin(size);
    979         if (mMinimumLogicalFontSize != size) {
    980             mMinimumLogicalFontSize = size;
    981             postSync();
    982         }
    983     }
    984 
    985     /**
    986      * @see android.webkit.WebSettings#getMinimumLogicalFontSize()
    987      */
    988     @Override
    989     public synchronized int getMinimumLogicalFontSize() {
    990         return mMinimumLogicalFontSize;
    991     }
    992 
    993     /**
    994      * @see android.webkit.WebSettings#setDefaultFontSize(int)
    995      */
    996     @Override
    997     public synchronized void setDefaultFontSize(int size) {
    998         size = pin(size);
    999         if (mDefaultFontSize != size) {
   1000             mDefaultFontSize = size;
   1001             postSync();
   1002         }
   1003     }
   1004 
   1005     /**
   1006      * @see android.webkit.WebSettings#getDefaultFontSize()
   1007      */
   1008     @Override
   1009     public synchronized int getDefaultFontSize() {
   1010         return mDefaultFontSize;
   1011     }
   1012 
   1013     /**
   1014      * @see android.webkit.WebSettings#setDefaultFixedFontSize(int)
   1015      */
   1016     @Override
   1017     public synchronized void setDefaultFixedFontSize(int size) {
   1018         size = pin(size);
   1019         if (mDefaultFixedFontSize != size) {
   1020             mDefaultFixedFontSize = size;
   1021             postSync();
   1022         }
   1023     }
   1024 
   1025     /**
   1026      * @see android.webkit.WebSettings#getDefaultFixedFontSize()
   1027      */
   1028     @Override
   1029     public synchronized int getDefaultFixedFontSize() {
   1030         return mDefaultFixedFontSize;
   1031     }
   1032 
   1033     /**
   1034      * Set the number of pages cached by the WebKit for the history navigation.
   1035      * @param size A non-negative integer between 0 (no cache) and 20 (max).
   1036      */
   1037     public synchronized void setPageCacheCapacity(int size) {
   1038         if (size < 0) size = 0;
   1039         if (size > 20) size = 20;
   1040         if (mPageCacheCapacity != size) {
   1041             mPageCacheCapacity = size;
   1042             postSync();
   1043         }
   1044     }
   1045 
   1046     /**
   1047      * @see android.webkit.WebSettings#setLoadsImagesAutomatically(boolean)
   1048      */
   1049     @Override
   1050     public synchronized void setLoadsImagesAutomatically(boolean flag) {
   1051         if (mLoadsImagesAutomatically != flag) {
   1052             mLoadsImagesAutomatically = flag;
   1053             postSync();
   1054         }
   1055     }
   1056 
   1057     /**
   1058      * @see android.webkit.WebSettings#getLoadsImagesAutomatically()
   1059      */
   1060     @Override
   1061     public synchronized boolean getLoadsImagesAutomatically() {
   1062         return mLoadsImagesAutomatically;
   1063     }
   1064 
   1065     /**
   1066      * @see android.webkit.WebSettings#setBlockNetworkImage(boolean)
   1067      */
   1068     @Override
   1069     public synchronized void setBlockNetworkImage(boolean flag) {
   1070         if (mBlockNetworkImage != flag) {
   1071             mBlockNetworkImage = flag;
   1072             postSync();
   1073         }
   1074     }
   1075 
   1076     /**
   1077      * @see android.webkit.WebSettings#getBlockNetworkImage()
   1078      */
   1079     @Override
   1080     public synchronized boolean getBlockNetworkImage() {
   1081         return mBlockNetworkImage;
   1082     }
   1083 
   1084     /**
   1085      * @see android.webkit.WebSettings#setBlockNetworkLoads(boolean)
   1086      */
   1087     @Override
   1088     public synchronized void setBlockNetworkLoads(boolean flag) {
   1089         if (mBlockNetworkLoads != flag) {
   1090             mBlockNetworkLoads = flag;
   1091             verifyNetworkAccess();
   1092             postSync();
   1093         }
   1094     }
   1095 
   1096     /**
   1097      * @see android.webkit.WebSettings#getBlockNetworkLoads()
   1098      */
   1099     @Override
   1100     public synchronized boolean getBlockNetworkLoads() {
   1101         return mBlockNetworkLoads;
   1102     }
   1103 
   1104 
   1105     private void verifyNetworkAccess() {
   1106         if (!mBlockNetworkLoads) {
   1107             if (mContext.checkPermission("android.permission.INTERNET",
   1108                     android.os.Process.myPid(), android.os.Process.myUid()) !=
   1109                         PackageManager.PERMISSION_GRANTED) {
   1110                 throw new SecurityException
   1111                         ("Permission denied - " +
   1112                                 "application missing INTERNET permission");
   1113             }
   1114         }
   1115     }
   1116 
   1117     /**
   1118      * @see android.webkit.WebSettings#setJavaScriptEnabled(boolean)
   1119      */
   1120     @Override
   1121     public synchronized void setJavaScriptEnabled(boolean flag) {
   1122         if (mJavaScriptEnabled != flag) {
   1123             mJavaScriptEnabled = flag;
   1124             postSync();
   1125             mWebView.updateJavaScriptEnabled(flag);
   1126         }
   1127     }
   1128 
   1129     /**
   1130      * @see android.webkit.WebSettings#setAllowUniversalAccessFromFileURLs
   1131      */
   1132     @Override
   1133     public synchronized void setAllowUniversalAccessFromFileURLs(boolean flag) {
   1134         if (mAllowUniversalAccessFromFileURLs != flag) {
   1135             mAllowUniversalAccessFromFileURLs = flag;
   1136             postSync();
   1137         }
   1138     }
   1139 
   1140     /**
   1141      * @see android.webkit.WebSettings#setAllowFileAccessFromFileURLs
   1142      */
   1143     @Override
   1144     public synchronized void setAllowFileAccessFromFileURLs(boolean flag) {
   1145         if (mAllowFileAccessFromFileURLs != flag) {
   1146             mAllowFileAccessFromFileURLs = flag;
   1147             postSync();
   1148         }
   1149     }
   1150 
   1151     /**
   1152      * Tell the WebView to use Skia's hardware accelerated rendering path
   1153      * @param flag True if the WebView should use Skia's hw-accel path
   1154      */
   1155     public synchronized void setHardwareAccelSkiaEnabled(boolean flag) {
   1156         if (mHardwareAccelSkia != flag) {
   1157             mHardwareAccelSkia = flag;
   1158             postSync();
   1159         }
   1160     }
   1161 
   1162     /**
   1163      * @return True if the WebView is using hardware accelerated skia
   1164      */
   1165     public synchronized boolean getHardwareAccelSkiaEnabled() {
   1166         return mHardwareAccelSkia;
   1167     }
   1168 
   1169     /**
   1170      * Tell the WebView to show the visual indicator
   1171      * @param flag True if the WebView should show the visual indicator
   1172      */
   1173     public synchronized void setShowVisualIndicator(boolean flag) {
   1174         if (mShowVisualIndicator != flag) {
   1175             mShowVisualIndicator = flag;
   1176             postSync();
   1177         }
   1178     }
   1179 
   1180     /**
   1181      * @return True if the WebView is showing the visual indicator
   1182      */
   1183     public synchronized boolean getShowVisualIndicator() {
   1184         return mShowVisualIndicator;
   1185     }
   1186 
   1187     /**
   1188      * @see android.webkit.WebSettings#setPluginsEnabled(boolean)
   1189      */
   1190     @Override
   1191     @Deprecated
   1192     public synchronized void setPluginsEnabled(boolean flag) {
   1193         setPluginState(flag ? PluginState.ON : PluginState.OFF);
   1194     }
   1195 
   1196     /**
   1197      * @see android.webkit.WebSettings#setPluginState(android.webkit.WebSettingsClassic.PluginState)
   1198      */
   1199     @Override
   1200     public synchronized void setPluginState(PluginState state) {
   1201         if (mPluginState != state) {
   1202             mPluginState = state;
   1203             postSync();
   1204         }
   1205     }
   1206 
   1207     /**
   1208      * @see android.webkit.WebSettings#setPluginsPath(java.lang.String)
   1209      */
   1210     @Override
   1211     @Deprecated
   1212     public synchronized void setPluginsPath(String pluginsPath) {
   1213     }
   1214 
   1215     /**
   1216      * @see android.webkit.WebSettings#setDatabasePath(java.lang.String)
   1217      */
   1218     @Override
   1219     public synchronized void setDatabasePath(String databasePath) {
   1220         if (databasePath != null && !mDatabasePathHasBeenSet) {
   1221             mDatabasePath = databasePath;
   1222             mDatabasePathHasBeenSet = true;
   1223             postSync();
   1224         }
   1225     }
   1226 
   1227     /**
   1228      * @see android.webkit.WebSettings#setGeolocationDatabasePath(java.lang.String)
   1229      */
   1230     @Override
   1231     public synchronized void setGeolocationDatabasePath(String databasePath) {
   1232         if (databasePath != null
   1233                 && !databasePath.equals(mGeolocationDatabasePath)) {
   1234             mGeolocationDatabasePath = databasePath;
   1235             postSync();
   1236         }
   1237     }
   1238 
   1239     /**
   1240      * @see android.webkit.WebSettings#setAppCacheEnabled(boolean)
   1241      */
   1242     @Override
   1243     public synchronized void setAppCacheEnabled(boolean flag) {
   1244         if (mAppCacheEnabled != flag) {
   1245             mAppCacheEnabled = flag;
   1246             postSync();
   1247         }
   1248     }
   1249 
   1250     /**
   1251      * @see android.webkit.WebSettings#setAppCachePath(java.lang.String)
   1252      */
   1253     @Override
   1254     public synchronized void setAppCachePath(String path) {
   1255         // We test for a valid path and for repeated setting on the native
   1256         // side, but we can avoid syncing in some simple cases.
   1257         if (mAppCachePath == null && path != null && !path.isEmpty()) {
   1258             mAppCachePath = path;
   1259             postSync();
   1260         }
   1261     }
   1262 
   1263     /**
   1264      * @see android.webkit.WebSettings#setAppCacheMaxSize(long)
   1265      */
   1266     @Override
   1267     public synchronized void setAppCacheMaxSize(long appCacheMaxSize) {
   1268         if (appCacheMaxSize != mAppCacheMaxSize) {
   1269             mAppCacheMaxSize = appCacheMaxSize;
   1270             postSync();
   1271         }
   1272     }
   1273 
   1274     /**
   1275      * @see android.webkit.WebSettings#setDatabaseEnabled(boolean)
   1276      */
   1277     @Override
   1278     public synchronized void setDatabaseEnabled(boolean flag) {
   1279        if (mDatabaseEnabled != flag) {
   1280            mDatabaseEnabled = flag;
   1281            postSync();
   1282        }
   1283     }
   1284 
   1285     /**
   1286      * @see android.webkit.WebSettings#setDomStorageEnabled(boolean)
   1287      */
   1288     @Override
   1289     public synchronized void setDomStorageEnabled(boolean flag) {
   1290        if (mDomStorageEnabled != flag) {
   1291            mDomStorageEnabled = flag;
   1292            postSync();
   1293        }
   1294     }
   1295 
   1296     /**
   1297      * @see android.webkit.WebSettings#getDomStorageEnabled()
   1298      */
   1299     @Override
   1300     public synchronized boolean getDomStorageEnabled() {
   1301        return mDomStorageEnabled;
   1302     }
   1303 
   1304     /**
   1305      * @see android.webkit.WebSettings#getDatabasePath()
   1306      */
   1307     @Override
   1308     public synchronized String getDatabasePath() {
   1309         return mDatabasePath;
   1310     }
   1311 
   1312     /**
   1313      * @see android.webkit.WebSettings#getDatabaseEnabled()
   1314      */
   1315     @Override
   1316     public synchronized boolean getDatabaseEnabled() {
   1317         return mDatabaseEnabled;
   1318     }
   1319 
   1320     /**
   1321      * Tell the WebView to enable WebWorkers API.
   1322      * @param flag True if the WebView should enable WebWorkers.
   1323      * Note that this flag only affects V8. JSC does not have
   1324      * an equivalent setting.
   1325      */
   1326     public synchronized void setWorkersEnabled(boolean flag) {
   1327         if (mWorkersEnabled != flag) {
   1328             mWorkersEnabled = flag;
   1329             postSync();
   1330         }
   1331     }
   1332 
   1333     /**
   1334      * @see android.webkit.WebSettings#setGeolocationEnabled(boolean)
   1335      */
   1336     @Override
   1337     public synchronized void setGeolocationEnabled(boolean flag) {
   1338         if (mGeolocationEnabled != flag) {
   1339             mGeolocationEnabled = flag;
   1340             postSync();
   1341         }
   1342     }
   1343 
   1344     /**
   1345      * Sets whether XSS Auditor is enabled.
   1346      * Only used by LayoutTestController.
   1347      * @param flag Whether XSS Auditor should be enabled.
   1348      */
   1349     public synchronized void setXSSAuditorEnabled(boolean flag) {
   1350         if (mXSSAuditorEnabled != flag) {
   1351             mXSSAuditorEnabled = flag;
   1352             postSync();
   1353         }
   1354     }
   1355 
   1356     /**
   1357      * Enables/disables HTML5 link "prefetch" parameter.
   1358      */
   1359     public synchronized void setLinkPrefetchEnabled(boolean flag) {
   1360         if (mLinkPrefetchEnabled != flag) {
   1361             mLinkPrefetchEnabled = flag;
   1362             postSync();
   1363         }
   1364     }
   1365 
   1366     /**
   1367      * @see android.webkit.WebSettings#getJavaScriptEnabled()
   1368      */
   1369     @Override
   1370     public synchronized boolean getJavaScriptEnabled() {
   1371         return mJavaScriptEnabled;
   1372     }
   1373 
   1374     /**
   1375      * @see android.webkit.WebSettings#getAllowUniversalFileAccessFromFileURLs
   1376      */
   1377     @Override
   1378     public synchronized boolean getAllowUniversalAccessFromFileURLs() {
   1379         return mAllowUniversalAccessFromFileURLs;
   1380     }
   1381 
   1382     /**
   1383      * @see android.webkit.WebSettings#getAllowFileAccessFromFileURLs
   1384      */
   1385     @Override
   1386     public synchronized boolean getAllowFileAccessFromFileURLs() {
   1387         return mAllowFileAccessFromFileURLs;
   1388     }
   1389 
   1390     /**
   1391      * @see android.webkit.WebSettings#getPluginsEnabled()
   1392      */
   1393     @Override
   1394     @Deprecated
   1395     public synchronized boolean getPluginsEnabled() {
   1396         return mPluginState == PluginState.ON;
   1397     }
   1398 
   1399     /**
   1400      * @see android.webkit.WebSettings#getPluginState()
   1401      */
   1402     @Override
   1403     public synchronized PluginState getPluginState() {
   1404         return mPluginState;
   1405     }
   1406 
   1407     /**
   1408      * @see android.webkit.WebSettings#getPluginsPath()
   1409      */
   1410     @Override
   1411     @Deprecated
   1412     public synchronized String getPluginsPath() {
   1413         return "";
   1414     }
   1415 
   1416     /**
   1417      * @see android.webkit.WebSettings#setJavaScriptCanOpenWindowsAutomatically(boolean)
   1418      */
   1419     @Override
   1420     public synchronized void setJavaScriptCanOpenWindowsAutomatically(
   1421             boolean flag) {
   1422         if (mJavaScriptCanOpenWindowsAutomatically != flag) {
   1423             mJavaScriptCanOpenWindowsAutomatically = flag;
   1424             postSync();
   1425         }
   1426     }
   1427 
   1428     /**
   1429      * @see android.webkit.WebSettings#getJavaScriptCanOpenWindowsAutomatically()
   1430      */
   1431     @Override
   1432     public synchronized boolean getJavaScriptCanOpenWindowsAutomatically() {
   1433         return mJavaScriptCanOpenWindowsAutomatically;
   1434     }
   1435 
   1436     /**
   1437      * @see android.webkit.WebSettings#setDefaultTextEncodingName(java.lang.String)
   1438      */
   1439     @Override
   1440     public synchronized void setDefaultTextEncodingName(String encoding) {
   1441         if (encoding != null && !encoding.equals(mDefaultTextEncoding)) {
   1442             mDefaultTextEncoding = encoding;
   1443             postSync();
   1444         }
   1445     }
   1446 
   1447     /**
   1448      * @see android.webkit.WebSettings#getDefaultTextEncodingName()
   1449      */
   1450     @Override
   1451     public synchronized String getDefaultTextEncodingName() {
   1452         return mDefaultTextEncoding;
   1453     }
   1454 
   1455     /**
   1456      * @see android.webkit.WebSettings#setUserAgentString(java.lang.String)
   1457      */
   1458     @Override
   1459     public synchronized void setUserAgentString(String ua) {
   1460         if (ua == null || ua.length() == 0) {
   1461             synchronized(sLockForLocaleSettings) {
   1462                 Locale currentLocale = Locale.getDefault();
   1463                 if (!sLocale.equals(currentLocale)) {
   1464                     sLocale = currentLocale;
   1465                     mAcceptLanguage = getCurrentAcceptLanguage();
   1466                 }
   1467             }
   1468             ua = getCurrentUserAgent();
   1469             mUseDefaultUserAgent = true;
   1470         } else  {
   1471             mUseDefaultUserAgent = false;
   1472         }
   1473 
   1474         if (!ua.equals(mUserAgent)) {
   1475             mUserAgent = ua;
   1476             postSync();
   1477         }
   1478     }
   1479 
   1480     /**
   1481      * @see android.webkit.WebSettings#getUserAgentString()
   1482      */
   1483     @Override
   1484     public synchronized String getUserAgentString() {
   1485         if (DESKTOP_USERAGENT.equals(mUserAgent) ||
   1486                 IPHONE_USERAGENT.equals(mUserAgent) ||
   1487                 !mUseDefaultUserAgent) {
   1488             return mUserAgent;
   1489         }
   1490 
   1491         boolean doPostSync = false;
   1492         synchronized(sLockForLocaleSettings) {
   1493             Locale currentLocale = Locale.getDefault();
   1494             if (!sLocale.equals(currentLocale)) {
   1495                 sLocale = currentLocale;
   1496                 mUserAgent = getCurrentUserAgent();
   1497                 mAcceptLanguage = getCurrentAcceptLanguage();
   1498                 doPostSync = true;
   1499             }
   1500         }
   1501         if (doPostSync) {
   1502             postSync();
   1503         }
   1504         return mUserAgent;
   1505     }
   1506 
   1507     /* package api to grab the Accept Language string. */
   1508     /*package*/ synchronized String getAcceptLanguage() {
   1509         synchronized(sLockForLocaleSettings) {
   1510             Locale currentLocale = Locale.getDefault();
   1511             if (!sLocale.equals(currentLocale)) {
   1512                 sLocale = currentLocale;
   1513                 mAcceptLanguage = getCurrentAcceptLanguage();
   1514             }
   1515         }
   1516         return mAcceptLanguage;
   1517     }
   1518 
   1519     /* package */ boolean isNarrowColumnLayout() {
   1520         return getLayoutAlgorithm() == LayoutAlgorithm.NARROW_COLUMNS;
   1521     }
   1522 
   1523     /**
   1524      * @see android.webkit.WebSettings#setNeedInitialFocus(boolean)
   1525      */
   1526     @Override
   1527     public void setNeedInitialFocus(boolean flag) {
   1528         if (mNeedInitialFocus != flag) {
   1529             mNeedInitialFocus = flag;
   1530         }
   1531     }
   1532 
   1533     /* Package api to get the choice whether it needs to set initial focus. */
   1534     /* package */ boolean getNeedInitialFocus() {
   1535         return mNeedInitialFocus;
   1536     }
   1537 
   1538     /**
   1539      * @see android.webkit.WebSettings#setRenderPriority(android.webkit.WebSettingsClassic.RenderPriority)
   1540      */
   1541     @Override
   1542     public synchronized void setRenderPriority(RenderPriority priority) {
   1543         if (mRenderPriority != priority) {
   1544             mRenderPriority = priority;
   1545             mEventHandler.sendMessage(Message.obtain(null,
   1546                     EventHandler.PRIORITY));
   1547         }
   1548     }
   1549 
   1550     /**
   1551      * @see android.webkit.WebSettings#setCacheMode(int)
   1552      */
   1553     @Override
   1554     public void setCacheMode(int mode) {
   1555         if (mode != mOverrideCacheMode) {
   1556             mOverrideCacheMode = mode;
   1557             postSync();
   1558         }
   1559     }
   1560 
   1561     /**
   1562      * @see android.webkit.WebSettings#getCacheMode()
   1563      */
   1564     @Override
   1565     public int getCacheMode() {
   1566         return mOverrideCacheMode;
   1567     }
   1568 
   1569     /**
   1570      * If set, webkit alternately shrinks and expands images viewed outside
   1571      * of an HTML page to fit the screen. This conflicts with attempts by
   1572      * the UI to zoom in and out of an image, so it is set false by default.
   1573      * @param shrink Set true to let webkit shrink the standalone image to fit.
   1574      */
   1575     public void setShrinksStandaloneImagesToFit(boolean shrink) {
   1576         if (mShrinksStandaloneImagesToFit != shrink) {
   1577             mShrinksStandaloneImagesToFit = shrink;
   1578             postSync();
   1579         }
   1580      }
   1581 
   1582     /**
   1583      * Specify the maximum decoded image size. The default is
   1584      * 2 megs for small memory devices and 8 megs for large memory devices.
   1585      * @param size The maximum decoded size, or zero to set to the default.
   1586      */
   1587     public void setMaximumDecodedImageSize(long size) {
   1588         if (mMaximumDecodedImageSize != size) {
   1589             mMaximumDecodedImageSize = size;
   1590             postSync();
   1591         }
   1592     }
   1593 
   1594     /**
   1595      * Returns whether to use fixed viewport.  Use fixed viewport
   1596      * whenever wide viewport is on.
   1597      */
   1598     /* package */ boolean getUseFixedViewport() {
   1599         return getUseWideViewPort();
   1600     }
   1601 
   1602     /**
   1603      * Returns whether private browsing is enabled.
   1604      */
   1605     /* package */ boolean isPrivateBrowsingEnabled() {
   1606         return mPrivateBrowsingEnabled;
   1607     }
   1608 
   1609     /**
   1610      * Sets whether private browsing is enabled.
   1611      * @param flag Whether private browsing should be enabled.
   1612      */
   1613     /* package */ synchronized void setPrivateBrowsingEnabled(boolean flag) {
   1614         if (mPrivateBrowsingEnabled != flag) {
   1615             mPrivateBrowsingEnabled = flag;
   1616 
   1617             // AutoFill is dependant on private browsing being enabled so
   1618             // reset it to take account of the new value of mPrivateBrowsingEnabled.
   1619             setAutoFillEnabled(mAutoFillEnabled);
   1620 
   1621             postSync();
   1622         }
   1623     }
   1624 
   1625     /**
   1626      * Returns whether the viewport metatag can disable zooming
   1627      */
   1628     public boolean forceUserScalable() {
   1629         return mForceUserScalable;
   1630     }
   1631 
   1632     /**
   1633      * Sets whether viewport metatag can disable zooming.
   1634      * @param flag Whether or not to forceably enable user scalable.
   1635      */
   1636     public synchronized void setForceUserScalable(boolean flag) {
   1637         mForceUserScalable = flag;
   1638     }
   1639 
   1640     synchronized void setSyntheticLinksEnabled(boolean flag) {
   1641         if (mSyntheticLinksEnabled != flag) {
   1642             mSyntheticLinksEnabled = flag;
   1643             postSync();
   1644         }
   1645     }
   1646 
   1647     public synchronized void setAutoFillEnabled(boolean enabled) {
   1648         // AutoFill is always disabled in private browsing mode.
   1649         boolean autoFillEnabled = enabled && !mPrivateBrowsingEnabled;
   1650         if (mAutoFillEnabled != autoFillEnabled) {
   1651             mAutoFillEnabled = autoFillEnabled;
   1652             postSync();
   1653         }
   1654     }
   1655 
   1656     public synchronized boolean getAutoFillEnabled() {
   1657         return mAutoFillEnabled;
   1658     }
   1659 
   1660     public synchronized void setAutoFillProfile(AutoFillProfile profile) {
   1661         if (mAutoFillProfile != profile) {
   1662             mAutoFillProfile = profile;
   1663             postSync();
   1664         }
   1665     }
   1666 
   1667     public synchronized AutoFillProfile getAutoFillProfile() {
   1668         return mAutoFillProfile;
   1669     }
   1670 
   1671     int getDoubleTapToastCount() {
   1672         return mDoubleTapToastCount;
   1673     }
   1674 
   1675     void setDoubleTapToastCount(int count) {
   1676         if (mDoubleTapToastCount != count) {
   1677             mDoubleTapToastCount = count;
   1678             // write the settings in the non-UI thread
   1679             mEventHandler.sendMessage(Message.obtain(null,
   1680                     EventHandler.SET_DOUBLE_TAP_TOAST_COUNT));
   1681         }
   1682     }
   1683 
   1684     public void setProperty(String key, String value) {
   1685         if (mWebView.nativeSetProperty(key, value)) {
   1686             mWebView.invalidate();
   1687         }
   1688     }
   1689 
   1690     public String getProperty(String key) {
   1691         return mWebView.nativeGetProperty(key);
   1692     }
   1693 
   1694     /**
   1695      * Transfer messages from the queue to the new WebCoreThread. Called from
   1696      * WebCore thread.
   1697      */
   1698     /*package*/
   1699     synchronized void syncSettingsAndCreateHandler(BrowserFrame frame) {
   1700         mBrowserFrame = frame;
   1701         if (DebugFlags.WEB_SETTINGS) {
   1702             junit.framework.Assert.assertTrue(frame.mNativeFrame != 0);
   1703         }
   1704 
   1705         SharedPreferences sp = mContext.getSharedPreferences(PREF_FILE,
   1706                 Context.MODE_PRIVATE);
   1707         if (mDoubleTapToastCount > 0) {
   1708             mDoubleTapToastCount = sp.getInt(DOUBLE_TAP_TOAST_COUNT,
   1709                     mDoubleTapToastCount);
   1710         }
   1711         nativeSync(frame.mNativeFrame);
   1712         mSyncPending = false;
   1713         mEventHandler.createHandler();
   1714     }
   1715 
   1716     /**
   1717      * Let the Settings object know that our owner is being destroyed.
   1718      */
   1719     /*package*/
   1720     synchronized void onDestroyed() {
   1721     }
   1722 
   1723     private int pin(int size) {
   1724         // FIXME: 72 is just an arbitrary max text size value.
   1725         if (size < 1) {
   1726             return 1;
   1727         } else if (size > 72) {
   1728             return 72;
   1729         }
   1730         return size;
   1731     }
   1732 
   1733     /* Post a SYNC message to handle syncing the native settings. */
   1734     private synchronized void postSync() {
   1735         // Only post if a sync is not pending
   1736         if (!mSyncPending) {
   1737             mSyncPending = mEventHandler.sendMessage(
   1738                     Message.obtain(null, EventHandler.SYNC));
   1739         }
   1740     }
   1741 
   1742     // Synchronize the native and java settings.
   1743     private native void nativeSync(int nativeFrame);
   1744 }
   1745