Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / xwalk / runtime / android / core_internal / src / org / xwalk / core / internal / XWalkContent.java
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Copyright (c) 2013-2014 Intel Corporation. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5
6 package org.xwalk.core.internal;
7
8 import android.app.Activity;
9 import android.content.Context;
10 import android.content.Intent;
11 import android.content.SharedPreferences;
12 import android.graphics.Rect;
13 import android.os.Build.VERSION;
14 import android.os.Build.VERSION_CODES;
15 import android.os.Bundle;
16 import android.view.View;
17 import android.view.WindowManager;
18 import android.text.TextUtils;
19 import android.util.AttributeSet;
20 import android.util.Log;
21 import android.view.ViewGroup;
22 import android.webkit.ValueCallback;
23 import android.webkit.WebResourceResponse;
24 import android.widget.FrameLayout;
25
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.lang.annotation.Annotation;
29
30 import org.chromium.base.CalledByNative;
31 import org.chromium.base.JNINamespace;
32 import org.chromium.base.ThreadUtils;
33 import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
34 import org.chromium.content.browser.ContentView;
35 import org.chromium.content.browser.ContentViewCore;
36 import org.chromium.content.browser.ContentViewRenderView;
37 import org.chromium.content.browser.ContentViewRenderView.CompositingSurfaceType;
38 import org.chromium.content.browser.ContentViewStatics;
39 import org.chromium.content.browser.LoadUrlParams;
40 import org.chromium.content.browser.NavigationHistory;
41 import org.chromium.content.common.CleanupReference;
42 import org.chromium.media.MediaPlayerBridge;
43 import org.chromium.ui.base.ActivityWindowAndroid;
44 import org.chromium.ui.gfx.DeviceDisplayInfo;
45
46 @JNINamespace("xwalk")
47 /**
48  * This class is the implementation class for XWalkViewInternal by calling internal
49  * various classes.
50  */
51 class XWalkContent extends FrameLayout implements XWalkPreferencesInternal.KeyValueChangeListener {
52     private static String TAG = "XWalkContent";
53     private static Class<? extends Annotation> javascriptInterfaceClass = null;
54
55     private ContentViewCore mContentViewCore;
56     private ContentView mContentView;
57     private ContentViewRenderView mContentViewRenderView;
58     private ActivityWindowAndroid mWindow;
59     private XWalkDevToolsServer mDevToolsServer;
60     private XWalkViewInternal mXWalkView;
61     private XWalkContentsClientBridge mContentsClientBridge;
62     private XWalkContentsIoThreadClient mIoThreadClient;
63     private XWalkWebContentsDelegateAdapter mXWalkContentsDelegateAdapter;
64     private XWalkSettings mSettings;
65     private XWalkGeolocationPermissions mGeolocationPermissions;
66     private XWalkLaunchScreenManager mLaunchScreenManager;
67
68     long mXWalkContent;
69     long mWebContents;
70
71     static void setJavascriptInterfaceClass(Class<? extends Annotation> clazz) {
72       assert(javascriptInterfaceClass == null);
73       javascriptInterfaceClass = clazz;
74     }
75
76     private static final class DestroyRunnable implements Runnable {
77         private final long mXWalkContent;
78         private DestroyRunnable(long nativeXWalkContent) {
79             mXWalkContent = nativeXWalkContent;
80         }
81
82         @Override
83         public void run() {
84             nativeDestroy(mXWalkContent);
85         }
86     }
87
88     // Reference to the active mXWalkContent pointer while it is active use
89     // (ie before it is destroyed).
90     private CleanupReference mCleanupReference;
91
92     public XWalkContent(Context context, AttributeSet attrs, XWalkViewInternal xwView) {
93         super(context, attrs);
94
95         // Initialize the WebContensDelegate.
96         mXWalkView = xwView;
97         mContentsClientBridge = new XWalkContentsClientBridge(mXWalkView);
98         mXWalkContentsDelegateAdapter = new XWalkWebContentsDelegateAdapter(
99             mContentsClientBridge);
100         mIoThreadClient = new XWalkIoThreadClientImpl();
101
102         // Initialize mWindow which is needed by content
103         mWindow = new ActivityWindowAndroid(xwView.getActivity());
104
105         // Initialize ContentViewRenderView
106         boolean animated = XWalkPreferencesInternal.getValue(XWalkPreferencesInternal.ANIMATABLE_XWALK_VIEW);
107         CompositingSurfaceType surfaceType =
108                 animated ? CompositingSurfaceType.TEXTURE_VIEW : CompositingSurfaceType.SURFACE_VIEW;
109         mContentViewRenderView = new ContentViewRenderView(context, surfaceType) {
110             protected void onReadyToRender() {
111                 // Anything depending on the underlying Surface readiness should
112                 // be placed here.
113             }
114         };
115         mContentViewRenderView.onNativeLibraryLoaded(mWindow);
116         mLaunchScreenManager = new XWalkLaunchScreenManager(context, mXWalkView);
117         mContentViewRenderView.registerFirstRenderedFrameListener(mLaunchScreenManager);
118         addView(mContentViewRenderView,
119                 new FrameLayout.LayoutParams(
120                         FrameLayout.LayoutParams.MATCH_PARENT,
121                         FrameLayout.LayoutParams.MATCH_PARENT));
122
123         mXWalkContent = nativeInit(mXWalkContentsDelegateAdapter, mContentsClientBridge);
124
125         // The native side object has been bound to this java instance, so now is the time to
126         // bind all the native->java relationships.
127         mCleanupReference = new CleanupReference(this, new DestroyRunnable(mXWalkContent));
128
129         mWebContents = nativeGetWebContents(mXWalkContent, mIoThreadClient,
130                 mContentsClientBridge.getInterceptNavigationDelegate());
131
132         // Initialize ContentView.
133         mContentViewCore = new ContentViewCore(getContext());
134         mContentView = ContentView.newInstance(getContext(), mContentViewCore);
135         mContentViewCore.initialize(mContentView, mContentView, mWebContents, mWindow);
136         addView(mContentView,
137                 new FrameLayout.LayoutParams(
138                         FrameLayout.LayoutParams.MATCH_PARENT,
139                         FrameLayout.LayoutParams.MATCH_PARENT));
140         mContentViewCore.setContentViewClient(mContentsClientBridge);
141         mContentViewRenderView.setCurrentContentViewCore(mContentViewCore);
142         // For addJavascriptInterface
143         mContentsClientBridge.installWebContentsObserver(mContentViewCore);
144
145         // Set DIP scale.
146         mContentsClientBridge.setDIPScale(DeviceDisplayInfo.create(context).getDIPScale());
147
148         mContentViewCore.setDownloadDelegate(mContentsClientBridge);
149
150         // Set the third argument isAccessFromFileURLsGrantedByDefault to false, so that
151         // the members mAllowUniversalAccessFromFileURLs and mAllowFileAccessFromFileURLs
152         // won't be changed from false to true at the same time in the constructor of
153         // XWalkSettings class.
154         mSettings = new XWalkSettings(getContext(), mWebContents, false);
155         // Enable AllowFileAccessFromFileURLs, so that files under file:// path could be
156         // loaded by XMLHttpRequest.
157         mSettings.setAllowFileAccessFromFileURLs(true);
158
159         SharedPreferences sharedPreferences = new InMemorySharedPreferences();
160         mGeolocationPermissions = new XWalkGeolocationPermissions(sharedPreferences);
161
162         MediaPlayerBridge.setResourceLoadingFilter(
163                 new XWalkMediaPlayerResourceLoadingFilter());
164
165         XWalkPreferencesInternal.load(this);
166     }
167
168     void doLoadUrl(String url, String content) {
169         // Handle the same url loading by parameters.
170         if (url != null && !url.isEmpty() &&
171                 TextUtils.equals(url, mContentViewCore.getUrl())) {
172             mContentViewCore.reload(true);
173         } else {
174             LoadUrlParams params = null;
175             if (content == null || content.isEmpty()) {
176                 params = new LoadUrlParams(url);
177             } else {
178                 params = LoadUrlParams.createLoadDataParamsWithBaseUrl(
179                         content, "text/html", false, url, null);
180             }
181             params.setOverrideUserAgent(LoadUrlParams.UA_OVERRIDE_TRUE);
182             mContentViewCore.loadUrl(params);
183         }
184
185         mContentView.requestFocus();
186     }
187
188     public void loadUrl(String url, String data) {
189         if ((url == null || url.isEmpty()) &&
190                 (data == null || data.isEmpty())) {
191             return;
192         }
193
194         doLoadUrl(url, data);
195     }
196
197     public void reload(int mode) {
198         switch (mode) {
199             case XWalkViewInternal.RELOAD_IGNORE_CACHE:
200                 mContentViewCore.reloadIgnoringCache(true);
201                 break;
202             case XWalkViewInternal.RELOAD_NORMAL:
203             default:
204                 mContentViewCore.reload(true);
205         }
206     }
207
208     public String getUrl() {
209         String url = mContentViewCore.getUrl();
210         if (url == null || url.trim().isEmpty()) return null;
211         return url;
212     }
213
214     public String getTitle() {
215         String title = mContentViewCore.getTitle().trim();
216         if (title == null) title = "";
217         return title;
218     }
219
220     public void addJavascriptInterface(Object object, String name) {
221         mContentViewCore.addPossiblyUnsafeJavascriptInterface(object, name,
222                 javascriptInterfaceClass);
223     }
224
225     public void evaluateJavascript(String script, ValueCallback<String> callback) {
226         final ValueCallback<String>  fCallback = callback;
227         ContentViewCore.JavaScriptCallback coreCallback = null;
228         if (fCallback != null) {
229             coreCallback = new ContentViewCore.JavaScriptCallback() {
230                 @Override
231                 public void handleJavaScriptResult(String jsonResult) {
232                     fCallback.onReceiveValue(jsonResult);
233                 }
234             };
235         }
236         mContentViewCore.evaluateJavaScript(script, coreCallback);
237     }
238
239     public void setUIClient(XWalkUIClientInternal client) {
240         mContentsClientBridge.setUIClient(client);
241     }
242
243     public void setResourceClient(XWalkResourceClientInternal client) {
244         mContentsClientBridge.setResourceClient(client);
245     }
246
247     public void setXWalkWebChromeClient(XWalkWebChromeClient client) {
248         mContentsClientBridge.setXWalkWebChromeClient(client);
249     }
250
251     public XWalkWebChromeClient getXWalkWebChromeClient() {
252         return mContentsClientBridge.getXWalkWebChromeClient();
253     }
254
255     public void setXWalkClient(XWalkClient client) {
256         mContentsClientBridge.setXWalkClient(client);
257     }
258
259     public void setDownloadListener(DownloadListener listener) {
260         mContentsClientBridge.setDownloadListener(listener);
261     }
262
263     public void setNavigationHandler(XWalkNavigationHandler handler) {
264         mContentsClientBridge.setNavigationHandler(handler);
265     }
266
267     public void setNotificationService(XWalkNotificationService service) {
268         mContentsClientBridge.setNotificationService(service);
269     }
270
271     public void onPause() {
272         mContentViewCore.onHide();
273     }
274
275     public void onResume() {
276         mContentViewCore.onShow();
277     }
278
279     public void onActivityResult(int requestCode, int resultCode, Intent data) {
280         mWindow.onActivityResult(requestCode, resultCode, data);
281     }
282
283     public boolean onNewIntent(Intent intent) {
284         return mContentsClientBridge.onNewIntent(intent);
285     }
286
287     public void clearCache(boolean includeDiskFiles) {
288         if (mXWalkContent == 0) return;
289         nativeClearCache(mXWalkContent, includeDiskFiles);
290     }
291
292     public void clearHistory() {
293         mContentViewCore.clearHistory();
294     }
295
296     public boolean canGoBack() {
297         return mContentViewCore.canGoBack();
298     }
299
300     public void goBack() {
301         mContentViewCore.goBack();
302     }
303
304     public boolean canGoForward() {
305         return mContentViewCore.canGoForward();
306     }
307
308     public void goForward() {
309         mContentViewCore.goForward();
310     }
311
312     void navigateTo(int offset)  {
313         mContentViewCore.goToOffset(offset);
314     }
315
316     public void stopLoading() {
317         mContentViewCore.stopLoading();
318         mContentsClientBridge.onStopLoading();
319     }
320
321     // Currently, timer pause/resume is actually
322     // a global setting. And multiple pause will fail the
323     // DCHECK in content (content_view_statics.cc:57).
324     // Here uses a static boolean to avoid this issue.
325     private static boolean timerPaused = false;
326
327     // TODO(Guangzhen): ContentViewStatics will be removed in upstream,
328     // details in content_view_statics.cc.
329     // We need follow up after upstream updates that.
330     public void pauseTimers() {
331         if (timerPaused) return;
332         ContentViewStatics.setWebKitSharedTimersSuspended(true);
333         timerPaused = true;
334     }
335
336     public void resumeTimers() {
337         if (!timerPaused) return;
338         ContentViewStatics.setWebKitSharedTimersSuspended(false);
339         timerPaused = false;
340     }
341
342     public String getOriginalUrl() {
343         NavigationHistory history = mContentViewCore.getNavigationHistory();
344         int currentIndex = history.getCurrentEntryIndex();
345         if (currentIndex >= 0 && currentIndex < history.getEntryCount()) {
346             return history.getEntryAtIndex(currentIndex).getOriginalUrl();
347         }
348         return null;
349     }
350
351     public String getXWalkVersion() {
352         if (mXWalkContent == 0) return "";
353         return nativeGetVersion(mXWalkContent);
354     }
355
356     public void setNetworkAvailable(boolean networkUp) {
357         if (mXWalkContent == 0) return;
358         nativeSetJsOnlineProperty(mXWalkContent, networkUp);
359     }
360
361     // For instrumentation test.
362     public ContentViewCore getContentViewCoreForTest() {
363         return mContentViewCore;
364     }
365
366     // For instrumentation test.
367     public void installWebContentsObserverForTest(XWalkContentsClient contentClient) {
368         contentClient.installWebContentsObserver(mContentViewCore);
369     }
370
371     public String devToolsAgentId() {
372         if (mXWalkContent == 0) return "";
373         return nativeDevToolsAgentId(mXWalkContent);
374     }
375
376     public XWalkSettings getSettings() {
377         return mSettings;
378     }
379
380     public void loadAppFromManifest(String url, String data) {
381         if (mXWalkContent == 0 ||
382                 ((url == null || url.isEmpty()) &&
383                         (data == null || data.isEmpty()))) {
384             return;
385         }
386
387         String content = data;
388         // If the data of manifest.json is not set, try to load it.
389         if (data == null || data.isEmpty()) {
390             try {
391                 content = AndroidProtocolHandler.getUrlContent(mXWalkView.getActivity(), url);
392             } catch (IOException e) {
393                 throw new RuntimeException("Failed to read the manifest: " + url);
394             }
395         }
396
397         // Calculate the base url of manifestUrl. Used by native side.
398         // TODO(yongsheng): It's from runtime side. Need to find a better way
399         // to get base url.
400         String baseUrl = url;
401         int position = url.lastIndexOf("/");
402         if (position != -1) {
403             baseUrl = url.substring(0, position + 1);
404         } else {
405             Log.w(TAG, "The url of manifest.json is probably not set correctly.");
406         }
407
408         if (!nativeSetManifest(mXWalkContent, baseUrl, content)) {
409             throw new RuntimeException("Failed to parse the manifest file: " + url);
410         }
411     }
412
413     public XWalkNavigationHistoryInternal getNavigationHistory() {
414         return new XWalkNavigationHistoryInternal(mXWalkView, mContentViewCore.getNavigationHistory());
415     }
416
417     public static final String SAVE_RESTORE_STATE_KEY = "XWALKVIEW_STATE";
418
419     public XWalkNavigationHistoryInternal saveState(Bundle outState) {
420         if (outState == null) return null;
421
422         byte[] state = nativeGetState(mXWalkContent);
423         if (state == null) return null;
424
425         outState.putByteArray(SAVE_RESTORE_STATE_KEY, state);
426         return getNavigationHistory();
427     }
428
429     public XWalkNavigationHistoryInternal restoreState(Bundle inState) {
430         if (inState == null) return null;
431
432         byte[] state = inState.getByteArray(SAVE_RESTORE_STATE_KEY);
433         if (state == null) return null;
434
435         boolean result = nativeSetState(mXWalkContent, state);
436
437         // The onUpdateTitle callback normally happens when a page is loaded,
438         // but is optimized out in the restoreState case because the title is
439         // already restored. See WebContentsImpl::UpdateTitleForEntry. So we
440         // call the callback explicitly here.
441         if (result) {
442             mContentsClientBridge.onUpdateTitle(mContentViewCore.getTitle());
443         }
444
445         return result ? getNavigationHistory() : null;
446     }
447
448     boolean hasEnteredFullscreen() {
449         return mContentsClientBridge.hasEnteredFullscreen();
450     }
451
452     void exitFullscreen() {
453         if (hasEnteredFullscreen()) {
454             mContentsClientBridge.exitFullscreen(mWebContents);
455         }
456     }
457
458     @CalledByNative
459     public void onGetUrlFromManifest(String url) {
460         if (url != null && !url.isEmpty()) {
461             loadUrl(url, null);
462         }
463     }
464
465     @CalledByNative
466     public void onGetUrlAndLaunchScreenFromManifest(String url, String readyWhen, String imageBorder) {
467         if (url == null || url.isEmpty()) return;
468         mLaunchScreenManager.displayLaunchScreen(readyWhen, imageBorder);
469         mContentsClientBridge.registerPageLoadListener(mLaunchScreenManager);
470         loadUrl(url, null);
471     }
472
473     @CalledByNative
474     public void onGetFullscreenFlagFromManifest(boolean enterFullscreen) {
475         if (enterFullscreen) {
476             if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
477                 View decorView = mXWalkView.getActivity().getWindow().getDecorView();
478                 decorView.setSystemUiVisibility(
479                         View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
480                         View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
481                         View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
482                         View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
483                         View.SYSTEM_UI_FLAG_FULLSCREEN |
484                         View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
485             } else {
486                 mXWalkView.getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
487             }
488         }
489     }
490
491     public void destroy() {
492         if (mXWalkContent == 0) return;
493
494         XWalkPreferencesInternal.unload(this);
495         // Reset existing notification service in order to destruct it.
496         setNotificationService(null);
497         // Remove its children used for page rendering from view hierarchy.
498         removeView(mContentView);
499         removeView(mContentViewRenderView);
500         mContentViewRenderView.setCurrentContentViewCore(null);
501
502         // Destroy the native resources.
503         mContentViewRenderView.destroy();
504         mContentViewCore.destroy();
505
506         mCleanupReference.cleanupNow();
507         mCleanupReference = null;
508         mXWalkContent = 0;
509     }
510
511     public int getRoutingID() {
512         return nativeGetRoutingID(mXWalkContent);
513     }
514
515     //--------------------------------------------------------------------------------------------
516     private class XWalkIoThreadClientImpl implements XWalkContentsIoThreadClient {
517         // All methods are called on the IO thread.
518
519         @Override
520         public int getCacheMode() {
521             return mSettings.getCacheMode();
522         }
523
524         @Override
525         public InterceptedRequestData shouldInterceptRequest(final String url,
526                 boolean isMainFrame) {
527
528             // Notify a resource load is started. This is not the best place to start the callback
529             // but it's a workable way.
530             mContentsClientBridge.getCallbackHelper().postOnResourceLoadStarted(url);
531
532             WebResourceResponse webResourceResponse = mContentsClientBridge.shouldInterceptRequest(url);
533             InterceptedRequestData interceptedRequestData = null;
534
535             if (webResourceResponse == null) {
536                 mContentsClientBridge.getCallbackHelper().postOnLoadResource(url);
537             } else {
538                 if (isMainFrame && webResourceResponse.getData() == null) {
539                     mContentsClientBridge.getCallbackHelper().postOnReceivedError(
540                             XWalkResourceClientInternal.ERROR_UNKNOWN, null, url);
541                 }
542                 interceptedRequestData = new InterceptedRequestData(webResourceResponse.getMimeType(),
543                                                                     webResourceResponse.getEncoding(),
544                                                                     webResourceResponse.getData());
545             }
546             return interceptedRequestData;
547         }
548
549         @Override
550         public boolean shouldBlockContentUrls() {
551             return !mSettings.getAllowContentAccess();
552         }
553
554         @Override
555         public boolean shouldBlockFileUrls() {
556             return !mSettings.getAllowFileAccess();
557         }
558
559         @Override
560         public boolean shouldBlockNetworkLoads() {
561             return mSettings.getBlockNetworkLoads();
562         }
563
564         @Override
565         public void onDownloadStart(String url,
566                                     String userAgent,
567                                     String contentDisposition,
568                                     String mimeType,
569                                     long contentLength) {
570             mContentsClientBridge.getCallbackHelper().postOnDownloadStart(url, userAgent,
571                     contentDisposition, mimeType, contentLength);
572         }
573
574         @Override
575         public void newLoginRequest(String realm, String account, String args) {
576             mContentsClientBridge.getCallbackHelper().postOnReceivedLoginRequest(realm, account, args);
577         }
578     }
579
580     private class XWalkGeolocationCallback implements XWalkGeolocationPermissions.Callback {
581         @Override
582         public void invoke(final String origin, final boolean allow, final boolean retain) {
583             ThreadUtils.runOnUiThread(new Runnable() {
584                 @Override
585                 public void run() {
586                     if (retain) {
587                         if (allow) {
588                             mGeolocationPermissions.allow(origin);
589                         } else {
590                             mGeolocationPermissions.deny(origin);
591                         }
592                     }
593                     nativeInvokeGeolocationCallback(mXWalkContent, allow, origin);
594                 }
595             });
596         }
597     }
598
599     @CalledByNative
600     private void onGeolocationPermissionsShowPrompt(String origin) {
601         // Reject if geolocation is disabled, or the origin has a retained deny.
602         if (!mSettings.getGeolocationEnabled()) {
603             nativeInvokeGeolocationCallback(mXWalkContent, false, origin);
604             return;
605         }
606         // Allow if the origin has a retained allow.
607         if (mGeolocationPermissions.hasOrigin(origin)) {
608             nativeInvokeGeolocationCallback(mXWalkContent,
609                     mGeolocationPermissions.isOriginAllowed(origin),
610                     origin);
611             return;
612         }
613         mContentsClientBridge.onGeolocationPermissionsShowPrompt(
614                 origin, new XWalkGeolocationCallback());
615     }
616
617     @CalledByNative
618     public void onGeolocationPermissionsHidePrompt() {
619         mContentsClientBridge.onGeolocationPermissionsHidePrompt();
620     }
621
622     public String enableRemoteDebugging(int allowedUid) {
623         // Chrome looks for "devtools_remote" pattern in the name of a unix domain socket
624         // to identify a debugging page
625         final String socketName = getContext().getApplicationContext().getPackageName() + "_devtools_remote";
626         if (mDevToolsServer == null) {
627             mDevToolsServer = new XWalkDevToolsServer(socketName);
628             mDevToolsServer.allowConnectionFromUid(allowedUid);
629             mDevToolsServer.setRemoteDebuggingEnabled(true);
630         }
631         // devtools/page is hardcoded in devtools_http_handler_impl.cc (kPageUrlPrefix)
632         return "ws://" + socketName + "/devtools/page/" + devToolsAgentId();
633     }
634
635     // Enables remote debugging and returns the URL at which the dev tools server is listening
636     // for commands. Only the current process is allowed to connect to the server.
637     String enableRemoteDebugging() {
638         return enableRemoteDebugging(getContext().getApplicationInfo().uid);
639     }
640
641     void disableRemoteDebugging() {
642         if (mDevToolsServer ==  null) return;
643
644         if (mDevToolsServer.isRemoteDebuggingEnabled()) {
645             mDevToolsServer.setRemoteDebuggingEnabled(false);
646         }
647         mDevToolsServer.destroy();
648         mDevToolsServer = null;
649     }
650
651     @Override
652     public void onKeyValueChanged(String key, boolean value) {
653         if (key == null) return;
654         if (key.equals(XWalkPreferencesInternal.REMOTE_DEBUGGING)) {
655             if (value) enableRemoteDebugging();
656             else disableRemoteDebugging();
657         } else if (key.equals(XWalkPreferencesInternal.ENABLE_JAVASCRIPT)) {
658             if (mSettings != null) mSettings.setJavaScriptEnabled(value);
659         } else if (key.equals(XWalkPreferencesInternal.JAVASCRIPT_CAN_OPEN_WINDOW)) {
660             if (mSettings != null) mSettings.setJavaScriptCanOpenWindowsAutomatically(value);
661         } else if (key.equals(XWalkPreferencesInternal.ALLOW_UNIVERSAL_ACCESS_FROM_FILE)) {
662             if (mSettings != null) mSettings.setAllowUniversalAccessFromFileURLs(value);
663         } else if (key.equals(XWalkPreferencesInternal.SUPPORT_MULTIPLE_WINDOWS)) {
664             if (mSettings != null) mSettings.setSupportMultipleWindows(value);
665         }
666     }
667
668     public void setOverlayVideoMode(boolean enabled) {
669         if (mContentViewRenderView != null) {
670             mContentViewRenderView.setOverlayVideoMode(enabled);
671         }
672     }
673
674     private native long nativeInit(XWalkWebContentsDelegate webViewContentsDelegate,
675             XWalkContentsClientBridge bridge);
676     private static native void nativeDestroy(long nativeXWalkContent);
677     private native long nativeGetWebContents(long nativeXWalkContent,
678             XWalkContentsIoThreadClient ioThreadClient,
679             InterceptNavigationDelegate delegate);
680     private native void nativeClearCache(long nativeXWalkContent, boolean includeDiskFiles);
681     private native String nativeDevToolsAgentId(long nativeXWalkContent);
682     private native String nativeGetVersion(long nativeXWalkContent);
683     private native void nativeSetJsOnlineProperty(long nativeXWalkContent, boolean networkUp);
684     private native boolean nativeSetManifest(long nativeXWalkContent, String path, String manifest);
685     private native int nativeGetRoutingID(long nativeXWalkContent);
686     private native void nativeInvokeGeolocationCallback(
687             long nativeXWalkContent, boolean value, String requestingFrame);
688     private native byte[] nativeGetState(long nativeXWalkContent);
689     private native boolean nativeSetState(long nativeXWalkContent, byte[] state);
690 }