ContentSettings.java revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package org.chromium.content.browser;
6
7import android.os.Handler;
8import android.os.Looper;
9import android.os.Message;
10import android.webkit.WebSettings.PluginState;
11import android.webkit.WebView;
12
13import org.chromium.base.CalledByNative;
14import org.chromium.base.JNINamespace;
15import org.chromium.base.ThreadUtils;
16
17/**
18 * Manages settings state for a ContentView. A ContentSettings instance is obtained
19 * from ContentView.getContentSettings(). If ContentView is used in the
20 * ContentView.PERSONALITY_VIEW role, all settings are read / write. If ContentView
21 * is in the ContentView.PERSONALITY_CHROME role, setting can only be read.
22 */
23@JNINamespace("content")
24public class ContentSettings {
25    // This enum corresponds to WebSettings.LayoutAlgorithm. We use our own to be
26    // able to extend it.
27    public enum LayoutAlgorithm {
28        NORMAL,
29        SINGLE_COLUMN,
30        NARROW_COLUMNS,
31        TEXT_AUTOSIZING,
32    }
33
34    private static final String TAG = "ContentSettings";
35
36    // This class must be created on the UI thread. Afterwards, it can be
37    // used from any thread. Internally, the class uses a message queue
38    // to call native code on the UI thread only.
39
40    // The native side of this object. Ownership is retained native-side by the WebContents
41    // instance that backs the associated ContentViewCore.
42    private int mNativeContentSettings = 0;
43
44    private ContentViewCore mContentViewCore;
45
46    // When ContentView is used in PERSONALITY_CHROME mode, settings can't
47    // be modified through the ContentSettings instance.
48    private boolean mCanModifySettings;
49
50    // A flag to avoid sending superfluous synchronization messages.
51    private boolean mIsSyncMessagePending = false;
52    // Custom handler that queues messages to call native code on the UI thread.
53    private final EventHandler mEventHandler;
54
55    // Protects access to settings fields.
56    private final Object mContentSettingsLock = new Object();
57
58    private static final int MINIMUM_FONT_SIZE = 1;
59    private static final int MAXIMUM_FONT_SIZE = 72;
60
61    // Private settings so we don't have to go into native code to
62    // retrieve the values. After setXXX, mEventHandler.syncSettingsLocked() needs to be called.
63    //
64    // TODO(mnaganov): populate with the complete set of legacy WebView settings.
65    // Note: If adding a new setting to this class, make sure to add it to the initFrom()
66    // method defined below.
67
68    private LayoutAlgorithm mLayoutAlgorithm = LayoutAlgorithm.NARROW_COLUMNS;
69    private int mTextSizePercent = 100;
70    private String mStandardFontFamily = "sans-serif";
71    private String mFixedFontFamily = "monospace";
72    private String mSansSerifFontFamily = "sans-serif";
73    private String mSerifFontFamily = "serif";
74    private String mCursiveFontFamily = "cursive";
75    private String mFantasyFontFamily = "fantasy";
76    // FIXME: Should be obtained from Android. Problem: it is hidden.
77    private String mDefaultTextEncoding = "Latin-1";
78    private String mUserAgent;
79    private int mMinimumFontSize = 8;
80    private int mMinimumLogicalFontSize = 8;
81    private int mDefaultFontSize = 16;
82    private int mDefaultFixedFontSize = 13;
83    private boolean mLoadsImagesAutomatically = true;
84    private boolean mImagesEnabled = true;
85    private boolean mJavaScriptEnabled = false;
86    private boolean mAllowUniversalAccessFromFileURLs = false;
87    private boolean mAllowFileAccessFromFileURLs = false;
88    private boolean mJavaScriptCanOpenWindowsAutomatically = false;
89    private boolean mSupportMultipleWindows = false;
90    private PluginState mPluginState = PluginState.OFF;
91    private boolean mAppCacheEnabled = false;
92    private boolean mDomStorageEnabled = false;
93    private boolean mDatabaseEnabled = false;
94    private boolean mUseWideViewport = false;
95    private boolean mLoadWithOverviewMode = false;
96    private boolean mMediaPlaybackRequiresUserGesture = true;
97    private String mDefaultVideoPosterURL;
98
99    // Not accessed by the native side.
100    private boolean mSupportZoom = true;
101    private boolean mBuiltInZoomControls = false;
102    private boolean mDisplayZoomControls = true;
103    static class LazyDefaultUserAgent {
104        // Lazy Holder pattern
105        private static final String sInstance = nativeGetDefaultUserAgent();
106    }
107
108    // Protects access to settings global fields.
109    private static final Object sGlobalContentSettingsLock = new Object();
110    // For compatibility with the legacy WebView, we can only enable AppCache when the path is
111    // provided. However, we don't use the path, so we just check if we have received it from the
112    // client.
113    private static boolean sAppCachePathIsSet = false;
114
115    // Class to handle messages to be processed on the UI thread.
116    private class EventHandler {
117        // Message id for syncing
118        private static final int SYNC = 0;
119        // Message id for updating user agent in the view
120        private static final int UPDATE_UA = 1;
121        // Message id for updating multi-touch zoom state in the view
122        private static final int UPDATE_MULTI_TOUCH = 2;
123        // Actual UI thread handler
124        private Handler mHandler;
125
126        EventHandler() {
127            mHandler = mContentViewCore.isPersonalityView() ?
128                    new Handler(Looper.getMainLooper()) {
129                        @Override
130                        public void handleMessage(Message msg) {
131                            switch (msg.what) {
132                                case SYNC:
133                                    synchronized (mContentSettingsLock) {
134                                        syncToNativeOnUiThread();
135                                        mIsSyncMessagePending = false;
136                                        mContentSettingsLock.notifyAll();
137                                    }
138                                    break;
139                                case UPDATE_UA:
140                                    if (mContentViewCore.isAlive()) {
141                                        mContentViewCore.setAllUserAgentOverridesInHistory();
142                                    }
143                                    break;
144                                case UPDATE_MULTI_TOUCH:
145                                    if (mContentViewCore.isAlive()) {
146                                        mContentViewCore.updateMultiTouchZoomSupport();
147                                    }
148                                    break;
149                            }
150                        }
151                    } :
152                    new Handler(Looper.getMainLooper()) {
153                        @Override
154                        public void handleMessage(Message msg) {
155                            switch (msg.what) {
156                                case SYNC:
157                                    synchronized (mContentSettingsLock) {
158                                        syncFromNativeOnUiThread();
159                                        mIsSyncMessagePending = false;
160                                    }
161                                    break;
162                            }
163                        }
164                    };
165        }
166
167        private void syncSettingsLocked() {
168            assert Thread.holdsLock(mContentSettingsLock);
169            if (mNativeContentSettings == 0) return;
170            if (mContentViewCore.isPersonalityView()) {
171                if (Looper.myLooper() == mHandler.getLooper()) {
172                    syncToNativeOnUiThread();
173                } else {
174                    // We're being called on a background thread, so post a message.
175                    if (mIsSyncMessagePending) {
176                        return;
177                    }
178                    mIsSyncMessagePending = true;
179                    mHandler.sendMessage(Message.obtain(null, SYNC));
180                    // When used in PERSONALITY_VIEW mode, we must block
181                    // until the settings have been sync'd to native to
182                    // ensure that they have taken effect.
183                    try {
184                        while (mIsSyncMessagePending) {
185                            mContentSettingsLock.wait();
186                        }
187                    } catch (InterruptedException e) {}
188                }
189            } else {
190                if (mIsSyncMessagePending) {
191                    return;
192                }
193                mIsSyncMessagePending = true;
194                mHandler.sendMessage(Message.obtain(null, SYNC));
195            }
196        }
197
198        private void sendUpdateUaMessageLocked() {
199            assert Thread.holdsLock(mContentSettingsLock);
200            if (mNativeContentSettings == 0) return;
201            mHandler.sendMessage(Message.obtain(null, UPDATE_UA));
202        }
203
204        private void sendUpdateMultiTouchMessageLocked() {
205            assert Thread.holdsLock(mContentSettingsLock);
206            if (mNativeContentSettings == 0) return;
207            mHandler.sendMessage(Message.obtain(null, UPDATE_MULTI_TOUCH));
208        }
209    }
210
211    /**
212     * Package constructor to prevent clients from creating a new settings
213     * instance. Must be called on the UI thread.
214     */
215    ContentSettings(ContentViewCore contentViewCore, int nativeContentView,
216            boolean isAccessFromFileURLsGrantedByDefault) {
217        ThreadUtils.assertOnUiThread();
218        mContentViewCore = contentViewCore;
219        mCanModifySettings = mContentViewCore.isPersonalityView();
220        mNativeContentSettings = nativeInit(nativeContentView, mCanModifySettings);
221        assert mNativeContentSettings != 0;
222
223        if (isAccessFromFileURLsGrantedByDefault) {
224            mAllowUniversalAccessFromFileURLs = true;
225            mAllowFileAccessFromFileURLs = true;
226        }
227
228        mEventHandler = new EventHandler();
229        if (mCanModifySettings) {
230            // PERSONALITY_VIEW
231            mUserAgent = LazyDefaultUserAgent.sInstance;
232            syncToNativeOnUiThread();
233        } else {
234            // PERSONALITY_CHROME
235            // Chrome has zooming enabled by default. These settings are not
236            // set by the native code.
237            mBuiltInZoomControls = true;
238            mDisplayZoomControls = false;
239            syncFromNativeOnUiThread();
240        }
241    }
242
243    /**
244     * Notification from the native side that it is being destroyed.
245     * @param nativeContentSettings the native instance that is going away.
246     */
247    @CalledByNative
248    private void onNativeContentSettingsDestroyed(int nativeContentSettings) {
249        assert mNativeContentSettings == nativeContentSettings;
250        mNativeContentSettings = 0;
251    }
252
253    /**
254     * @returns the default User-Agent used by each ContentViewCore instance, i.e. unless
255     * overridden by {@link #setUserAgentString()}
256     */
257    public static String getDefaultUserAgent() {
258        return LazyDefaultUserAgent.sInstance;
259    }
260
261    /**
262     * Set the WebView's user-agent string. If the string "ua" is null or empty,
263     * it will use the system default user-agent string.
264     */
265    public void setUserAgentString(String ua) {
266        assert mCanModifySettings;
267        synchronized (mContentSettingsLock) {
268            final String oldUserAgent = mUserAgent;
269            if (ua == null || ua.length() == 0) {
270                mUserAgent = LazyDefaultUserAgent.sInstance;
271            } else {
272                mUserAgent = ua;
273            }
274            if (!oldUserAgent.equals(mUserAgent)) {
275                mEventHandler.sendUpdateUaMessageLocked();
276            }
277        }
278    }
279
280    /**
281     * Gets the WebView's user-agent string.
282     */
283    public String getUserAgentString() {
284        // TODO(mnaganov): Doesn't reflect changes made by ChromeNativePreferences.
285        synchronized (mContentSettingsLock) {
286            return mUserAgent;
287        }
288    }
289
290    /**
291     * Sets whether the WebView should support zooming using its on-screen zoom
292     * controls and gestures. The particular zoom mechanisms that should be used
293     * can be set with {@link #setBuiltInZoomControls}. This setting does not
294     * affect zooming performed using the {@link WebView#zoomIn()} and
295     * {@link WebView#zoomOut()} methods. The default is true.
296     *
297     * @param support whether the WebView should support zoom
298     */
299    public void setSupportZoom(boolean support) {
300        synchronized (mContentSettingsLock) {
301            mSupportZoom = support;
302            mEventHandler.sendUpdateMultiTouchMessageLocked();
303        }
304    }
305
306    /**
307     * Gets whether the WebView supports zoom.
308     *
309     * @return true if the WebView supports zoom
310     * @see #setSupportZoom
311     */
312    public boolean supportZoom() {
313        return mSupportZoom;
314    }
315
316   /**
317     * Sets whether the WebView should use its built-in zoom mechanisms. The
318     * built-in zoom mechanisms comprise on-screen zoom controls, which are
319     * displayed over the WebView's content, and the use of a pinch gesture to
320     * control zooming. Whether or not these on-screen controls are displayed
321     * can be set with {@link #setDisplayZoomControls}. The default is false,
322     * due to compatibility reasons.
323     * <p>
324     * The built-in mechanisms are the only currently supported zoom
325     * mechanisms, so it is recommended that this setting is always enabled.
326     * In other words, there is no point of calling this method other than
327     * with the 'true' parameter.
328     *
329     * @param enabled whether the WebView should use its built-in zoom mechanisms
330     */
331     public void setBuiltInZoomControls(boolean enabled) {
332        synchronized (mContentSettingsLock) {
333            mBuiltInZoomControls = enabled;
334            mEventHandler.sendUpdateMultiTouchMessageLocked();
335        }
336    }
337
338    /**
339     * Gets whether the zoom mechanisms built into WebView are being used.
340     *
341     * @return true if the zoom mechanisms built into WebView are being used
342     * @see #setBuiltInZoomControls
343     */
344    public boolean getBuiltInZoomControls() {
345        return mBuiltInZoomControls;
346    }
347
348    /**
349     * Sets whether the WebView should display on-screen zoom controls when
350     * using the built-in zoom mechanisms. See {@link #setBuiltInZoomControls}.
351     * The default is true.
352     *
353     * @param enabled whether the WebView should display on-screen zoom controls
354     */
355    public void setDisplayZoomControls(boolean enabled) {
356        synchronized (mContentSettingsLock) {
357            mDisplayZoomControls = enabled;
358            mEventHandler.sendUpdateMultiTouchMessageLocked();
359        }
360    }
361
362    /**
363     * Gets whether the WebView displays on-screen zoom controls when using
364     * the built-in zoom mechanisms.
365     *
366     * @return true if the WebView displays on-screen zoom controls when using
367     *         the built-in zoom mechanisms
368     * @see #setDisplayZoomControls
369     */
370    public boolean getDisplayZoomControls() {
371        return mDisplayZoomControls;
372    }
373
374    boolean supportsMultiTouchZoom() {
375        return mSupportZoom && mBuiltInZoomControls;
376    }
377
378    boolean shouldDisplayZoomControls() {
379        return supportsMultiTouchZoom() && mDisplayZoomControls;
380    }
381
382    public void setLoadWithOverviewMode(boolean overview) {
383        assert mCanModifySettings;
384        synchronized (mContentSettingsLock) {
385            if (mLoadWithOverviewMode != overview) {
386                mLoadWithOverviewMode = overview;
387                mEventHandler.syncSettingsLocked();
388            }
389        }
390    }
391
392    public boolean getLoadWithOverviewMode() {
393        synchronized (mContentSettingsLock) {
394            return mLoadWithOverviewMode;
395        }
396    }
397
398    /**
399     * Sets the text zoom of the page in percent. Default is 100.
400     *
401     * @param textZoom the percent value for increasing or decreasing the text
402     */
403    public void setTextZoom(int textZoom) {
404        assert mCanModifySettings;
405        synchronized (mContentSettingsLock) {
406            if (mTextSizePercent != textZoom) {
407                mTextSizePercent = textZoom;
408                mEventHandler.syncSettingsLocked();
409            }
410        }
411    }
412
413    /**
414     * Gets the text zoom of the page in percent.
415     *
416     * @return a percent value describing the text zoom
417     * @see #setTextSizeZoom
418     */
419    public int getTextZoom() {
420        synchronized (mContentSettingsLock) {
421            return mTextSizePercent;
422        }
423    }
424
425    /**
426     * Set the standard font family name.
427     * @param font A font family name.
428     */
429    public void setStandardFontFamily(String font) {
430        assert mCanModifySettings;
431        synchronized (mContentSettingsLock) {
432            if (font != null && !mStandardFontFamily.equals(font)) {
433                mStandardFontFamily = font;
434                mEventHandler.syncSettingsLocked();
435            }
436        }
437    }
438
439    /**
440     * Get the standard font family name. The default is "sans-serif".
441     * @return The standard font family name as a string.
442     */
443    public String getStandardFontFamily() {
444        synchronized (mContentSettingsLock) {
445            return mStandardFontFamily;
446        }
447    }
448
449    /**
450     * Set the fixed font family name.
451     * @param font A font family name.
452     */
453    public void setFixedFontFamily(String font) {
454        assert mCanModifySettings;
455        synchronized (mContentSettingsLock) {
456            if (font != null && !mFixedFontFamily.equals(font)) {
457                mFixedFontFamily = font;
458                mEventHandler.syncSettingsLocked();
459            }
460        }
461    }
462
463    /**
464     * Get the fixed font family name. The default is "monospace".
465     * @return The fixed font family name as a string.
466     */
467    public String getFixedFontFamily() {
468        synchronized (mContentSettingsLock) {
469            return mFixedFontFamily;
470        }
471    }
472
473    /**
474     * Set the sans-serif font family name.
475     * @param font A font family name.
476     */
477    public void setSansSerifFontFamily(String font) {
478        assert mCanModifySettings;
479        synchronized (mContentSettingsLock) {
480            if (font != null && !mSansSerifFontFamily.equals(font)) {
481                mSansSerifFontFamily = font;
482                mEventHandler.syncSettingsLocked();
483            }
484        }
485    }
486
487    /**
488     * Get the sans-serif font family name.
489     * @return The sans-serif font family name as a string.
490     */
491    public String getSansSerifFontFamily() {
492        synchronized (mContentSettingsLock) {
493            return mSansSerifFontFamily;
494        }
495    }
496
497    /**
498     * Set the serif font family name. The default is "sans-serif".
499     * @param font A font family name.
500     */
501    public void setSerifFontFamily(String font) {
502        assert mCanModifySettings;
503        synchronized (mContentSettingsLock) {
504            if (font != null && !mSerifFontFamily.equals(font)) {
505                mSerifFontFamily = font;
506                mEventHandler.syncSettingsLocked();
507            }
508        }
509    }
510
511    /**
512     * Get the serif font family name. The default is "serif".
513     * @return The serif font family name as a string.
514     */
515    public String getSerifFontFamily() {
516        synchronized (mContentSettingsLock) {
517            return mSerifFontFamily;
518        }
519    }
520
521    /**
522     * Set the cursive font family name.
523     * @param font A font family name.
524     */
525    public void setCursiveFontFamily(String font) {
526        assert mCanModifySettings;
527        synchronized (mContentSettingsLock) {
528            if (font != null && !mCursiveFontFamily.equals(font)) {
529                mCursiveFontFamily = font;
530                mEventHandler.syncSettingsLocked();
531            }
532        }
533    }
534
535    /**
536     * Get the cursive font family name. The default is "cursive".
537     * @return The cursive font family name as a string.
538     */
539    public String getCursiveFontFamily() {
540        synchronized (mContentSettingsLock) {
541            return mCursiveFontFamily;
542        }
543    }
544
545    /**
546     * Set the fantasy font family name.
547     * @param font A font family name.
548     */
549    public void setFantasyFontFamily(String font) {
550        assert mCanModifySettings;
551        synchronized (mContentSettingsLock) {
552            if (font != null && !mFantasyFontFamily.equals(font)) {
553                mFantasyFontFamily = font;
554                mEventHandler.syncSettingsLocked();
555            }
556        }
557    }
558
559    /**
560     * Get the fantasy font family name. The default is "fantasy".
561     * @return The fantasy font family name as a string.
562     */
563    public String getFantasyFontFamily() {
564        synchronized (mContentSettingsLock) {
565            return mFantasyFontFamily;
566        }
567    }
568
569    /**
570     * Set the minimum font size.
571     * @param size A non-negative integer between 1 and 72.
572     * Any number outside the specified range will be pinned.
573     */
574    public void setMinimumFontSize(int size) {
575        assert mCanModifySettings;
576        synchronized (mContentSettingsLock) {
577            size = clipFontSize(size);
578            if (mMinimumFontSize != size) {
579                mMinimumFontSize = size;
580                mEventHandler.syncSettingsLocked();
581            }
582        }
583    }
584
585    /**
586     * Get the minimum font size. The default is 8.
587     * @return A non-negative integer between 1 and 72.
588     */
589    public int getMinimumFontSize() {
590        synchronized (mContentSettingsLock) {
591            return mMinimumFontSize;
592        }
593    }
594
595    /**
596     * Set the minimum logical font size.
597     * @param size A non-negative integer between 1 and 72.
598     * Any number outside the specified range will be pinned.
599     */
600    public void setMinimumLogicalFontSize(int size) {
601        assert mCanModifySettings;
602        synchronized (mContentSettingsLock) {
603            size = clipFontSize(size);
604            if (mMinimumLogicalFontSize != size) {
605                mMinimumLogicalFontSize = size;
606                mEventHandler.syncSettingsLocked();
607            }
608        }
609    }
610
611    /**
612     * Get the minimum logical font size. The default is 8.
613     * @return A non-negative integer between 1 and 72.
614     */
615    public int getMinimumLogicalFontSize() {
616        synchronized (mContentSettingsLock) {
617            return mMinimumLogicalFontSize;
618        }
619    }
620
621    /**
622     * Set the default font size.
623     * @param size A non-negative integer between 1 and 72.
624     * Any number outside the specified range will be pinned.
625     */
626    public void setDefaultFontSize(int size) {
627        assert mCanModifySettings;
628        synchronized (mContentSettingsLock) {
629            size = clipFontSize(size);
630            if (mDefaultFontSize != size) {
631                mDefaultFontSize = size;
632                mEventHandler.syncSettingsLocked();
633            }
634        }
635    }
636
637    /**
638     * Get the default font size. The default is 16.
639     * @return A non-negative integer between 1 and 72.
640     */
641    public int getDefaultFontSize() {
642        synchronized (mContentSettingsLock) {
643            return mDefaultFontSize;
644        }
645    }
646
647    /**
648     * Set the default fixed font size.
649     * @param size A non-negative integer between 1 and 72.
650     * Any number outside the specified range will be pinned.
651     */
652    public void setDefaultFixedFontSize(int size) {
653        assert mCanModifySettings;
654        synchronized (mContentSettingsLock) {
655            size = clipFontSize(size);
656            if (mDefaultFixedFontSize != size) {
657                mDefaultFixedFontSize = size;
658                mEventHandler.syncSettingsLocked();
659            }
660        }
661    }
662
663    /**
664     * Get the default fixed font size. The default is 16.
665     * @return A non-negative integer between 1 and 72.
666     */
667    public int getDefaultFixedFontSize() {
668        synchronized (mContentSettingsLock) {
669            return mDefaultFixedFontSize;
670        }
671    }
672
673    /**
674     * Tell the WebView to enable JavaScript execution.
675     *
676     * @param flag True if the WebView should execute JavaScript.
677     */
678    public void setJavaScriptEnabled(boolean flag) {
679        assert mCanModifySettings;
680        synchronized (mContentSettingsLock) {
681            if (mJavaScriptEnabled != flag) {
682                mJavaScriptEnabled = flag;
683                mEventHandler.syncSettingsLocked();
684            }
685        }
686    }
687
688    /**
689     * Sets whether JavaScript running in the context of a file scheme URL
690     * should be allowed to access content from any origin. This includes
691     * access to content from other file scheme URLs. See
692     * {@link #setAllowFileAccessFromFileURLs}. To enable the most restrictive,
693     * and therefore secure policy, this setting should be disabled.
694     * <p>
695     * The default value is true for API level
696     * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and below,
697     * and false for API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN}
698     * and above.
699     *
700     * @param flag whether JavaScript running in the context of a file scheme
701     *             URL should be allowed to access content from any origin
702     */
703    public void setAllowUniversalAccessFromFileURLs(boolean flag) {
704        assert mCanModifySettings;
705        synchronized (mContentSettingsLock) {
706            if (mAllowUniversalAccessFromFileURLs != flag) {
707                mAllowUniversalAccessFromFileURLs = flag;
708                mEventHandler.syncSettingsLocked();
709            }
710        }
711    }
712
713    /**
714     * Sets whether JavaScript running in the context of a file scheme URL
715     * should be allowed to access content from other file scheme URLs. To
716     * enable the most restrictive, and therefore secure policy, this setting
717     * should be disabled. Note that the value of this setting is ignored if
718     * the value of {@link #getAllowUniversalAccessFromFileURLs} is true.
719     * <p>
720     * The default value is true for API level
721     * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and below,
722     * and false for API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN}
723     * and above.
724     *
725     * @param flag whether JavaScript running in the context of a file scheme
726     *             URL should be allowed to access content from other file
727     *             scheme URLs
728     */
729    public void setAllowFileAccessFromFileURLs(boolean flag) {
730        assert mCanModifySettings;
731        synchronized (mContentSettingsLock) {
732            if (mAllowFileAccessFromFileURLs != flag) {
733                mAllowFileAccessFromFileURLs = flag;
734                mEventHandler.syncSettingsLocked();
735            }
736        }
737    }
738
739    /**
740     * Tell the WebView to load image resources automatically.
741     * Note that setting this flag to false this does not block image loads
742     * from WebCore cache.
743     * @param flag True if the WebView should load images automatically.
744     */
745    public void setLoadsImagesAutomatically(boolean flag) {
746        assert mCanModifySettings;
747        synchronized (mContentSettingsLock) {
748            if (mLoadsImagesAutomatically != flag) {
749                mLoadsImagesAutomatically = flag;
750                mEventHandler.syncSettingsLocked();
751            }
752        }
753    }
754
755    /**
756     * Return true if the WebView will load image resources automatically.
757     * The default is true.
758     * @return True if the WebView loads images automatically.
759     */
760    public boolean getLoadsImagesAutomatically() {
761        synchronized (mContentSettingsLock) {
762            return mLoadsImagesAutomatically;
763        }
764    }
765
766    /**
767     * Sets whether images are enabled for this WebView. Setting this from
768     * false to true will reload the blocked images in place.
769     * Note that unlike {@link #setLoadsImagesAutomatically}, setting this
770     * flag to false this will block image loads from WebCore cache as well.
771     * The default is true.
772     * @param flag whether the WebView should enable images.
773     */
774    public void setImagesEnabled(boolean flag) {
775        assert mCanModifySettings;
776        synchronized (mContentSettingsLock) {
777            if (mImagesEnabled != flag) {
778                mImagesEnabled = flag;
779                mEventHandler.syncSettingsLocked();
780            }
781        }
782    }
783
784    /**
785     * Gets whether images are enabled for this WebView.
786     * @return true if the WebView has images eanbled
787     */
788    public boolean getImagesEnabled() {
789        synchronized (mContentSettingsLock) {
790            return mImagesEnabled;
791        }
792    }
793
794    /**
795     * Return true if JavaScript is enabled. <b>Note: The default is false.</b>
796     *
797     * @return True if JavaScript is enabled.
798     */
799    public boolean getJavaScriptEnabled() {
800        synchronized (mContentSettingsLock) {
801            return mJavaScriptEnabled;
802        }
803    }
804
805    /**
806     * Gets whether JavaScript running in the context of a file scheme URL can
807     * access content from any origin. This includes access to content from
808     * other file scheme URLs.
809     *
810     * @return whether JavaScript running in the context of a file scheme URL
811     *         can access content from any origin
812     * @see #setAllowUniversalAccessFromFileURLs
813     */
814    public boolean getAllowUniversalAccessFromFileURLs() {
815        synchronized (mContentSettingsLock) {
816            return mAllowUniversalAccessFromFileURLs;
817        }
818    }
819
820    /**
821     * Gets whether JavaScript running in the context of a file scheme URL can
822     * access content from other file scheme URLs.
823     *
824     * @return whether JavaScript running in the context of a file scheme URL
825     *         can access content from other file scheme URLs
826     * @see #setAllowFileAccessFromFileURLs
827     */
828    public boolean getAllowFileAccessFromFileURLs() {
829        synchronized (mContentSettingsLock) {
830            return mAllowFileAccessFromFileURLs;
831        }
832    }
833
834    /**
835     * Tell the WebView to enable plugins.
836     * @param flag True if the WebView should load plugins.
837     * @deprecated This method has been deprecated in favor of
838     *             {@link #setPluginState}
839     */
840    @Deprecated
841    public void setPluginsEnabled(boolean flag) {
842        assert mCanModifySettings;
843        setPluginState(flag ? PluginState.ON : PluginState.OFF);
844    }
845
846    /**
847     * Tell the WebView to enable, disable, or have plugins on demand. On
848     * demand mode means that if a plugin exists that can handle the embedded
849     * content, a placeholder icon will be shown instead of the plugin. When
850     * the placeholder is clicked, the plugin will be enabled.
851     * @param state One of the PluginState values.
852     */
853    public void setPluginState(PluginState state) {
854        assert mCanModifySettings;
855        synchronized (mContentSettingsLock) {
856            if (mPluginState != state) {
857                mPluginState = state;
858                mEventHandler.syncSettingsLocked();
859            }
860        }
861    }
862
863    /**
864     * Return true if plugins are enabled.
865     * @return True if plugins are enabled.
866     * @deprecated This method has been replaced by {@link #getPluginState}
867     */
868    @Deprecated
869    public boolean getPluginsEnabled() {
870        synchronized (mContentSettingsLock) {
871            return mPluginState == PluginState.ON;
872        }
873    }
874
875    /**
876     * Return true if plugins are disabled.
877     * @return True if plugins are disabled.
878     * @hide
879     */
880    @CalledByNative
881    private boolean getPluginsDisabled() {
882        // This should only be called from SyncToNative, which is called
883        // either from the constructor, or with mContentSettingsLock being held.
884        return mPluginState == PluginState.OFF;
885    }
886
887    /**
888     * Sets if plugins are disabled.
889     * @return True if plugins are disabled.
890     * @hide
891     */
892    @CalledByNative
893    private void setPluginsDisabled(boolean disabled) {
894        // This should only be called from SyncFromToNative, which is called
895        // either from the constructor, or with mContentSettingsLock being held.
896        mPluginState = disabled ? PluginState.OFF : PluginState.ON;
897    }
898
899    /**
900     * Return the current plugin state.
901     * @return A value corresponding to the enum PluginState.
902     */
903    public PluginState getPluginState() {
904        synchronized (mContentSettingsLock) {
905            return mPluginState;
906        }
907    }
908
909
910    /**
911     * Tell javascript to open windows automatically. This applies to the
912     * javascript function window.open().
913     * @param flag True if javascript can open windows automatically.
914     */
915    public void setJavaScriptCanOpenWindowsAutomatically(boolean flag) {
916        assert mCanModifySettings;
917        synchronized (mContentSettingsLock) {
918            if (mJavaScriptCanOpenWindowsAutomatically != flag) {
919                mJavaScriptCanOpenWindowsAutomatically = flag;
920                mEventHandler.syncSettingsLocked();
921            }
922        }
923    }
924
925    /**
926     * Return true if javascript can open windows automatically. The default
927     * is false.
928     * @return True if javascript can open windows automatically during
929     *         window.open().
930     */
931    public boolean getJavaScriptCanOpenWindowsAutomatically() {
932        synchronized (mContentSettingsLock) {
933            return mJavaScriptCanOpenWindowsAutomatically;
934        }
935    }
936
937    /**
938     * Sets the underlying layout algorithm. The default is
939     * {@link LayoutAlgorithm#NARROW_COLUMNS}.
940     *
941     * @param l the layout algorithm to use, as a {@link LayoutAlgorithm} value
942     */
943    public void setLayoutAlgorithm(LayoutAlgorithm l) {
944        assert mCanModifySettings;
945        synchronized (mContentSettingsLock) {
946            if (mLayoutAlgorithm != l) {
947                mLayoutAlgorithm = l;
948                mEventHandler.syncSettingsLocked();
949            }
950        }
951    }
952
953    /**
954     * Gets the current layout algorithm.
955     *
956     * @return the layout algorithm in use, as a {@link LayoutAlgorithm} value
957     * @see #setLayoutAlgorithm
958     */
959    public LayoutAlgorithm getLayoutAlgorithm() {
960        synchronized (mContentSettingsLock) {
961            return mLayoutAlgorithm;
962        }
963    }
964
965    /**
966     * Sets whether Text Auto-sizing layout algorithm is enabled.
967     *
968     * @param enabled whether Text Auto-sizing layout algorithm is enabled
969     * @hide
970     */
971    @CalledByNative
972    private void setTextAutosizingEnabled(boolean enabled) {
973        // This should only be called from SyncFromNative, which is called
974        // either from the constructor, or with mContentSettingsLock being held.
975        mLayoutAlgorithm = enabled ?
976                LayoutAlgorithm.TEXT_AUTOSIZING : LayoutAlgorithm.NARROW_COLUMNS;
977    }
978
979    /**
980     * Gets whether Text Auto-sizing layout algorithm is enabled.
981     *
982     * @return true if Text Auto-sizing layout algorithm is enabled
983     * @hide
984     */
985    @CalledByNative
986    private boolean getTextAutosizingEnabled() {
987        return mLayoutAlgorithm == LayoutAlgorithm.TEXT_AUTOSIZING;
988    }
989
990    /**
991     * Tells the WebView whether it supports multiple windows. True means
992     * that {@link WebChromeClient#onCreateWindow(WebView, boolean,
993     * boolean, Message)} is implemented by the host application.
994     */
995    public void setSupportMultipleWindows(boolean support) {
996        assert mCanModifySettings;
997        synchronized (mContentSettingsLock) {
998            if (mSupportMultipleWindows != support) {
999                mSupportMultipleWindows = support;
1000                mEventHandler.syncSettingsLocked();
1001            }
1002        }
1003    }
1004
1005    /**
1006     * Gets whether the WebView is supporting multiple windows.
1007     *
1008     * @return true if the WebView is supporting multiple windows. This means
1009     *         that {@link WebChromeClient#onCreateWindow(WebView, boolean,
1010     *         boolean, Message)} is implemented by the host application.
1011     */
1012    public boolean supportMultipleWindows() {
1013        synchronized (mContentSettingsLock) {
1014            return mSupportMultipleWindows;
1015        }
1016    }
1017
1018    /**
1019     * Sets whether the WebView should enable support for the &quot;viewport&quot;
1020     * HTML meta tag or should use a wide viewport.
1021     * When the value of the setting is false, the layout width is always set to the
1022     * width of the WebView control in device-independent (CSS) pixels.
1023     * When the value is true and the page contains the viewport meta tag, the value
1024     * of the width specified in the tag is used. If the page does not contain the tag or
1025     * does not provide a width, then a wide viewport will be used.
1026     *
1027     * @param use whether to enable support for the viewport meta tag
1028     */
1029    public void setUseWideViewPort(boolean use) {
1030        assert mCanModifySettings;
1031        synchronized (mContentSettingsLock) {
1032            if (mUseWideViewport != use) {
1033                mUseWideViewport = use;
1034                mEventHandler.syncSettingsLocked();
1035            }
1036        }
1037    }
1038
1039    /**
1040     * Gets whether the WebView supports the &quot;viewport&quot;
1041     * HTML meta tag or will use a wide viewport.
1042     *
1043     * @return true if the WebView supports the viewport meta tag
1044     * @see #setUseWideViewPort
1045     */
1046    public boolean getUseWideViewPort() {
1047        synchronized (mContentSettingsLock) {
1048            return mUseWideViewport;
1049        }
1050    }
1051
1052    /**
1053     * Sets whether the Application Caches API should be enabled. The default
1054     * is false. Note that in order for the Application Caches API to be
1055     * enabled, a non-empty database path must also be supplied to
1056     * {@link #setAppCachePath} (this is done for compatibility with the
1057     * legacy implementation).
1058     *
1059     * @param flag true if the WebView should enable Application Caches
1060     */
1061    public void setAppCacheEnabled(boolean flag) {
1062        assert mCanModifySettings;
1063        synchronized (mContentSettingsLock) {
1064            if (mAppCacheEnabled != flag) {
1065                mAppCacheEnabled = flag;
1066                mEventHandler.syncSettingsLocked();
1067            }
1068        }
1069    }
1070
1071    /**
1072     * Sets the path to the Application Caches files. In order for the
1073     * Application Caches API to be enabled, this method must be called with a
1074     * non-empty path. This method should only be called once: repeated calls
1075     * are ignored.
1076     *
1077     * @param path a non empty-string
1078     */
1079    public void setAppCachePath(String path) {
1080        assert mCanModifySettings;
1081        boolean needToSync = false;
1082        synchronized (sGlobalContentSettingsLock) {
1083            // AppCachePath can only be set once.
1084            if (!sAppCachePathIsSet && path != null && !path.isEmpty()) {
1085                sAppCachePathIsSet = true;
1086                needToSync = true;
1087            }
1088        }
1089        // The obvious problem here is that other WebViews will not be updated,
1090        // until they execute synchronization from Java to the native side.
1091        // But this is the same behaviour as it was in the legacy WebView.
1092        if (needToSync) {
1093            synchronized (mContentSettingsLock) {
1094                mEventHandler.syncSettingsLocked();
1095            }
1096        }
1097    }
1098
1099    /**
1100     * Gets whether Application Cache is enabled.
1101     *
1102     * @return true if Application Cache is enabled
1103     * @hide
1104     */
1105    @CalledByNative
1106    private boolean getAppCacheEnabled() {
1107        // This should only be called from SyncToNative, which is called
1108        // either from the constructor, or with mContentSettingsLock being held.
1109        if (!mAppCacheEnabled) {
1110            return false;
1111        }
1112        synchronized (sGlobalContentSettingsLock) {
1113            return sAppCachePathIsSet;
1114        }
1115    }
1116
1117    /**
1118     * Sets whether the DOM storage API is enabled. The default value is false.
1119     *
1120     * @param flag true if the ContentView should use the DOM storage API
1121     */
1122    public void setDomStorageEnabled(boolean flag) {
1123        assert mCanModifySettings;
1124        synchronized (mContentSettingsLock) {
1125            if (mDomStorageEnabled != flag) {
1126                mDomStorageEnabled = flag;
1127                mEventHandler.syncSettingsLocked();
1128            }
1129        }
1130    }
1131
1132    /**
1133     * Gets whether the DOM Storage APIs are enabled.
1134     *
1135     * @return true if the DOM Storage APIs are enabled
1136     * @see #setDomStorageEnabled
1137     */
1138    public boolean getDomStorageEnabled() {
1139       synchronized (mContentSettingsLock) {
1140           return mDomStorageEnabled;
1141       }
1142    }
1143
1144    /**
1145     * Sets whether the WebSQL storage API is enabled. The default value is false.
1146     *
1147     * @param flag true if the ContentView should use the WebSQL storage API
1148     */
1149    public void setDatabaseEnabled(boolean flag) {
1150        assert mCanModifySettings;
1151        synchronized (mContentSettingsLock) {
1152            if (mDatabaseEnabled != flag) {
1153                mDatabaseEnabled = flag;
1154                mEventHandler.syncSettingsLocked();
1155            }
1156        }
1157    }
1158
1159    /**
1160     * Gets whether the WebSQL Storage APIs are enabled.
1161     *
1162     * @return true if the WebSQL Storage APIs are enabled
1163     * @see #setDatabaseEnabled
1164     */
1165    public boolean getDatabaseEnabled() {
1166       synchronized (mContentSettingsLock) {
1167           return mDatabaseEnabled;
1168       }
1169    }
1170
1171    /**
1172     * Set the default text encoding name to use when decoding html pages.
1173     * @param encoding The text encoding name.
1174     */
1175    public void setDefaultTextEncodingName(String encoding) {
1176        assert mCanModifySettings;
1177        synchronized (mContentSettingsLock) {
1178            if (encoding != null && !mDefaultTextEncoding.equals(encoding)) {
1179                mDefaultTextEncoding = encoding;
1180                mEventHandler.syncSettingsLocked();
1181            }
1182        }
1183    }
1184
1185    /**
1186     * Get the default text encoding name. The default is "Latin-1".
1187     * @return The default text encoding name as a string.
1188     */
1189    public String getDefaultTextEncodingName() {
1190        synchronized (mContentSettingsLock) {
1191            return mDefaultTextEncoding;
1192        }
1193    }
1194
1195    /**
1196     * Set whether the user gesture is required for media playback.
1197     * @param require true if the user gesture is required.
1198     */
1199    public void setMediaPlaybackRequiresUserGesture(boolean require) {
1200        assert mCanModifySettings;
1201        synchronized (mContentSettingsLock) {
1202            if (mMediaPlaybackRequiresUserGesture != require) {
1203                mMediaPlaybackRequiresUserGesture = require;
1204                mEventHandler.syncSettingsLocked();
1205            }
1206        }
1207    }
1208
1209    /**
1210     * Get whether the user gesture is required for Media Playback.
1211     * @return true if the user gesture is required.
1212     */
1213    public boolean getMediaPlaybackRequiresUserGesture() {
1214        synchronized (mContentSettingsLock) {
1215            return mMediaPlaybackRequiresUserGesture;
1216        }
1217    }
1218
1219    /**
1220     * Set the default video poster URL.
1221     * @param url The url of default video poster.
1222     */
1223    public void setDefaultVideoPosterURL(String url) {
1224        assert mCanModifySettings;
1225        synchronized (mContentSettingsLock) {
1226            if (mDefaultVideoPosterURL != null && !mDefaultVideoPosterURL.equals(url) ||
1227                    mDefaultVideoPosterURL == null && url != null) {
1228                mDefaultVideoPosterURL = url;
1229                mEventHandler.syncSettingsLocked();
1230            }
1231        }
1232    }
1233
1234    /**
1235     * Get the default video poster URL.
1236     */
1237    public String getDefaultVideoPosterURL() {
1238        synchronized (mContentSettingsLock) {
1239            return mDefaultVideoPosterURL;
1240        }
1241    }
1242
1243    private int clipFontSize(int size) {
1244        if (size < MINIMUM_FONT_SIZE) {
1245            return MINIMUM_FONT_SIZE;
1246        } else if (size > MAXIMUM_FONT_SIZE) {
1247            return MAXIMUM_FONT_SIZE;
1248        }
1249        return size;
1250    }
1251
1252    /**
1253     * Sets the settings in this object to those from another
1254     * ContentSettings.
1255     * Required by WebView when we swap a in a new ContentViewCore
1256     * to an existing AwContents (i.e. to support displaying popup
1257     * windows in an already created WebView)
1258     */
1259    public void initFrom(ContentSettings settings) {
1260        setLayoutAlgorithm(settings.getLayoutAlgorithm());
1261        setLoadWithOverviewMode(settings.getLoadWithOverviewMode());
1262        setTextZoom(settings.getTextZoom());
1263        setStandardFontFamily(settings.getStandardFontFamily());
1264        setFixedFontFamily(settings.getFixedFontFamily());
1265        setSansSerifFontFamily(settings.getSansSerifFontFamily());
1266        setSerifFontFamily(settings.getSerifFontFamily());
1267        setCursiveFontFamily(settings.getCursiveFontFamily());
1268        setFantasyFontFamily(settings.getFantasyFontFamily());
1269        setDefaultTextEncodingName(settings.getDefaultTextEncodingName());
1270        setUserAgentString(settings.getUserAgentString());
1271        setMinimumFontSize(settings.getMinimumFontSize());
1272        setMinimumLogicalFontSize(settings.getMinimumLogicalFontSize());
1273        setDefaultFontSize(settings.getDefaultFontSize());
1274        setDefaultFixedFontSize(settings.getDefaultFixedFontSize());
1275        setLoadsImagesAutomatically(settings.getLoadsImagesAutomatically());
1276        setImagesEnabled(settings.getImagesEnabled());
1277        setJavaScriptEnabled(settings.getJavaScriptEnabled());
1278        setAllowUniversalAccessFromFileURLs(settings.getAllowUniversalAccessFromFileURLs());
1279        setAllowFileAccessFromFileURLs(settings.getAllowFileAccessFromFileURLs());
1280        setJavaScriptCanOpenWindowsAutomatically(
1281                settings.getJavaScriptCanOpenWindowsAutomatically());
1282        setSupportMultipleWindows(settings.supportMultipleWindows());
1283        setPluginState(settings.getPluginState());
1284        setAppCacheEnabled(settings.mAppCacheEnabled);
1285        setDomStorageEnabled(settings.getDomStorageEnabled());
1286        setDatabaseEnabled(settings.getDatabaseEnabled());
1287        setSupportZoom(settings.supportZoom());
1288        setBuiltInZoomControls(settings.getBuiltInZoomControls());
1289        setDisplayZoomControls(settings.getDisplayZoomControls());
1290        setMediaPlaybackRequiresUserGesture(settings.getMediaPlaybackRequiresUserGesture());
1291        setDefaultVideoPosterURL(settings.getDefaultVideoPosterURL());
1292    }
1293
1294    /**
1295     * Synchronize java side and native side settings. When ContentView
1296     * is running in PERSONALITY_VIEW mode, this needs to be done after
1297     * any java side setting is changed to sync them to native. In
1298     * PERSONALITY_CHROME mode, this needs to be called whenever native
1299     * settings are changed to sync them to java.
1300     */
1301    void syncSettings() {
1302        synchronized (mContentSettingsLock) {
1303            mEventHandler.syncSettingsLocked();
1304        }
1305    }
1306
1307    void syncToNativeOnUiThread() {
1308        if (mNativeContentSettings != 0) nativeSyncToNative(mNativeContentSettings);
1309    }
1310
1311    void syncFromNativeOnUiThread() {
1312        if (mNativeContentSettings != 0) nativeSyncFromNative(mNativeContentSettings);
1313    }
1314
1315    // Initialize the ContentSettings native side.
1316    private native int nativeInit(int contentViewPtr, boolean isMasterMode);
1317
1318    private static native String nativeGetDefaultUserAgent();
1319
1320    // Synchronize Java settings from native settings.
1321    private native void nativeSyncFromNative(int nativeContentSettings);
1322
1323    // Synchronize native settings from Java settings.
1324    private native void nativeSyncToNative(int nativeContentSettings);
1325}
1326