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