Upstream version 6.35.131.0
[platform/framework/web/crosswalk.git] / src / xwalk / runtime / android / core / src / org / xwalk / core / XWalkSettings.java
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
5 package org.xwalk.core;
6
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;
14
15 import org.chromium.base.CalledByNative;
16 import org.chromium.base.JNINamespace;
17 import org.chromium.base.ThreadUtils;
18
19 /**
20  * @hide
21  */
22 @JNINamespace("xwalk")
23 public class XWalkSettings {
24
25     private static final String TAG = "XWalkSettings";
26
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.
30
31     // Lock to protect all settings.
32     private final Object mXWalkSettingsLock = new Object();
33
34     private final Context mContext;
35
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;
51
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;
59
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
64     // client.
65     private static boolean sAppCachePathIsSet = false;
66
67     // The native side of this object.
68     private long mNativeXWalkSettings = 0;
69
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;
74
75     private static final int MINIMUM_FONT_SIZE = 1;
76     private static final int MAXIMUM_FONT_SIZE = 72;
77
78     static class LazyDefaultUserAgent{
79         private static final String sInstance = nativeGetDefaultUserAgent();
80     }
81
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;
88
89         EventHandler() {
90         }
91
92         void bindUiThread() {
93             if (mHandler != null) return;
94             mHandler = new Handler(ThreadUtils.getUiThreadLooper()) {
95                     @Override
96                     public void handleMessage(Message msg) {
97                         switch (msg.what) {
98                             case UPDATE_WEBKIT_PREFERENCES:
99                                 synchronized (mXWalkSettingsLock) {
100                                     updateWebkitPreferencesOnUiThread();
101                                     mIsUpdateWebkitPrefsMessagePending = false;
102                                     mXWalkSettingsLock.notifyAll();
103                                 }
104                                 break;
105                         }
106                     }
107                 };
108         }
109
110         void maybeRunOnUiThreadBlocking(Runnable r) {
111             if (mHandler != null) {
112                 ThreadUtils.runOnUiThreadBlocking(r);
113             }
114         }
115
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();
122             } else {
123                 // We're being called on a background thread, so post a message.
124                 if (mIsUpdateWebkitPrefsMessagePending) {
125                     return;
126                 }
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.
131                 try {
132                     while (mIsUpdateWebkitPrefsMessagePending) {
133                         mXWalkSettingsLock.wait();
134                     }
135                 } catch (InterruptedException e) {}
136             }
137         }
138     }
139
140     public XWalkSettings(Context context, long nativeWebContents,
141             boolean isAccessFromFileURLsGrantedByDefault) {
142         ThreadUtils.assertOnUiThread();
143         mContext = context;
144         mBlockNetworkLoads = mContext.checkPermission(
145                 android.Manifest.permission.INTERNET,
146                 Process.myPid(),
147                 Process.myUid()) != PackageManager.PERMISSION_GRANTED;
148
149         if (isAccessFromFileURLsGrantedByDefault) {
150             mAllowUniversalAccessFromFileURLs = true;
151             mAllowFileAccessFromFileURLs = true;
152         }
153
154         mUserAgent = LazyDefaultUserAgent.sInstance;
155
156         mEventHandler = new EventHandler();
157
158         setWebContents(nativeWebContents);
159     }
160
161     void setWebContents(long nativeWebContents) {
162         synchronized (mXWalkSettingsLock) {
163             if (mNativeXWalkSettings != 0) {
164                 nativeDestroy(mNativeXWalkSettings);
165                 assert mNativeXWalkSettings == 0;
166             }
167             if (nativeWebContents != 0) {
168                 mEventHandler.bindUiThread();
169                 mNativeXWalkSettings = nativeInit(nativeWebContents);
170                 nativeUpdateEverythingLocked(mNativeXWalkSettings);
171             }
172         }
173     }
174
175     @CalledByNative
176     private void nativeXWalkSettingsGone(long nativeXWalkSettings) {
177         assert mNativeXWalkSettings != 0 && mNativeXWalkSettings == nativeXWalkSettings;
178         mNativeXWalkSettings = 0;
179     }
180
181     public void setAllowScriptsToCloseWindows(boolean allow) {
182         synchronized (mXWalkSettingsLock) {
183             if (mAllowScriptsToCloseWindows != allow) {
184                 mAllowScriptsToCloseWindows = allow;
185             }
186         }
187     }
188
189     public boolean getAllowScriptsToCloseWindows() {
190         synchronized (mXWalkSettingsLock) {
191             return mAllowScriptsToCloseWindows;
192         }
193     }
194
195     /**
196      * See {@link android.webkit.WebSettings#setCacheMode}.
197      */
198     public void setCacheMode(int mode) {
199         synchronized (mXWalkSettingsLock) {
200             if (mCacheMode != mode) {
201                 mCacheMode = mode;
202             }
203         }
204     }
205
206     /**
207      * See {@link android.webkit.WebSettings#getCacheMode}.
208      */
209     public int getCacheMode() {
210         synchronized (mXWalkSettingsLock) {
211             return mCacheMode;
212         }
213     }
214
215     /**
216      * See {@link android.webkit.WebSettings#setBlockNetworkLoads}.
217      */
218     public void setBlockNetworkLoads(boolean flag) {
219         synchronized (mXWalkSettingsLock) {
220             if (!flag && mContext.checkPermission(
221                     android.Manifest.permission.INTERNET,
222                     Process.myPid(),
223                     Process.myUid()) != PackageManager.PERMISSION_GRANTED) {
224                 throw new SecurityException("Permission denied - " +
225                         "application missing INTERNET permission");
226             }
227             mBlockNetworkLoads = flag;
228         }
229     }
230
231     /**
232      * See {@link android.webkit.WebSettings#getBlockNetworkLoads}.
233      */
234     public boolean getBlockNetworkLoads() {
235         synchronized (mXWalkSettingsLock) {
236             return mBlockNetworkLoads;
237         }
238     }
239
240     /**
241      * See {@link android.webkit.WebSettings#setAllowFileAccess}.
242      */
243     public void setAllowFileAccess(boolean allow) {
244         synchronized (mXWalkSettingsLock) {
245             if (mAllowFileUrlAccess != allow) {
246                 mAllowFileUrlAccess = allow;
247             }
248         }
249     }
250
251     /**
252      * See {@link android.webkit.WebSettings#getAllowFileAccess}.
253      */
254     public boolean getAllowFileAccess() {
255         synchronized (mXWalkSettingsLock) {
256             return mAllowFileUrlAccess;
257         }
258     }
259
260     /**
261      * See {@link android.webkit.WebSettings#setAllowContentAccess}.
262      */
263     public void setAllowContentAccess(boolean allow) {
264         synchronized (mXWalkSettingsLock) {
265             if (mAllowContentUrlAccess != allow) {
266                 mAllowContentUrlAccess = allow;
267             }
268         }
269     }
270
271     /**
272      * See {@link android.webkit.WebSettings#getAllowContentAccess}.
273      */
274     public boolean getAllowContentAccess() {
275         synchronized (mXWalkSettingsLock) {
276             return mAllowContentUrlAccess;
277         }
278     }
279
280     /**
281      * See {@link android.webkit.WebSettings#setGeolocationEnabled}.
282      */
283     public void setGeolocationEnabled(boolean flag) {
284         synchronized (mXWalkSettingsLock) {
285             if (mGeolocationEnabled != flag) {
286                 mGeolocationEnabled = flag;
287             }
288         }
289     }
290
291     /**
292      * @return Returns if geolocation is currently enabled.
293      */
294     boolean getGeolocationEnabled() {
295         synchronized (mXWalkSettingsLock) {
296             return mGeolocationEnabled;
297         }
298     }
299
300     /**
301      * See {@link android.webkit.WebSettings#setJavaScriptEnabled}.
302      */
303     public void setJavaScriptEnabled(boolean flag) {
304         synchronized (mXWalkSettingsLock) {
305             if (mJavaScriptEnabled != flag) {
306                 mJavaScriptEnabled = flag;
307                 mEventHandler.updateWebkitPreferencesLocked();
308             }
309         }
310     }
311
312     /**
313      * See {@link android.webkit.WebSettings#setAllowUniversalAccessFromFileURLs}.
314      */
315     public void setAllowUniversalAccessFromFileURLs(boolean flag) {
316         synchronized (mXWalkSettingsLock) {
317             if (mAllowUniversalAccessFromFileURLs != flag) {
318                 mAllowUniversalAccessFromFileURLs = flag;
319                 mEventHandler.updateWebkitPreferencesLocked();
320             }
321         }
322     }
323
324     /**
325      * See {@link android.webkit.WebSettings#setAllowFileAccessFromFileURLs}.
326      */
327     public void setAllowFileAccessFromFileURLs(boolean flag) {
328         synchronized (mXWalkSettingsLock) {
329             if (mAllowFileAccessFromFileURLs != flag) {
330                 mAllowFileAccessFromFileURLs = flag;
331                 mEventHandler.updateWebkitPreferencesLocked();
332             }
333         }
334     }
335
336     /**
337      * See {@link android.webkit.WebSettings#setLoadsImagesAutomatically}.
338      */
339     public void setLoadsImagesAutomatically(boolean flag) {
340         synchronized (mXWalkSettingsLock) {
341             if (mLoadsImagesAutomatically != flag) {
342                 mLoadsImagesAutomatically = flag;
343                 mEventHandler.updateWebkitPreferencesLocked();
344             }
345         }
346     }
347
348     /**
349      * See {@link android.webkit.WebSettings#getLoadsImagesAutomatically}.
350      */
351     public boolean getLoadsImagesAutomatically() {
352         synchronized (mXWalkSettingsLock) {
353             return mLoadsImagesAutomatically;
354         }
355     }
356
357     /**
358      * See {@link android.webkit.WebSettings#setImagesEnabled}.
359      */
360     public void setImagesEnabled(boolean flag) {
361         synchronized (mXWalkSettingsLock) {
362             if (mImagesEnabled != flag) {
363                 mImagesEnabled = flag;
364                 mEventHandler.updateWebkitPreferencesLocked();
365             }
366         }
367     }
368
369     /**
370      * See {@link android.webkit.WebSettings#getImagesEnabled}.
371      */
372     public boolean getImagesEnabled() {
373         synchronized (mXWalkSettingsLock) {
374             return mImagesEnabled;
375         }
376     }
377
378     /**
379      * See {@link android.webkit.WebSettings#getJavaScriptEnabled}.
380      */
381     public boolean getJavaScriptEnabled() {
382         synchronized (mXWalkSettingsLock) {
383             return mJavaScriptEnabled;
384         }
385     }
386
387     /**
388      * See {@link android.webkit.WebSettings#getAllowUniversalAccessFromFileURLs}.
389      */
390     public boolean getAllowUniversalAccessFromFileURLs() {
391         synchronized (mXWalkSettingsLock) {
392             return mAllowUniversalAccessFromFileURLs;
393         }
394     }
395
396     /**
397      * See {@link android.webkit.WebSettings#getAllowFileAccessFromFileURLs}.
398      */
399     public boolean getAllowFileAccessFromFileURLs() {
400         synchronized (mXWalkSettingsLock) {
401             return mAllowFileAccessFromFileURLs;
402         }
403     }
404
405     /**
406      * See {@link android.webkit.WebSettings#setJavaScriptCanOpenWindowsAutomatically}.
407      */
408     public void setJavaScriptCanOpenWindowsAutomatically(boolean flag) {
409         synchronized (mXWalkSettingsLock) {
410             if (mJavaScriptCanOpenWindowsAutomatically != flag) {
411                 mJavaScriptCanOpenWindowsAutomatically = flag;
412                 mEventHandler.updateWebkitPreferencesLocked();
413             }
414         }
415     }
416
417     /**
418      * See {@link android.webkit.WebSettings#getJavaScriptCanOpenWindowsAutomatically}.
419      */
420     public boolean getJavaScriptCanOpenWindowsAutomatically() {
421         synchronized (mXWalkSettingsLock) {
422             return mJavaScriptCanOpenWindowsAutomatically;
423         }
424     }
425
426     /**
427      * See {@link android.webkit.WebSettings#setSupportMultipleWindows}.
428      */
429     public void setSupportMultipleWindows(boolean support) {
430         synchronized (mXWalkSettingsLock) {
431             if (mSupportMultipleWindows != support) {
432                 mSupportMultipleWindows = support;
433                 mEventHandler.updateWebkitPreferencesLocked();
434             }
435         }
436     }
437
438     /**
439      * See {@link android.webkit.WebSettings#supportMultipleWindows}.
440      */
441     public boolean supportMultipleWindows() {
442         synchronized (mXWalkSettingsLock) {
443             return mSupportMultipleWindows;
444         }
445     }
446
447     /**
448      * See {@link android.webkit.WebSettings#setUseWideViewPort}.
449      */
450     public void setUseWideViewPort(boolean use) {
451         synchronized (mXWalkSettingsLock) {
452             if (mUseWideViewport != use) {
453                 mUseWideViewport = use;
454                 mEventHandler.updateWebkitPreferencesLocked();
455             }
456         }
457     }
458
459     /**
460      * See {@link android.webkit.WebSettings#getUseWideViewPort}.
461      */
462     public boolean getUseWideViewPort() {
463         synchronized (mXWalkSettingsLock) {
464             return mUseWideViewport;
465         }
466     }
467
468     /**
469      * See {@link android.webkit.WebSettings#setAppCacheEnabled}.
470      */
471     public void setAppCacheEnabled(boolean flag) {
472         synchronized (mXWalkSettingsLock) {
473             if (mAppCacheEnabled != flag) {
474                 mAppCacheEnabled = flag;
475                 mEventHandler.updateWebkitPreferencesLocked();
476             }
477         }
478     }
479
480     /**
481      * See {@link android.webkit.WebSettings#setAppCachePath}.
482      */
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;
489                 needToSync = true;
490             }
491         }
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.
495         if (needToSync) {
496             synchronized (mXWalkSettingsLock) {
497                 mEventHandler.updateWebkitPreferencesLocked();
498             }
499         }
500     }
501
502     /**
503      * Gets whether Application Cache is enabled.
504      *
505      * @return true if Application Cache is enabled
506      * @hide
507      */
508     @CalledByNative
509     private boolean getAppCacheEnabled() {
510         // When no app cache path is set, use chromium default cache path.
511         return mAppCacheEnabled;
512     }
513
514     /**
515      * See {@link android.webkit.WebSettings#setDomStorageEnabled}.
516      */
517     public void setDomStorageEnabled(boolean flag) {
518         synchronized (mXWalkSettingsLock) {
519             if (mDomStorageEnabled != flag) {
520                 mDomStorageEnabled = flag;
521                 mEventHandler.updateWebkitPreferencesLocked();
522             }
523         }
524     }
525
526     /**
527      * See {@link android.webkit.WebSettings#getDomStorageEnabled}.
528      */
529     public boolean getDomStorageEnabled() {
530        synchronized (mXWalkSettingsLock) {
531            return mDomStorageEnabled;
532        }
533     }
534
535     /**
536      * See {@link android.webkit.WebSettings#setDatabaseEnabled}.
537      */
538     public void setDatabaseEnabled(boolean flag) {
539         synchronized (mXWalkSettingsLock) {
540             if (mDatabaseEnabled != flag) {
541                 mDatabaseEnabled = flag;
542                 mEventHandler.updateWebkitPreferencesLocked();
543             }
544         }
545     }
546
547     /**
548      * See {@link android.webkit.WebSettings#getDatabaseEnabled}.
549      */
550     public boolean getDatabaseEnabled() {
551        synchronized (mXWalkSettingsLock) {
552            return mDatabaseEnabled;
553        }
554     }
555
556     /**
557      * See {@link android.webkit.WebSettings#setMediaPlaybackRequiresUserGesture}.
558      */
559     public void setMediaPlaybackRequiresUserGesture(boolean require) {
560         synchronized (mXWalkSettingsLock) {
561             if (mMediaPlaybackRequiresUserGesture != require) {
562                 mMediaPlaybackRequiresUserGesture = require;
563                 mEventHandler.updateWebkitPreferencesLocked();
564             }
565         }
566     }
567
568     /**
569      * See {@link android.webkit.WebSettings#getMediaPlaybackRequiresUserGesture}.
570      */
571     public boolean getMediaPlaybackRequiresUserGesture() {
572         synchronized (mXWalkSettingsLock) {
573             return mMediaPlaybackRequiresUserGesture;
574         }
575     }
576
577     /**
578      * See {@link android.webkit.WebSettings#setDefaultVideoPosterURL}.
579      */
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();
586             }
587         }
588     }
589
590     /**
591      * @return returns the default User-Agent used by each ContentViewCore instance, i.e. unless
592      * overridden by {@link #setUserAgentString()}
593      */
594     public static String getDefaultUserAgent() {
595         return LazyDefaultUserAgent.sInstance;
596     }
597
598     /**
599      * See {@link android.webkit.WebSettings#setUserAgentString}.
600      */
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;
606             } else {
607                 mUserAgent = ua;
608             }
609             if (!oldUserAgent.equals(mUserAgent)) {
610                 mEventHandler.maybeRunOnUiThreadBlocking(new Runnable() {
611                     @Override
612                     public void run() {
613                         if (mNativeXWalkSettings != 0) {
614                             nativeUpdateUserAgent(mNativeXWalkSettings);
615                         }
616                     }
617                 });
618             }
619         }
620     }
621
622     /**
623      * See {@link android.webkit.WebSettings#getUserAgentString}.
624      */
625     public String getUserAgentString() {
626         synchronized (mXWalkSettingsLock) {
627             return mUserAgent;
628         }
629     }
630
631     @CalledByNative
632     private String getUserAgentLocked() {
633         return mUserAgent;
634     }
635
636     /**
637      * See {@link android.webkit.WebSettings#getDefaultVideoPosterURL}.
638      */
639     public String getDefaultVideoPosterURL() {
640         synchronized (mXWalkSettingsLock) {
641             return mDefaultVideoPosterURL;
642         }
643     }
644
645     @CalledByNative
646     private void updateEverything() {
647         synchronized (mXWalkSettingsLock) {
648             nativeUpdateEverythingLocked(mNativeXWalkSettings);
649         }
650     }
651
652     private void updateWebkitPreferencesOnUiThread() {
653         if (mNativeXWalkSettings != 0) {
654             ThreadUtils.assertOnUiThread();
655             nativeUpdateWebkitPreferences(mNativeXWalkSettings);
656         }
657     }
658
659     private native long nativeInit(long webContentsPtr);
660
661     private native void nativeDestroy(long nativeXWalkSettings);
662
663     private static native String nativeGetDefaultUserAgent();
664
665     private native void nativeUpdateEverythingLocked(long nativeXWalkSettings);
666
667     private native void nativeUpdateUserAgent(long nativeXWalkSettings);
668
669     private native void nativeUpdateWebkitPreferences(long nativeXWalkSettings);
670 }