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