Upstream version 5.34.97.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 @JNINamespace("xwalk")
20 public class XWalkSettings {
21
22     private static final String TAG = "XWalkSettings";
23
24     // This class must be created on the UI thread. Afterwards, it can be
25     // used from any thread. Internally, the class uses a message queue
26     // to call native code on the UI thread only.
27
28     // Lock to protect all settings.
29     private final Object mXWalkSettingsLock = new Object();
30
31     private final Context mContext;
32
33     private boolean mAllowScriptsToCloseWindows = true;
34     private boolean mLoadsImagesAutomatically = true;
35     private boolean mImagesEnabled = true;
36     private boolean mJavaScriptEnabled = true;
37     private boolean mAllowUniversalAccessFromFileURLs = false;
38     private boolean mAllowFileAccessFromFileURLs = false;
39     private boolean mJavaScriptCanOpenWindowsAutomatically = true;
40     private int mCacheMode = WebSettings.LOAD_DEFAULT;
41     private boolean mSupportMultipleWindows = false;
42     private boolean mAppCacheEnabled = true;
43     private boolean mDomStorageEnabled = true;
44     private boolean mDatabaseEnabled = true;
45     private boolean mUseWideViewport = false;
46     private boolean mMediaPlaybackRequiresUserGesture = false;
47     private String mDefaultVideoPosterURL;
48
49     // Not accessed by the native side.
50     private boolean mBlockNetworkLoads;  // Default depends on permission of embedding APK.
51     private boolean mAllowContentUrlAccess = true;
52     private boolean mAllowFileUrlAccess = true;
53     private boolean mShouldFocusFirstNode = true;
54     private boolean mGeolocationEnabled = true;
55     private String mUserAgent;
56
57     // Protects access to settings global fields.
58     private static final Object sGlobalContentSettingsLock = new Object();
59     // For compatibility with the legacy WebView, we can only enable AppCache when the path is
60     // provided. However, we don't use the path, so we just check if we have received it from the
61     // client.
62     private static boolean sAppCachePathIsSet = false;
63
64     // The native side of this object.
65     private int mNativeXWalkSettings = 0;
66
67     // A flag to avoid sending superfluous synchronization messages.
68     private boolean mIsUpdateWebkitPrefsMessagePending = false;
69     // Custom handler that queues messages to call native code on the UI thread.
70     private final EventHandler mEventHandler;
71
72     private static final int MINIMUM_FONT_SIZE = 1;
73     private static final int MAXIMUM_FONT_SIZE = 72;
74
75     static class LazyDefaultUserAgent{
76         private static final String sInstance = nativeGetDefaultUserAgent();
77     }
78
79     // Class to handle messages to be processed on the UI thread.
80     private class EventHandler {
81         // Message id for updating Webkit preferences
82         private static final int UPDATE_WEBKIT_PREFERENCES = 0;
83         // Actual UI thread handler
84         private Handler mHandler;
85
86         EventHandler() {
87         }
88
89         void bindUiThread() {
90             if (mHandler != null) return;
91             mHandler = new Handler(ThreadUtils.getUiThreadLooper()) {
92                     @Override
93                     public void handleMessage(Message msg) {
94                         switch (msg.what) {
95                             case UPDATE_WEBKIT_PREFERENCES:
96                                 synchronized (mXWalkSettingsLock) {
97                                     updateWebkitPreferencesOnUiThread();
98                                     mIsUpdateWebkitPrefsMessagePending = false;
99                                     mXWalkSettingsLock.notifyAll();
100                                 }
101                                 break;
102                         }
103                     }
104                 };
105         }
106
107         void maybeRunOnUiThreadBlocking(Runnable r) {
108             if (mHandler != null) {
109                 ThreadUtils.runOnUiThreadBlocking(r);
110             }
111         }
112
113         private void updateWebkitPreferencesLocked() {
114             assert Thread.holdsLock(mXWalkSettingsLock);
115             if (mNativeXWalkSettings == 0) return;
116             if (mHandler == null) return;
117             if (ThreadUtils.runningOnUiThread()) {
118                 updateWebkitPreferencesOnUiThread();
119             } else {
120                 // We're being called on a background thread, so post a message.
121                 if (mIsUpdateWebkitPrefsMessagePending) {
122                     return;
123                 }
124                 mIsUpdateWebkitPrefsMessagePending = true;
125                 mHandler.sendMessage(Message.obtain(null, UPDATE_WEBKIT_PREFERENCES));
126                 // We must block until the settings have been sync'd to native to
127                 // ensure that they have taken effect.
128                 try {
129                     while (mIsUpdateWebkitPrefsMessagePending) {
130                         mXWalkSettingsLock.wait();
131                     }
132                 } catch (InterruptedException e) {}
133             }
134         }
135     }
136
137     public XWalkSettings(Context context, int nativeWebContents,
138             boolean isAccessFromFileURLsGrantedByDefault) {
139         ThreadUtils.assertOnUiThread();
140         mContext = context;
141         mBlockNetworkLoads = mContext.checkPermission(
142                 android.Manifest.permission.INTERNET,
143                 Process.myPid(),
144                 Process.myUid()) != PackageManager.PERMISSION_GRANTED;
145
146         if (isAccessFromFileURLsGrantedByDefault) {
147             mAllowUniversalAccessFromFileURLs = true;
148             mAllowFileAccessFromFileURLs = true;
149         }
150
151         mUserAgent = LazyDefaultUserAgent.sInstance;
152
153         mEventHandler = new EventHandler();
154
155         setWebContents(nativeWebContents);
156     }
157
158     void setWebContents(int nativeWebContents) {
159         synchronized (mXWalkSettingsLock) {
160             if (mNativeXWalkSettings != 0) {
161                 nativeDestroy(mNativeXWalkSettings);
162                 assert mNativeXWalkSettings == 0;
163             }
164             if (nativeWebContents != 0) {
165                 mEventHandler.bindUiThread();
166                 mNativeXWalkSettings = nativeInit(nativeWebContents);
167                 nativeUpdateEverythingLocked(mNativeXWalkSettings);
168             }
169         }
170     }
171
172     @CalledByNative
173     private void nativeXWalkSettingsGone(int nativeXWalkSettings) {
174         assert mNativeXWalkSettings != 0 && mNativeXWalkSettings == nativeXWalkSettings;
175         mNativeXWalkSettings = 0;
176     }
177
178     public void setAllowScriptsToCloseWindows(boolean allow) {
179         synchronized (mXWalkSettingsLock) {
180             if (mAllowScriptsToCloseWindows != allow) {
181                 mAllowScriptsToCloseWindows = allow;
182             }
183         }
184     }
185
186     public boolean getAllowScriptsToCloseWindows() {
187         synchronized (mXWalkSettingsLock) {
188             return mAllowScriptsToCloseWindows;
189         }
190     }
191
192     /**
193      * See {@link android.webkit.WebSettings#setCacheMode}.
194      */
195     public void setCacheMode(int mode) {
196         synchronized (mXWalkSettingsLock) {
197             if (mCacheMode != mode) {
198                 mCacheMode = mode;
199             }
200         }
201     }
202
203     /**
204      * See {@link android.webkit.WebSettings#getCacheMode}.
205      */
206     public int getCacheMode() {
207         synchronized (mXWalkSettingsLock) {
208             return mCacheMode;
209         }
210     }
211
212     /**
213      * See {@link android.webkit.WebSettings#setBlockNetworkLoads}.
214      */
215     public void setBlockNetworkLoads(boolean flag) {
216         synchronized (mXWalkSettingsLock) {
217             if (!flag && mContext.checkPermission(
218                     android.Manifest.permission.INTERNET,
219                     Process.myPid(),
220                     Process.myUid()) != PackageManager.PERMISSION_GRANTED) {
221                 throw new SecurityException("Permission denied - " +
222                         "application missing INTERNET permission");
223             }
224             mBlockNetworkLoads = flag;
225         }
226     }
227
228     /**
229      * See {@link android.webkit.WebSettings#getBlockNetworkLoads}.
230      */
231     public boolean getBlockNetworkLoads() {
232         synchronized (mXWalkSettingsLock) {
233             return mBlockNetworkLoads;
234         }
235     }
236
237     /**
238      * See {@link android.webkit.WebSettings#setAllowFileAccess}.
239      */
240     public void setAllowFileAccess(boolean allow) {
241         synchronized (mXWalkSettingsLock) {
242             if (mAllowFileUrlAccess != allow) {
243                 mAllowFileUrlAccess = allow;
244             }
245         }
246     }
247
248     /**
249      * See {@link android.webkit.WebSettings#getAllowFileAccess}.
250      */
251     public boolean getAllowFileAccess() {
252         synchronized (mXWalkSettingsLock) {
253             return mAllowFileUrlAccess;
254         }
255     }
256
257     /**
258      * See {@link android.webkit.WebSettings#setAllowContentAccess}.
259      */
260     public void setAllowContentAccess(boolean allow) {
261         synchronized (mXWalkSettingsLock) {
262             if (mAllowContentUrlAccess != allow) {
263                 mAllowContentUrlAccess = allow;
264             }
265         }
266     }
267
268     /**
269      * See {@link android.webkit.WebSettings#getAllowContentAccess}.
270      */
271     public boolean getAllowContentAccess() {
272         synchronized (mXWalkSettingsLock) {
273             return mAllowContentUrlAccess;
274         }
275     }
276
277     /**
278      * See {@link android.webkit.WebSettings#setGeolocationEnabled}.
279      */
280     public void setGeolocationEnabled(boolean flag) {
281         synchronized (mXWalkSettingsLock) {
282             if (mGeolocationEnabled != flag) {
283                 mGeolocationEnabled = flag;
284             }
285         }
286     }
287
288     /**
289      * @return Returns if geolocation is currently enabled.
290      */
291     boolean getGeolocationEnabled() {
292         synchronized (mXWalkSettingsLock) {
293             return mGeolocationEnabled;
294         }
295     }
296
297     /**
298      * See {@link android.webkit.WebSettings#setJavaScriptEnabled}.
299      */
300     public void setJavaScriptEnabled(boolean flag) {
301         synchronized (mXWalkSettingsLock) {
302             if (mJavaScriptEnabled != flag) {
303                 mJavaScriptEnabled = flag;
304                 mEventHandler.updateWebkitPreferencesLocked();
305             }
306         }
307     }
308
309     /**
310      * See {@link android.webkit.WebSettings#setAllowUniversalAccessFromFileURLs}.
311      */
312     public void setAllowUniversalAccessFromFileURLs(boolean flag) {
313         synchronized (mXWalkSettingsLock) {
314             if (mAllowUniversalAccessFromFileURLs != flag) {
315                 mAllowUniversalAccessFromFileURLs = flag;
316                 mEventHandler.updateWebkitPreferencesLocked();
317             }
318         }
319     }
320
321     /**
322      * See {@link android.webkit.WebSettings#setAllowFileAccessFromFileURLs}.
323      */
324     public void setAllowFileAccessFromFileURLs(boolean flag) {
325         synchronized (mXWalkSettingsLock) {
326             if (mAllowFileAccessFromFileURLs != flag) {
327                 mAllowFileAccessFromFileURLs = flag;
328                 mEventHandler.updateWebkitPreferencesLocked();
329             }
330         }
331     }
332
333     /**
334      * See {@link android.webkit.WebSettings#setLoadsImagesAutomatically}.
335      */
336     public void setLoadsImagesAutomatically(boolean flag) {
337         synchronized (mXWalkSettingsLock) {
338             if (mLoadsImagesAutomatically != flag) {
339                 mLoadsImagesAutomatically = flag;
340                 mEventHandler.updateWebkitPreferencesLocked();
341             }
342         }
343     }
344
345     /**
346      * See {@link android.webkit.WebSettings#getLoadsImagesAutomatically}.
347      */
348     public boolean getLoadsImagesAutomatically() {
349         synchronized (mXWalkSettingsLock) {
350             return mLoadsImagesAutomatically;
351         }
352     }
353
354     /**
355      * See {@link android.webkit.WebSettings#setImagesEnabled}.
356      */
357     public void setImagesEnabled(boolean flag) {
358         synchronized (mXWalkSettingsLock) {
359             if (mImagesEnabled != flag) {
360                 mImagesEnabled = flag;
361                 mEventHandler.updateWebkitPreferencesLocked();
362             }
363         }
364     }
365
366     /**
367      * See {@link android.webkit.WebSettings#getImagesEnabled}.
368      */
369     public boolean getImagesEnabled() {
370         synchronized (mXWalkSettingsLock) {
371             return mImagesEnabled;
372         }
373     }
374
375     /**
376      * See {@link android.webkit.WebSettings#getJavaScriptEnabled}.
377      */
378     public boolean getJavaScriptEnabled() {
379         synchronized (mXWalkSettingsLock) {
380             return mJavaScriptEnabled;
381         }
382     }
383
384     /**
385      * See {@link android.webkit.WebSettings#getAllowUniversalAccessFromFileURLs}.
386      */
387     public boolean getAllowUniversalAccessFromFileURLs() {
388         synchronized (mXWalkSettingsLock) {
389             return mAllowUniversalAccessFromFileURLs;
390         }
391     }
392
393     /**
394      * See {@link android.webkit.WebSettings#getAllowFileAccessFromFileURLs}.
395      */
396     public boolean getAllowFileAccessFromFileURLs() {
397         synchronized (mXWalkSettingsLock) {
398             return mAllowFileAccessFromFileURLs;
399         }
400     }
401
402     /**
403      * See {@link android.webkit.WebSettings#setJavaScriptCanOpenWindowsAutomatically}.
404      */
405     public void setJavaScriptCanOpenWindowsAutomatically(boolean flag) {
406         synchronized (mXWalkSettingsLock) {
407             if (mJavaScriptCanOpenWindowsAutomatically != flag) {
408                 mJavaScriptCanOpenWindowsAutomatically = flag;
409                 mEventHandler.updateWebkitPreferencesLocked();
410             }
411         }
412     }
413
414     /**
415      * See {@link android.webkit.WebSettings#getJavaScriptCanOpenWindowsAutomatically}.
416      */
417     public boolean getJavaScriptCanOpenWindowsAutomatically() {
418         synchronized (mXWalkSettingsLock) {
419             return mJavaScriptCanOpenWindowsAutomatically;
420         }
421     }
422
423     /**
424      * See {@link android.webkit.WebSettings#setSupportMultipleWindows}.
425      */
426     public void setSupportMultipleWindows(boolean support) {
427         synchronized (mXWalkSettingsLock) {
428             if (mSupportMultipleWindows != support) {
429                 mSupportMultipleWindows = support;
430                 mEventHandler.updateWebkitPreferencesLocked();
431             }
432         }
433     }
434
435     /**
436      * See {@link android.webkit.WebSettings#supportMultipleWindows}.
437      */
438     public boolean supportMultipleWindows() {
439         synchronized (mXWalkSettingsLock) {
440             return mSupportMultipleWindows;
441         }
442     }
443
444     /**
445      * See {@link android.webkit.WebSettings#setUseWideViewPort}.
446      */
447     public void setUseWideViewPort(boolean use) {
448         synchronized (mXWalkSettingsLock) {
449             if (mUseWideViewport != use) {
450                 mUseWideViewport = use;
451                 mEventHandler.updateWebkitPreferencesLocked();
452             }
453         }
454     }
455
456     /**
457      * See {@link android.webkit.WebSettings#getUseWideViewPort}.
458      */
459     public boolean getUseWideViewPort() {
460         synchronized (mXWalkSettingsLock) {
461             return mUseWideViewport;
462         }
463     }
464
465     /**
466      * See {@link android.webkit.WebSettings#setAppCacheEnabled}.
467      */
468     public void setAppCacheEnabled(boolean flag) {
469         synchronized (mXWalkSettingsLock) {
470             if (mAppCacheEnabled != flag) {
471                 mAppCacheEnabled = flag;
472                 mEventHandler.updateWebkitPreferencesLocked();
473             }
474         }
475     }
476
477     /**
478      * See {@link android.webkit.WebSettings#setAppCachePath}.
479      */
480     public void setAppCachePath(String path) {
481         boolean needToSync = false;
482         synchronized (sGlobalContentSettingsLock) {
483             // AppCachePath can only be set once.
484             if (!sAppCachePathIsSet && path != null && !path.isEmpty()) {
485                 sAppCachePathIsSet = true;
486                 needToSync = true;
487             }
488         }
489         // The obvious problem here is that other WebViews will not be updated,
490         // until they execute synchronization from Java to the native side.
491         // But this is the same behaviour as it was in the legacy WebView.
492         if (needToSync) {
493             synchronized (mXWalkSettingsLock) {
494                 mEventHandler.updateWebkitPreferencesLocked();
495             }
496         }
497     }
498
499     /**
500      * Gets whether Application Cache is enabled.
501      *
502      * @return true if Application Cache is enabled
503      * @hide
504      */
505     @CalledByNative
506     private boolean getAppCacheEnabled() {
507         // This should only be called from UpdateWebkitPreferences, which is called
508         // either from the constructor, or with mXWalkSettingsLock being held.
509         if (!mAppCacheEnabled) {
510             return false;
511         }
512         synchronized (sGlobalContentSettingsLock) {
513             return sAppCachePathIsSet;
514         }
515     }
516
517     /**
518      * See {@link android.webkit.WebSettings#setDomStorageEnabled}.
519      */
520     public void setDomStorageEnabled(boolean flag) {
521         synchronized (mXWalkSettingsLock) {
522             if (mDomStorageEnabled != flag) {
523                 mDomStorageEnabled = flag;
524                 mEventHandler.updateWebkitPreferencesLocked();
525             }
526         }
527     }
528
529     /**
530      * See {@link android.webkit.WebSettings#getDomStorageEnabled}.
531      */
532     public boolean getDomStorageEnabled() {
533        synchronized (mXWalkSettingsLock) {
534            return mDomStorageEnabled;
535        }
536     }
537
538     /**
539      * See {@link android.webkit.WebSettings#setDatabaseEnabled}.
540      */
541     public void setDatabaseEnabled(boolean flag) {
542         synchronized (mXWalkSettingsLock) {
543             if (mDatabaseEnabled != flag) {
544                 mDatabaseEnabled = flag;
545                 mEventHandler.updateWebkitPreferencesLocked();
546             }
547         }
548     }
549
550     /**
551      * See {@link android.webkit.WebSettings#getDatabaseEnabled}.
552      */
553     public boolean getDatabaseEnabled() {
554        synchronized (mXWalkSettingsLock) {
555            return mDatabaseEnabled;
556        }
557     }
558
559     /**
560      * See {@link android.webkit.WebSettings#setMediaPlaybackRequiresUserGesture}.
561      */
562     public void setMediaPlaybackRequiresUserGesture(boolean require) {
563         synchronized (mXWalkSettingsLock) {
564             if (mMediaPlaybackRequiresUserGesture != require) {
565                 mMediaPlaybackRequiresUserGesture = require;
566                 mEventHandler.updateWebkitPreferencesLocked();
567             }
568         }
569     }
570
571     /**
572      * See {@link android.webkit.WebSettings#getMediaPlaybackRequiresUserGesture}.
573      */
574     public boolean getMediaPlaybackRequiresUserGesture() {
575         synchronized (mXWalkSettingsLock) {
576             return mMediaPlaybackRequiresUserGesture;
577         }
578     }
579
580     /**
581      * See {@link android.webkit.WebSettings#setDefaultVideoPosterURL}.
582      */
583     public void setDefaultVideoPosterURL(String url) {
584         synchronized (mXWalkSettingsLock) {
585             if (mDefaultVideoPosterURL != null && !mDefaultVideoPosterURL.equals(url) ||
586                     mDefaultVideoPosterURL == null && url != null) {
587                 mDefaultVideoPosterURL = url;
588                 mEventHandler.updateWebkitPreferencesLocked();
589             }
590         }
591     }
592
593     /**
594      * @returns the default User-Agent used by each ContentViewCore instance, i.e. unless
595      * overridden by {@link #setUserAgentString()}
596      */
597     public static String getDefaultUserAgent() {
598         return LazyDefaultUserAgent.sInstance;
599     }
600
601     /**
602      * See {@link android.webkit.WebSettings#setUserAgentString}.
603      */
604     public void setUserAgentString(String ua) {
605         synchronized (mXWalkSettingsLock) {
606             final String oldUserAgent = mUserAgent;
607             if (ua == null || ua.length() == 0) {
608                 mUserAgent = LazyDefaultUserAgent.sInstance;
609             } else {
610                 mUserAgent = ua;
611             }
612             if (!oldUserAgent.equals(mUserAgent)) {
613                 mEventHandler.maybeRunOnUiThreadBlocking(new Runnable() {
614                     @Override
615                     public void run() {
616                         if (mNativeXWalkSettings != 0) {
617                             nativeUpdateUserAgent(mNativeXWalkSettings);
618                         }
619                     }
620                 });
621             }
622         }
623     }
624
625     /**
626      * See {@link android.webkit.WebSettings#getUserAgentString}.
627      */
628     public String getUserAgentString() {
629         synchronized (mXWalkSettingsLock) {
630             return mUserAgent;
631         }
632     }
633
634     @CalledByNative
635     private String getUserAgentLocked() {
636         return mUserAgent;
637     }
638
639     /**
640      * See {@link android.webkit.WebSettings#getDefaultVideoPosterURL}.
641      */
642     public String getDefaultVideoPosterURL() {
643         synchronized (mXWalkSettingsLock) {
644             return mDefaultVideoPosterURL;
645         }
646     }
647
648     @CalledByNative
649     private void updateEverything() {
650         synchronized (mXWalkSettingsLock) {
651             nativeUpdateEverythingLocked(mNativeXWalkSettings);
652         }
653     }
654
655     private void updateWebkitPreferencesOnUiThread() {
656         if (mNativeXWalkSettings != 0) {
657             ThreadUtils.assertOnUiThread();
658             nativeUpdateWebkitPreferences(mNativeXWalkSettings);
659         }
660     }
661
662     private native int nativeInit(int webContentsPtr);
663
664     private native void nativeDestroy(int nativeXWalkSettings);
665
666     private static native String nativeGetDefaultUserAgent();
667
668     private native void nativeUpdateEverythingLocked(int nativeXWalkSettings);
669
670     private native void nativeUpdateUserAgent(int nativeXWalkSettings);
671
672     private native void nativeUpdateWebkitPreferences(int nativeXWalkSettings);
673 }