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.
5 package org.xwalk.core.internal;
7 import android.content.Context;
8 import android.content.pm.PackageManager;
9 import android.os.Handler;
10 import android.os.Looper;
11 import android.os.Message;
12 import android.os.Process;
13 import android.webkit.WebSettings;
15 import org.chromium.base.CalledByNative;
16 import org.chromium.base.JNINamespace;
17 import org.chromium.base.ThreadUtils;
22 @JNINamespace("xwalk")
23 public class XWalkSettings {
25 private static final String TAG = "XWalkSettings";
27 // This class must be created on the UI thread. Afterwards, it can be
28 // used from any thread. Internally, the class uses a message queue
29 // to call native code on the UI thread only.
31 // Lock to protect all settings.
32 private final Object mXWalkSettingsLock = new Object();
34 private final Context mContext;
36 private boolean mAllowScriptsToCloseWindows = true;
37 private boolean mLoadsImagesAutomatically = true;
38 private boolean mImagesEnabled = true;
39 private boolean mJavaScriptEnabled = true;
40 private boolean mAllowUniversalAccessFromFileURLs = false;
41 private boolean mAllowFileAccessFromFileURLs = false;
42 private boolean mJavaScriptCanOpenWindowsAutomatically = true;
43 private int mCacheMode = WebSettings.LOAD_DEFAULT;
44 private boolean mSupportMultipleWindows = false;
45 private boolean mAppCacheEnabled = true;
46 private boolean mDomStorageEnabled = true;
47 private boolean mDatabaseEnabled = true;
48 private boolean mUseWideViewport = false;
49 private boolean mMediaPlaybackRequiresUserGesture = false;
50 private String mDefaultVideoPosterURL;
52 // Not accessed by the native side.
53 private boolean mBlockNetworkLoads; // Default depends on permission of embedding APK.
54 private boolean mAllowContentUrlAccess = true;
55 private boolean mAllowFileUrlAccess = true;
56 private boolean mShouldFocusFirstNode = true;
57 private boolean mGeolocationEnabled = true;
58 private String mUserAgent;
60 // Protects access to settings global fields.
61 private static final Object sGlobalContentSettingsLock = new Object();
62 // For compatibility with the legacy WebView, we can only enable AppCache when the path is
63 // provided. However, we don't use the path, so we just check if we have received it from the
65 private static boolean sAppCachePathIsSet = false;
67 // The native side of this object.
68 private long mNativeXWalkSettings = 0;
70 // A flag to avoid sending superfluous synchronization messages.
71 private boolean mIsUpdateWebkitPrefsMessagePending = false;
72 // Custom handler that queues messages to call native code on the UI thread.
73 private final EventHandler mEventHandler;
75 private static final int MINIMUM_FONT_SIZE = 1;
76 private static final int MAXIMUM_FONT_SIZE = 72;
78 static class LazyDefaultUserAgent{
79 private static final String sInstance = nativeGetDefaultUserAgent();
82 // Class to handle messages to be processed on the UI thread.
83 private class EventHandler {
84 // Message id for updating Webkit preferences
85 private static final int UPDATE_WEBKIT_PREFERENCES = 0;
86 // Actual UI thread handler
87 private Handler mHandler;
93 if (mHandler != null) return;
94 mHandler = new Handler(ThreadUtils.getUiThreadLooper()) {
96 public void handleMessage(Message msg) {
98 case UPDATE_WEBKIT_PREFERENCES:
99 synchronized (mXWalkSettingsLock) {
100 updateWebkitPreferencesOnUiThread();
101 mIsUpdateWebkitPrefsMessagePending = false;
102 mXWalkSettingsLock.notifyAll();
110 void maybeRunOnUiThreadBlocking(Runnable r) {
111 if (mHandler != null) {
112 ThreadUtils.runOnUiThreadBlocking(r);
116 private void updateWebkitPreferencesLocked() {
117 assert Thread.holdsLock(mXWalkSettingsLock);
118 if (mNativeXWalkSettings == 0) return;
119 if (mHandler == null) return;
120 if (ThreadUtils.runningOnUiThread()) {
121 updateWebkitPreferencesOnUiThread();
123 // We're being called on a background thread, so post a message.
124 if (mIsUpdateWebkitPrefsMessagePending) {
127 mIsUpdateWebkitPrefsMessagePending = true;
128 mHandler.sendMessage(Message.obtain(null, UPDATE_WEBKIT_PREFERENCES));
129 // We must block until the settings have been sync'd to native to
130 // ensure that they have taken effect.
132 while (mIsUpdateWebkitPrefsMessagePending) {
133 mXWalkSettingsLock.wait();
135 } catch (InterruptedException e) {}
140 public XWalkSettings(Context context, long nativeWebContents,
141 boolean isAccessFromFileURLsGrantedByDefault) {
142 ThreadUtils.assertOnUiThread();
144 mBlockNetworkLoads = mContext.checkPermission(
145 android.Manifest.permission.INTERNET,
147 Process.myUid()) != PackageManager.PERMISSION_GRANTED;
149 if (isAccessFromFileURLsGrantedByDefault) {
150 mAllowUniversalAccessFromFileURLs = true;
151 mAllowFileAccessFromFileURLs = true;
154 mUserAgent = LazyDefaultUserAgent.sInstance;
156 mEventHandler = new EventHandler();
158 setWebContents(nativeWebContents);
161 void setWebContents(long nativeWebContents) {
162 synchronized (mXWalkSettingsLock) {
163 if (mNativeXWalkSettings != 0) {
164 nativeDestroy(mNativeXWalkSettings);
165 assert mNativeXWalkSettings == 0;
167 if (nativeWebContents != 0) {
168 mEventHandler.bindUiThread();
169 mNativeXWalkSettings = nativeInit(nativeWebContents);
170 nativeUpdateEverythingLocked(mNativeXWalkSettings);
176 private void nativeXWalkSettingsGone(long nativeXWalkSettings) {
177 assert mNativeXWalkSettings != 0 && mNativeXWalkSettings == nativeXWalkSettings;
178 mNativeXWalkSettings = 0;
181 public void setAllowScriptsToCloseWindows(boolean allow) {
182 synchronized (mXWalkSettingsLock) {
183 if (mAllowScriptsToCloseWindows != allow) {
184 mAllowScriptsToCloseWindows = allow;
189 public boolean getAllowScriptsToCloseWindows() {
190 synchronized (mXWalkSettingsLock) {
191 return mAllowScriptsToCloseWindows;
196 * See {@link android.webkit.WebSettings#setCacheMode}.
198 public void setCacheMode(int mode) {
199 synchronized (mXWalkSettingsLock) {
200 if (mCacheMode != mode) {
207 * See {@link android.webkit.WebSettings#getCacheMode}.
209 public int getCacheMode() {
210 synchronized (mXWalkSettingsLock) {
216 * See {@link android.webkit.WebSettings#setBlockNetworkLoads}.
218 public void setBlockNetworkLoads(boolean flag) {
219 synchronized (mXWalkSettingsLock) {
220 if (!flag && mContext.checkPermission(
221 android.Manifest.permission.INTERNET,
223 Process.myUid()) != PackageManager.PERMISSION_GRANTED) {
224 throw new SecurityException("Permission denied - " +
225 "application missing INTERNET permission");
227 mBlockNetworkLoads = flag;
232 * See {@link android.webkit.WebSettings#getBlockNetworkLoads}.
234 public boolean getBlockNetworkLoads() {
235 synchronized (mXWalkSettingsLock) {
236 return mBlockNetworkLoads;
241 * See {@link android.webkit.WebSettings#setAllowFileAccess}.
243 public void setAllowFileAccess(boolean allow) {
244 synchronized (mXWalkSettingsLock) {
245 if (mAllowFileUrlAccess != allow) {
246 mAllowFileUrlAccess = allow;
252 * See {@link android.webkit.WebSettings#getAllowFileAccess}.
254 public boolean getAllowFileAccess() {
255 synchronized (mXWalkSettingsLock) {
256 return mAllowFileUrlAccess;
261 * See {@link android.webkit.WebSettings#setAllowContentAccess}.
263 public void setAllowContentAccess(boolean allow) {
264 synchronized (mXWalkSettingsLock) {
265 if (mAllowContentUrlAccess != allow) {
266 mAllowContentUrlAccess = allow;
272 * See {@link android.webkit.WebSettings#getAllowContentAccess}.
274 public boolean getAllowContentAccess() {
275 synchronized (mXWalkSettingsLock) {
276 return mAllowContentUrlAccess;
281 * See {@link android.webkit.WebSettings#setGeolocationEnabled}.
283 public void setGeolocationEnabled(boolean flag) {
284 synchronized (mXWalkSettingsLock) {
285 if (mGeolocationEnabled != flag) {
286 mGeolocationEnabled = flag;
292 * @return Returns if geolocation is currently enabled.
294 boolean getGeolocationEnabled() {
295 synchronized (mXWalkSettingsLock) {
296 return mGeolocationEnabled;
301 * See {@link android.webkit.WebSettings#setJavaScriptEnabled}.
303 public void setJavaScriptEnabled(boolean flag) {
304 synchronized (mXWalkSettingsLock) {
305 if (mJavaScriptEnabled != flag) {
306 mJavaScriptEnabled = flag;
307 mEventHandler.updateWebkitPreferencesLocked();
313 * See {@link android.webkit.WebSettings#setAllowUniversalAccessFromFileURLs}.
315 public void setAllowUniversalAccessFromFileURLs(boolean flag) {
316 synchronized (mXWalkSettingsLock) {
317 if (mAllowUniversalAccessFromFileURLs != flag) {
318 mAllowUniversalAccessFromFileURLs = flag;
319 mEventHandler.updateWebkitPreferencesLocked();
325 * See {@link android.webkit.WebSettings#setAllowFileAccessFromFileURLs}.
327 public void setAllowFileAccessFromFileURLs(boolean flag) {
328 synchronized (mXWalkSettingsLock) {
329 if (mAllowFileAccessFromFileURLs != flag) {
330 mAllowFileAccessFromFileURLs = flag;
331 mEventHandler.updateWebkitPreferencesLocked();
337 * See {@link android.webkit.WebSettings#setLoadsImagesAutomatically}.
339 public void setLoadsImagesAutomatically(boolean flag) {
340 synchronized (mXWalkSettingsLock) {
341 if (mLoadsImagesAutomatically != flag) {
342 mLoadsImagesAutomatically = flag;
343 mEventHandler.updateWebkitPreferencesLocked();
349 * See {@link android.webkit.WebSettings#getLoadsImagesAutomatically}.
351 public boolean getLoadsImagesAutomatically() {
352 synchronized (mXWalkSettingsLock) {
353 return mLoadsImagesAutomatically;
358 * See {@link android.webkit.WebSettings#setImagesEnabled}.
360 public void setImagesEnabled(boolean flag) {
361 synchronized (mXWalkSettingsLock) {
362 if (mImagesEnabled != flag) {
363 mImagesEnabled = flag;
364 mEventHandler.updateWebkitPreferencesLocked();
370 * See {@link android.webkit.WebSettings#getImagesEnabled}.
372 public boolean getImagesEnabled() {
373 synchronized (mXWalkSettingsLock) {
374 return mImagesEnabled;
379 * See {@link android.webkit.WebSettings#getJavaScriptEnabled}.
381 public boolean getJavaScriptEnabled() {
382 synchronized (mXWalkSettingsLock) {
383 return mJavaScriptEnabled;
388 * See {@link android.webkit.WebSettings#getAllowUniversalAccessFromFileURLs}.
390 public boolean getAllowUniversalAccessFromFileURLs() {
391 synchronized (mXWalkSettingsLock) {
392 return mAllowUniversalAccessFromFileURLs;
397 * See {@link android.webkit.WebSettings#getAllowFileAccessFromFileURLs}.
399 public boolean getAllowFileAccessFromFileURLs() {
400 synchronized (mXWalkSettingsLock) {
401 return mAllowFileAccessFromFileURLs;
406 * See {@link android.webkit.WebSettings#setJavaScriptCanOpenWindowsAutomatically}.
408 public void setJavaScriptCanOpenWindowsAutomatically(boolean flag) {
409 synchronized (mXWalkSettingsLock) {
410 if (mJavaScriptCanOpenWindowsAutomatically != flag) {
411 mJavaScriptCanOpenWindowsAutomatically = flag;
412 mEventHandler.updateWebkitPreferencesLocked();
418 * See {@link android.webkit.WebSettings#getJavaScriptCanOpenWindowsAutomatically}.
420 public boolean getJavaScriptCanOpenWindowsAutomatically() {
421 synchronized (mXWalkSettingsLock) {
422 return mJavaScriptCanOpenWindowsAutomatically;
427 * See {@link android.webkit.WebSettings#setSupportMultipleWindows}.
429 public void setSupportMultipleWindows(boolean support) {
430 synchronized (mXWalkSettingsLock) {
431 if (mSupportMultipleWindows != support) {
432 mSupportMultipleWindows = support;
433 mEventHandler.updateWebkitPreferencesLocked();
439 * See {@link android.webkit.WebSettings#supportMultipleWindows}.
441 public boolean supportMultipleWindows() {
442 synchronized (mXWalkSettingsLock) {
443 return mSupportMultipleWindows;
448 * See {@link android.webkit.WebSettings#setUseWideViewPort}.
450 public void setUseWideViewPort(boolean use) {
451 synchronized (mXWalkSettingsLock) {
452 if (mUseWideViewport != use) {
453 mUseWideViewport = use;
454 mEventHandler.updateWebkitPreferencesLocked();
460 * See {@link android.webkit.WebSettings#getUseWideViewPort}.
462 public boolean getUseWideViewPort() {
463 synchronized (mXWalkSettingsLock) {
464 return mUseWideViewport;
469 * See {@link android.webkit.WebSettings#setAppCacheEnabled}.
471 public void setAppCacheEnabled(boolean flag) {
472 synchronized (mXWalkSettingsLock) {
473 if (mAppCacheEnabled != flag) {
474 mAppCacheEnabled = flag;
475 mEventHandler.updateWebkitPreferencesLocked();
481 * See {@link android.webkit.WebSettings#setAppCachePath}.
483 public void setAppCachePath(String path) {
484 boolean needToSync = false;
485 synchronized (sGlobalContentSettingsLock) {
486 // AppCachePath can only be set once.
487 if (!sAppCachePathIsSet && path != null && !path.isEmpty()) {
488 sAppCachePathIsSet = true;
492 // The obvious problem here is that other WebViews will not be updated,
493 // until they execute synchronization from Java to the native side.
494 // But this is the same behaviour as it was in the legacy WebView.
496 synchronized (mXWalkSettingsLock) {
497 mEventHandler.updateWebkitPreferencesLocked();
503 * Gets whether Application Cache is enabled.
505 * @return true if Application Cache is enabled
509 private boolean getAppCacheEnabled() {
510 // When no app cache path is set, use chromium default cache path.
511 return mAppCacheEnabled;
515 * See {@link android.webkit.WebSettings#setDomStorageEnabled}.
517 public void setDomStorageEnabled(boolean flag) {
518 synchronized (mXWalkSettingsLock) {
519 if (mDomStorageEnabled != flag) {
520 mDomStorageEnabled = flag;
521 mEventHandler.updateWebkitPreferencesLocked();
527 * See {@link android.webkit.WebSettings#getDomStorageEnabled}.
529 public boolean getDomStorageEnabled() {
530 synchronized (mXWalkSettingsLock) {
531 return mDomStorageEnabled;
536 * See {@link android.webkit.WebSettings#setDatabaseEnabled}.
538 public void setDatabaseEnabled(boolean flag) {
539 synchronized (mXWalkSettingsLock) {
540 if (mDatabaseEnabled != flag) {
541 mDatabaseEnabled = flag;
542 mEventHandler.updateWebkitPreferencesLocked();
548 * See {@link android.webkit.WebSettings#getDatabaseEnabled}.
550 public boolean getDatabaseEnabled() {
551 synchronized (mXWalkSettingsLock) {
552 return mDatabaseEnabled;
557 * See {@link android.webkit.WebSettings#setMediaPlaybackRequiresUserGesture}.
559 public void setMediaPlaybackRequiresUserGesture(boolean require) {
560 synchronized (mXWalkSettingsLock) {
561 if (mMediaPlaybackRequiresUserGesture != require) {
562 mMediaPlaybackRequiresUserGesture = require;
563 mEventHandler.updateWebkitPreferencesLocked();
569 * See {@link android.webkit.WebSettings#getMediaPlaybackRequiresUserGesture}.
571 public boolean getMediaPlaybackRequiresUserGesture() {
572 synchronized (mXWalkSettingsLock) {
573 return mMediaPlaybackRequiresUserGesture;
578 * See {@link android.webkit.WebSettings#setDefaultVideoPosterURL}.
580 public void setDefaultVideoPosterURL(String url) {
581 synchronized (mXWalkSettingsLock) {
582 if (mDefaultVideoPosterURL != null && !mDefaultVideoPosterURL.equals(url) ||
583 mDefaultVideoPosterURL == null && url != null) {
584 mDefaultVideoPosterURL = url;
585 mEventHandler.updateWebkitPreferencesLocked();
591 * @return returns the default User-Agent used by each ContentViewCore instance, i.e. unless
592 * overridden by {@link #setUserAgentString()}
594 public static String getDefaultUserAgent() {
595 return LazyDefaultUserAgent.sInstance;
599 * See {@link android.webkit.WebSettings#setUserAgentString}.
601 public void setUserAgentString(String ua) {
602 synchronized (mXWalkSettingsLock) {
603 final String oldUserAgent = mUserAgent;
604 if (ua == null || ua.length() == 0) {
605 mUserAgent = LazyDefaultUserAgent.sInstance;
609 if (!oldUserAgent.equals(mUserAgent)) {
610 mEventHandler.maybeRunOnUiThreadBlocking(new Runnable() {
613 if (mNativeXWalkSettings != 0) {
614 nativeUpdateUserAgent(mNativeXWalkSettings);
623 * See {@link android.webkit.WebSettings#getUserAgentString}.
625 public String getUserAgentString() {
626 synchronized (mXWalkSettingsLock) {
632 private String getUserAgentLocked() {
637 * See {@link android.webkit.WebSettings#getDefaultVideoPosterURL}.
639 public String getDefaultVideoPosterURL() {
640 synchronized (mXWalkSettingsLock) {
641 return mDefaultVideoPosterURL;
646 private void updateEverything() {
647 synchronized (mXWalkSettingsLock) {
648 nativeUpdateEverythingLocked(mNativeXWalkSettings);
652 private void updateWebkitPreferencesOnUiThread() {
653 if (mNativeXWalkSettings != 0) {
654 ThreadUtils.assertOnUiThread();
655 nativeUpdateWebkitPreferences(mNativeXWalkSettings);
659 private native long nativeInit(long webContentsPtr);
661 private native void nativeDestroy(long nativeXWalkSettings);
663 private static native String nativeGetDefaultUserAgent();
665 private native void nativeUpdateEverythingLocked(long nativeXWalkSettings);
667 private native void nativeUpdateUserAgent(long nativeXWalkSettings);
669 private native void nativeUpdateWebkitPreferences(long nativeXWalkSettings);