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