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