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