Upstream version 8.36.169.0
[platform/framework/web/crosswalk.git] / src / xwalk / runtime / android / core_internal / src / org / xwalk / core / internal / XWalkContentsClientBridge.java
1 // Copyright (c) 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.content.ActivityNotFoundException;
9 import android.content.ContentResolver;
10 import android.content.Intent;
11 import android.database.Cursor;
12 import android.graphics.Bitmap;
13 import android.graphics.Picture;
14 import android.net.Uri;
15 import android.net.http.SslCertificate;
16 import android.net.http.SslError;
17 import android.os.Message;
18 import android.provider.MediaStore;
19 import android.util.Log;
20 import android.view.KeyEvent;
21 import android.view.View;
22 import android.webkit.ConsoleMessage;
23 import android.webkit.ValueCallback;
24 import android.webkit.WebResourceResponse;
25
26 import org.chromium.base.CalledByNative;
27 import org.chromium.base.JNINamespace;
28 import org.chromium.base.ThreadUtils;
29 import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
30 import org.chromium.components.navigation_interception.NavigationParams;
31 import org.chromium.content.browser.ContentVideoViewClient;
32 import org.chromium.content.browser.ContentViewDownloadDelegate;
33 import org.chromium.content.browser.DownloadInfo;
34 import org.xwalk.core.internal.XWalkUIClientInternal.LoadStatusInternal;
35
36 // Help bridge callback in XWalkContentsClient to XWalkViewClient and
37 // XWalkWebChromeClient; Also handle the JNI conmmunication logic.
38 @JNINamespace("xwalk")
39 class XWalkContentsClientBridge extends XWalkContentsClient
40         implements ContentViewDownloadDelegate {
41         private static final String TAG = XWalkContentsClientBridge.class.getName();
42
43     private XWalkViewInternal mXWalkView;
44     private XWalkUIClientInternal mXWalkUIClient;
45     private XWalkResourceClientInternal mXWalkResourceClient;
46     private XWalkClient mXWalkClient;
47     private XWalkWebChromeClient mXWalkWebChromeClient;
48     private Bitmap mFavicon;
49     private DownloadListener mDownloadListener;
50     private InterceptNavigationDelegate mInterceptNavigationDelegate;
51     private PageLoadListener mPageLoadListener;
52     private XWalkNavigationHandler mNavigationHandler;
53     private XWalkNotificationService mNotificationService;
54
55     /** State recording variables */
56     // For fullscreen state.
57     private boolean mIsFullscreen = false;
58     // For load state.
59     private LoadStatusInternal mLoadStatus = LoadStatusInternal.FINISHED;
60     private String mLoadingUrl = null;
61
62     // The native peer of the object
63     private long mNativeContentsClientBridge;
64
65     private class InterceptNavigationDelegateImpl implements InterceptNavigationDelegate {
66         private XWalkContentsClient mContentsClient;
67
68         public InterceptNavigationDelegateImpl(XWalkContentsClient client) {
69             mContentsClient = client;
70         }
71
72         public boolean shouldIgnoreNavigation(NavigationParams navigationParams) {
73             final String url = navigationParams.url;
74             boolean ignoreNavigation = shouldOverrideUrlLoading(url) ||
75                      (mNavigationHandler != null &&
76                       mNavigationHandler.handleNavigation(navigationParams));
77
78             if (!ignoreNavigation) {
79                 // Post a message to UI thread to notify the page is starting to load.
80                 mContentsClient.getCallbackHelper().postOnPageStarted(url);
81             }
82
83             return ignoreNavigation;
84         }
85     }
86
87     public XWalkContentsClientBridge(XWalkViewInternal xwView) {
88         mXWalkView = xwView;
89
90         mInterceptNavigationDelegate = new InterceptNavigationDelegateImpl(this);
91     }
92
93     public void setUIClient(XWalkUIClientInternal client) {
94         // If it's null, use Crosswalk implementation.
95         if (client != null) {
96             mXWalkUIClient = client;
97             return;
98         }
99         mXWalkUIClient = new XWalkUIClientInternal(mXWalkView);
100     }
101
102     public void setResourceClient(XWalkResourceClientInternal client) {
103         // If it's null, use Crosswalk implementation.
104         if (client != null) {
105             mXWalkResourceClient = client;
106             return;
107         }
108         mXWalkResourceClient = new XWalkResourceClientInternal(mXWalkView);
109     }
110
111
112     public void setXWalkWebChromeClient(XWalkWebChromeClient client) {
113         // If it's null, use Crosswalk implementation.
114         if (client == null) return;
115         client.setContentsClient(this);
116         mXWalkWebChromeClient = client;
117     }
118
119     public XWalkWebChromeClient getXWalkWebChromeClient() {
120         return mXWalkWebChromeClient;
121     }
122
123     public void setXWalkClient(XWalkClient client) {
124         mXWalkClient = client;
125     }
126
127     public void setNavigationHandler(XWalkNavigationHandler handler) {
128         mNavigationHandler = handler;
129     }
130
131     void registerPageLoadListener(PageLoadListener listener) {
132         mPageLoadListener = listener;
133     }
134
135     public void setNotificationService(XWalkNotificationService service) {
136         if (mNotificationService != null) mNotificationService.shutdown();
137         mNotificationService = service;
138         if (mNotificationService != null) mNotificationService.setBridge(this);
139     }
140
141     public boolean onNewIntent(Intent intent) {
142         return mNotificationService.maybeHandleIntent(intent);
143     }
144
145     public InterceptNavigationDelegate getInterceptNavigationDelegate() {
146         return mInterceptNavigationDelegate;
147     }
148
149     private boolean isOwnerActivityRunning() {
150         if (mXWalkView != null && mXWalkView.isOwnerActivityRunning()) {
151             return true;
152         }
153         return false;
154     }
155
156     // TODO(Xingnan): All the empty functions need to be implemented.
157     @Override
158     public boolean shouldOverrideUrlLoading(String url) {
159         if (mXWalkResourceClient != null && mXWalkView != null) {
160             return mXWalkResourceClient.shouldOverrideUrlLoading(mXWalkView, url);
161         }
162         return false;
163     }
164
165     @Override
166     public boolean shouldOverrideKeyEvent(KeyEvent event) {
167         boolean overridden = false;
168         if (mXWalkUIClient != null && mXWalkView != null) {
169             overridden = mXWalkUIClient.shouldOverrideKeyEvent(mXWalkView, event);
170         }
171         if (!overridden) {
172             return super.shouldOverrideKeyEvent(event);
173         }
174         return overridden;
175     }
176
177     @Override
178     public void onUnhandledKeyEvent(KeyEvent event) {
179         if (mXWalkUIClient != null && mXWalkView != null) {
180             mXWalkUIClient.onUnhandledKeyEvent(mXWalkView, event);
181         }
182     }
183
184     @Override
185     public void getVisitedHistory(ValueCallback<String[]> callback) {
186     }
187
188     @Override
189     public void doUpdateVisitedHistory(String url, boolean isReload) {
190     }
191
192     @Override
193     public void onProgressChanged(int progress) {
194         if (isOwnerActivityRunning()) {
195             mXWalkResourceClient.onProgressChanged(mXWalkView, progress);
196         }
197     }
198
199     @Override
200     public WebResourceResponse shouldInterceptRequest(String url) {
201         if (isOwnerActivityRunning()) {
202             return mXWalkResourceClient.shouldInterceptLoadRequest(mXWalkView, url);
203         }
204         return null;
205     }
206
207     @Override
208     public void onResourceLoadStarted(String url) {
209         if (isOwnerActivityRunning()) {
210             mXWalkResourceClient.onLoadStarted(mXWalkView, url);
211         }
212     }
213
214     @Override
215     public void onResourceLoadFinished(String url) {
216         if (isOwnerActivityRunning()) {
217             mXWalkResourceClient.onLoadFinished(mXWalkView, url);
218         }
219     }
220
221     @Override
222     public void onLoadResource(String url) {
223         if (mXWalkClient != null && isOwnerActivityRunning()) {
224             mXWalkClient.onLoadResource(mXWalkView, url);
225         }
226     }
227
228     @Override
229     public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
230         return false;
231     }
232
233     @CalledByNative
234     public void onReceivedHttpAuthRequest(XWalkHttpAuthHandler handler, String host, String realm) {
235         if (mXWalkClient != null && isOwnerActivityRunning()) {
236             mXWalkClient.onReceivedHttpAuthRequest(mXWalkView, handler, host, realm);
237         }
238     }
239
240     @Override
241     public void onReceivedSslError(ValueCallback<Boolean> callback, SslError error) {
242         if (mXWalkClient != null && isOwnerActivityRunning()) {
243             mXWalkClient.onReceivedSslError(mXWalkView, callback, error);
244         }
245     }
246
247     @Override
248     public void onReceivedLoginRequest(String realm, String account, String args) {
249     }
250
251     @Override
252     public void onGeolocationPermissionsShowPrompt(String origin,
253             XWalkGeolocationPermissions.Callback callback) {
254         if (mXWalkWebChromeClient != null && isOwnerActivityRunning()) {
255             mXWalkWebChromeClient.onGeolocationPermissionsShowPrompt(origin, callback);
256         }
257     }
258
259     @Override
260     public void onGeolocationPermissionsHidePrompt() {
261         if (mXWalkWebChromeClient != null && isOwnerActivityRunning()) {
262             mXWalkWebChromeClient.onGeolocationPermissionsHidePrompt();
263         }
264     }
265
266     @Override
267     public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
268             boolean isDoneCounting) {
269     }
270
271     @Override
272     public void onNewPicture(Picture picture) {
273     }
274
275     @Override
276     public void onPageStarted(String url) {
277         if (mXWalkUIClient != null && isOwnerActivityRunning()) {
278             mLoadingUrl = url;
279             mLoadStatus = LoadStatusInternal.FINISHED;
280             mXWalkUIClient.onPageLoadStarted(mXWalkView, url);
281         }
282     }
283
284     @Override
285     public void onPageFinished(String url) {
286         if (!isOwnerActivityRunning()) return;
287         if (mPageLoadListener != null) mPageLoadListener.onPageFinished(url);
288         if (mXWalkUIClient != null) {
289             if (mLoadStatus == LoadStatusInternal.CANCELLED && mLoadingUrl != null) {
290                 mXWalkUIClient.onPageLoadStopped(mXWalkView, mLoadingUrl, mLoadStatus);
291             } else {
292                 mXWalkUIClient.onPageLoadStopped(mXWalkView, url, mLoadStatus);
293             }
294             mLoadingUrl = null;
295         }
296
297         // This isn't the accurate point to notify a resource loading is finished,
298         // but it's a workable way. We could enhance this by extending Content
299         // API in future if we have the demand.
300         onResourceLoadFinished(url);
301     }
302
303     @Override
304     protected void onStopLoading() {
305         mLoadStatus = LoadStatusInternal.CANCELLED;
306     }
307
308     @Override
309     public void onReceivedError(int errorCode, String description, String failingUrl) {
310         if (isOwnerActivityRunning()) {
311             if (mLoadingUrl != null && mLoadingUrl.equals(failingUrl)) {
312                 mLoadStatus = LoadStatusInternal.FAILED;
313             }
314             mXWalkResourceClient.onReceivedLoadError(mXWalkView, errorCode, description, failingUrl);
315         }
316     }
317
318     @Override
319     public void onRendererUnresponsive() {
320         if (mXWalkClient != null && isOwnerActivityRunning()) {
321             mXWalkClient.onRendererUnresponsive(mXWalkView);
322         }
323     }
324
325     @Override
326     public void onRendererResponsive() {
327         if (mXWalkClient != null && isOwnerActivityRunning()) {
328             mXWalkClient.onRendererResponsive(mXWalkView);
329         }
330     }
331
332     @Override
333     public void onFormResubmission(Message dontResend, Message resend) {
334         dontResend.sendToTarget();
335     }
336
337     @Override
338     public void onDownloadStart(String url,
339                                 String userAgent,
340                                 String contentDisposition,
341                                 String mimeType,
342                                 long contentLength) {
343     }
344
345     @Override
346     public boolean onCreateWindow(boolean isDialog, boolean isUserGesture) {
347         return false;
348     }
349
350     @Override
351     public void onRequestFocus() {
352         if (isOwnerActivityRunning()) {
353             mXWalkUIClient.onRequestFocus(mXWalkView);
354         }
355     }
356
357     @Override
358     public void onCloseWindow() {
359         if (isOwnerActivityRunning()) {
360             mXWalkUIClient.onJavascriptCloseWindow(mXWalkView);
361         }
362     }
363
364     @Override
365     public void onReceivedIcon(Bitmap bitmap) {
366         if (mXWalkWebChromeClient != null && mXWalkView != null) {
367             mXWalkWebChromeClient.onReceivedIcon(mXWalkView, bitmap);
368         }
369         mFavicon = bitmap;
370     }
371
372     @Override
373     public void onShowCustomView(View view, XWalkWebChromeClient.CustomViewCallback callback) {
374         if (mXWalkWebChromeClient != null && isOwnerActivityRunning()) {
375             mXWalkWebChromeClient.onShowCustomView(view, callback);
376         }
377     }
378
379     @Override
380     public void onHideCustomView() {
381         if (mXWalkWebChromeClient != null && isOwnerActivityRunning()) {
382             mXWalkWebChromeClient.onHideCustomView();
383         }
384     }
385
386     @Override
387     public void onScaleChangedScaled(float oldScale, float newScale) {
388         if (isOwnerActivityRunning()) {
389             mXWalkUIClient.onScaleChanged(mXWalkView, oldScale, newScale);
390         }
391     }
392
393     @Override
394     public void didFinishLoad(String url) {
395     }
396
397     @Override
398     public void onTitleChanged(String title) {
399         if (mXWalkUIClient != null && isOwnerActivityRunning()) {
400             mXWalkUIClient.onReceivedTitle(mXWalkView, title);
401         }
402     }
403
404     @Override
405     public void onToggleFullscreen(boolean enterFullscreen) {
406         if (isOwnerActivityRunning()) {
407             mIsFullscreen = enterFullscreen;
408             mXWalkUIClient.onFullscreenToggled(mXWalkView, enterFullscreen);
409         }
410     }
411
412     @Override
413     public boolean hasEnteredFullscreen() {
414         return mIsFullscreen;
415     }
416
417     @Override
418     public boolean shouldOpenWithDefaultBrowser(String contentUrl) {
419         Intent intent = new Intent();
420         intent.setAction("android.intent.action.VIEW");
421         Uri url = Uri.parse(contentUrl);
422         intent.setData(url);
423         try {
424             mXWalkView.getActivity().startActivity(intent);
425         } catch (ActivityNotFoundException exception) {
426             Log.w(TAG, "Activity not found for Intent:");
427             return false;
428         }
429
430         return true;
431     }
432
433     @Override
434     public boolean shouldOverrideRunFileChooser(
435             final int processId, final int renderId, final int modeFlags,
436             String acceptTypes, boolean capture) {
437         if (!isOwnerActivityRunning()) return false;
438         abstract class UriCallback implements ValueCallback<Uri> {
439             boolean syncNullReceived = false;
440             boolean syncCallFinished = false;
441             protected String resolveFileName(Uri uri, ContentResolver contentResolver) {
442                 if (contentResolver == null || uri == null) return "";
443                 Cursor cursor = null;
444                 try {
445                     cursor = contentResolver.query(uri, null, null, null, null);
446
447                     if (cursor != null && cursor.getCount() >= 1) {
448                         cursor.moveToFirst();
449                         int index = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
450                         if (index > -1) return cursor.getString(index);
451                     }
452                 } catch (NullPointerException e) {
453                     // Some android models don't handle the provider call correctly.
454                     // see crbug.com/345393
455                     return "";
456                 } finally {
457                     if (cursor != null) cursor.close();
458                 }
459                 return "";
460             }
461         }
462         UriCallback uploadFile = new UriCallback() {
463             boolean completed = false;
464             @Override
465             public void onReceiveValue(Uri value) {
466                 if (completed) {
467                     throw new IllegalStateException("Duplicate openFileChooser result");
468                 }
469                 completed = true;
470                 if (value == null && !syncCallFinished) {
471                     syncNullReceived = true;
472                     return;
473                 }
474                 if (value == null) {
475                     nativeOnFilesNotSelected(mNativeContentsClientBridge,
476                             processId, renderId, modeFlags);
477                 } else {
478                     String result = "";
479                     String displayName = null;
480                     if (ContentResolver.SCHEME_FILE.equals(value.getScheme())) {
481                         result = value.getSchemeSpecificPart();
482                         displayName = value.getLastPathSegment();
483                     } else if (ContentResolver.SCHEME_CONTENT.equals(value.getScheme())) {
484                         result = value.toString();
485                         displayName = resolveFileName(
486                                 value, mXWalkView.getActivity().getContentResolver());
487                     } else {
488                         result = value.getPath();
489                         displayName = value.getLastPathSegment();
490                     }
491                     if (displayName == null || displayName.isEmpty()) displayName = result;
492                     nativeOnFilesSelected(mNativeContentsClientBridge,
493                             processId, renderId, modeFlags, result, displayName);
494                 }
495             }
496         };
497         mXWalkUIClient.openFileChooser(
498                 mXWalkView, uploadFile, acceptTypes, Boolean.toString(capture));
499         uploadFile.syncCallFinished = true;
500         // File chooser requires user interaction, valid derives should handle it in async process.
501         // If the ValueCallback receive a sync result with null value, it is considered the
502         // file chooser is not overridden.
503         return !uploadFile.syncNullReceived;
504     }
505
506     @Override
507     public ContentVideoViewClient getContentVideoViewClient() {
508         return new XWalkContentVideoViewClient(this, mXWalkView.getActivity(), mXWalkView);
509     }
510
511     // Used by the native peer to set/reset a weak ref to the native peer.
512     @CalledByNative
513     private void setNativeContentsClientBridge(long nativeContentsClientBridge) {
514         mNativeContentsClientBridge = nativeContentsClientBridge;
515     }
516
517     // If returns false, the request is immediately canceled, and any call to proceedSslError
518     // has no effect. If returns true, the request should be canceled or proceeded using
519     // proceedSslError().
520     // Unlike the webview classic, we do not keep keep a database of certificates that
521     // are allowed by the user, because this functionality is already handled via
522     // ssl_policy in native layers.
523     @CalledByNative
524     private boolean allowCertificateError(int certError, byte[] derBytes, final String url,
525             final int id) {
526         final SslCertificate cert = SslUtil.getCertificateFromDerBytes(derBytes);
527         if (cert == null) {
528             // if the certificate or the client is null, cancel the request
529             return false;
530         }
531         final SslError sslError = SslUtil.sslErrorFromNetErrorCode(certError, cert, url);
532         ValueCallback<Boolean> callback = new ValueCallback<Boolean>() {
533             @Override
534             public void onReceiveValue(Boolean value) {
535                 proceedSslError(value.booleanValue(), id);
536             }
537         };
538         onReceivedSslError(callback, sslError);
539         return true;
540     }
541
542     private void proceedSslError(boolean proceed, int id) {
543         if (mNativeContentsClientBridge == 0) return;
544         nativeProceedSslError(mNativeContentsClientBridge, proceed, id);
545     }
546
547     @CalledByNative
548     private void handleJsAlert(String url, String message, int id) {
549         if (isOwnerActivityRunning()) {
550             XWalkJavascriptResultHandlerInternal result =
551                     new XWalkJavascriptResultHandlerInternal(this, id);
552             mXWalkUIClient.onJavascriptModalDialog(mXWalkView,
553                     XWalkUIClientInternal.JavascriptMessageTypeInternal.JAVASCRIPT_ALERT,
554                     url, message, "", result);
555         }
556     }
557
558     @CalledByNative
559     private void handleJsConfirm(String url, String message, int id) {
560         if (isOwnerActivityRunning()) {
561             XWalkJavascriptResultHandlerInternal result =
562                     new XWalkJavascriptResultHandlerInternal(this, id);
563             mXWalkUIClient.onJavascriptModalDialog(mXWalkView,
564                     XWalkUIClientInternal.JavascriptMessageTypeInternal.JAVASCRIPT_CONFIRM,
565                     url, message, "", result);
566         }
567     }
568
569     @CalledByNative
570     private void handleJsPrompt(String url, String message, String defaultValue, int id) {
571         if (isOwnerActivityRunning()) {
572             XWalkJavascriptResultHandlerInternal result =
573                     new XWalkJavascriptResultHandlerInternal(this, id);
574             mXWalkUIClient.onJavascriptModalDialog(mXWalkView,
575                     XWalkUIClientInternal.JavascriptMessageTypeInternal.JAVASCRIPT_PROMPT,
576                     url, message, defaultValue, result);
577         }
578     }
579
580     @CalledByNative
581     private void handleJsBeforeUnload(String url, String message, int id) {
582         if (isOwnerActivityRunning()) {
583             XWalkJavascriptResultHandlerInternal result =
584                     new XWalkJavascriptResultHandlerInternal(this, id);
585             mXWalkUIClient.onJavascriptModalDialog(mXWalkView,
586                     XWalkUIClientInternal.JavascriptMessageTypeInternal.JAVASCRIPT_BEFOREUNLOAD,
587                     url, message, "", result);
588         }
589     }
590
591     @CalledByNative
592     private void updateNotificationIcon(int notificationId, Bitmap icon) {
593         mNotificationService.updateNotificationIcon(notificationId, icon);
594     }
595
596     @CalledByNative
597     private void showNotification(String title, String message, String replaceId,
598             int notificationId, long delegate) {
599         // FIXME(wang16): use replaceId to replace exist notification. It happens when
600         //                a notification with same name and tag fires.
601         mNotificationService.showNotification(
602                 title, message, notificationId, delegate);
603     }
604
605     @CalledByNative
606     private void cancelNotification(int notificationId, long delegate) {
607         mNotificationService.cancelNotification(notificationId, delegate);
608     }
609
610     void confirmJsResult(int id, String prompt) {
611         if (mNativeContentsClientBridge == 0) return;
612         nativeConfirmJsResult(mNativeContentsClientBridge, id, prompt);
613     }
614
615     void cancelJsResult(int id) {
616         if (mNativeContentsClientBridge == 0) return;
617         nativeCancelJsResult(mNativeContentsClientBridge, id);
618     }
619
620     void exitFullscreen(long nativeWebContents) {
621         if (mNativeContentsClientBridge == 0) return;
622         nativeExitFullscreen(mNativeContentsClientBridge, nativeWebContents);
623     }
624
625     public void notificationDisplayed(long delegate) {
626         if (mNativeContentsClientBridge == 0) return;
627         nativeNotificationDisplayed(mNativeContentsClientBridge, delegate);
628     }
629
630     public void notificationError(long delegate) {
631         if (mNativeContentsClientBridge == 0) return;
632         nativeNotificationError(mNativeContentsClientBridge, delegate);
633     }
634
635     public void notificationClicked(int id, long delegate) {
636         if (mNativeContentsClientBridge == 0) return;
637         nativeNotificationClicked(mNativeContentsClientBridge, id, delegate);
638     }
639
640     public void notificationClosed(int id, boolean byUser, long delegate) {
641         if (mNativeContentsClientBridge == 0) return;
642         nativeNotificationClosed(mNativeContentsClientBridge, id, byUser, delegate);
643     }
644
645     void setDownloadListener(DownloadListener listener) {
646         mDownloadListener = listener;
647     }
648
649     // Implement ContentViewDownloadDelegate methods.
650     public void requestHttpGetDownload(DownloadInfo downloadInfo) {
651         if (mDownloadListener != null) {
652             mDownloadListener.onDownloadStart(downloadInfo.getUrl(), downloadInfo.getUserAgent(),
653             downloadInfo.getContentDisposition(), downloadInfo.getMimeType(), downloadInfo.getContentLength());
654         }
655     }
656
657     public void onDownloadStarted(String filename, String mimeType) {
658     }
659
660     public void onDangerousDownload(String filename, int downloadId) {
661     }
662
663     //--------------------------------------------------------------------------------------------
664     //  Native methods
665     //--------------------------------------------------------------------------------------------
666     private native void nativeProceedSslError(long nativeXWalkContentsClientBridge,
667             boolean proceed, int id);
668
669     private native void nativeConfirmJsResult(long nativeXWalkContentsClientBridge, int id,
670             String prompt);
671     private native void nativeCancelJsResult(long nativeXWalkContentsClientBridge, int id);
672     private native void nativeExitFullscreen(long nativeXWalkContentsClientBridge, long nativeWebContents);
673     private native void nativeNotificationDisplayed(long nativeXWalkContentsClientBridge, long delegate);
674     private native void nativeNotificationError(long nativeXWalkContentsClientBridge, long delegate);
675     private native void nativeNotificationClicked(long nativeXWalkContentsClientBridge, int id, long delegate);
676     private native void nativeNotificationClosed(long nativeXWalkContentsClientBridge, int id, boolean byUser, long delegate);
677     private native void nativeOnFilesSelected(long nativeXWalkContentsClientBridge,
678             int processId, int renderId, int mode_flags, String filepath, String displayName);
679     private native void nativeOnFilesNotSelected(long nativeXWalkContentsClientBridge,
680             int processId, int renderId, int mode_flags);
681 }