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