6693c0d17a9d6b99a9e3e5c3deb4b95a36bed681
[platform/framework/web/crosswalk.git] / src / xwalk / runtime / android / core / src / org / xwalk / core / 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;
7
8 import android.content.Intent;
9 import android.graphics.Bitmap;
10 import android.graphics.Picture;
11 import android.net.http.SslCertificate;
12 import android.net.http.SslError;
13 import android.os.Message;
14 import android.util.Log;
15 import android.view.KeyEvent;
16 import android.view.View;
17 import android.webkit.ConsoleMessage;
18 import android.webkit.ValueCallback;
19 import android.webkit.WebResourceResponse;
20
21 import org.chromium.base.CalledByNative;
22 import org.chromium.base.JNINamespace;
23 import org.chromium.base.ThreadUtils;
24 import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
25 import org.chromium.components.navigation_interception.NavigationParams;
26 import org.chromium.content.browser.ContentVideoViewClient;
27 import org.chromium.content.browser.ContentViewDownloadDelegate;
28 import org.chromium.content.browser.DownloadInfo;
29
30 // Help bridge callback in XWalkContentsClient to XWalkViewClient and
31 // XWalkWebChromeClient; Also handle the JNI conmmunication logic.
32 @JNINamespace("xwalk")
33 class XWalkContentsClientBridge extends XWalkContentsClient
34         implements ContentViewDownloadDelegate {
35
36     private XWalkView mXWalkView;
37     private XWalkUIClient mXWalkUIClient;
38     private XWalkResourceClient mXWalkResourceClient;
39     private XWalkClient mXWalkClient;
40     private XWalkWebChromeClient mXWalkWebChromeClient;
41     private Bitmap mFavicon;
42     private DownloadListener mDownloadListener;
43     private InterceptNavigationDelegate mInterceptNavigationDelegate;
44     private PageLoadListener mPageLoadListener;
45     private XWalkNavigationHandler mNavigationHandler;
46     private XWalkNotificationService mNotificationService;
47     private boolean mIsFullscreen = false;
48
49     // The native peer of the object
50     private int mNativeContentsClientBridge;
51
52     private class InterceptNavigationDelegateImpl implements InterceptNavigationDelegate {
53         private XWalkContentsClient mContentsClient;
54
55         public InterceptNavigationDelegateImpl(XWalkContentsClient client) {
56             mContentsClient = client;
57         }
58
59         public boolean shouldIgnoreNavigation(NavigationParams navigationParams) {
60             final String url = navigationParams.url;
61             boolean ignoreNavigation = shouldOverrideUrlLoading(url) ||
62                      (mNavigationHandler != null &&
63                       mNavigationHandler.handleNavigation(navigationParams));
64
65             if (!ignoreNavigation) {
66                 // Post a message to UI thread to notify the page is starting to load.
67                 mContentsClient.getCallbackHelper().postOnPageStarted(url);
68             }
69
70             return ignoreNavigation;
71         }
72     }
73
74     public XWalkContentsClientBridge(XWalkView xwView) {
75         mXWalkView = xwView;
76
77         mInterceptNavigationDelegate = new InterceptNavigationDelegateImpl(this);
78     }
79
80     public void setUIClient(XWalkUIClient client) {
81         // If it's null, use Crosswalk implementation.
82         if (client != null) {
83             mXWalkUIClient = client;
84             return;
85         }
86         mXWalkUIClient = new XWalkUIClientImpl(mXWalkView.getContext(), mXWalkView);
87     }
88
89     public void setResourceClient(XWalkResourceClient client) {
90         // If it's null, use Crosswalk implementation.
91         if (client != null) {
92             mXWalkResourceClient = client;
93             return;
94         }
95         mXWalkResourceClient = new XWalkResourceClientImpl(mXWalkView.getContext(), mXWalkView);
96     }
97
98
99     public void setXWalkWebChromeClient(XWalkWebChromeClient client) {
100         // If it's null, use Crosswalk implementation.
101         if (client == null) return;
102         client.setContentsClient(this);
103         mXWalkWebChromeClient = client;
104     }
105
106     public XWalkWebChromeClient getXWalkWebChromeClient() {
107         return mXWalkWebChromeClient;
108     }
109
110     public void setXWalkClient(XWalkClient client) {
111         mXWalkClient = client;
112     }
113
114     public void setNavigationHandler(XWalkNavigationHandler handler) {
115         mNavigationHandler = handler;
116     }
117
118     void registerPageLoadListener(PageLoadListener listener) {
119         mPageLoadListener = listener;
120     }
121
122     public void setNotificationService(XWalkNotificationService service) {
123         if (mNotificationService != null) mNotificationService.shutdown();
124         mNotificationService = service;
125         if (mNotificationService != null) mNotificationService.setBridge(this);
126     }
127
128     public boolean onNewIntent(Intent intent) {
129         return mNotificationService.maybeHandleIntent(intent);
130     }
131
132     public InterceptNavigationDelegate getInterceptNavigationDelegate() {
133         return mInterceptNavigationDelegate;
134     }
135
136     // TODO(Xingnan): All the empty functions need to be implemented.
137     @Override
138     public boolean shouldOverrideUrlLoading(String url) {
139         if (mXWalkClient != null && mXWalkView != null)
140             return mXWalkClient.shouldOverrideUrlLoading(mXWalkView, url);
141         return false;
142     }
143
144     @Override
145     public void onUnhandledKeyEvent(KeyEvent event) {
146     }
147
148     @Override
149     public void getVisitedHistory(ValueCallback<String[]> callback) {
150     }
151
152     @Override
153     public void doUpdateVisitedHistory(String url, boolean isReload) {
154     }
155
156     @Override
157     public void onProgressChanged(int progress) {
158         mXWalkResourceClient.onProgressChanged(mXWalkView, progress);
159     }
160
161     @Override
162     public WebResourceResponse shouldInterceptRequest(String url) {
163         return mXWalkResourceClient.shouldInterceptLoadRequest(mXWalkView, url);
164     }
165
166     public void onResourceLoadStarted(String url) {
167         mXWalkResourceClient.onLoadStarted(mXWalkView, url);
168     }
169
170     public void onResourceLoadFinished(String url) {
171         // TODO(yongsheng): this method is never called. Where should it be hooked?
172         mXWalkResourceClient.onLoadFinished(mXWalkView, url);
173     }
174
175     @Override
176     public void onLoadResource(String url) {
177         if (mXWalkClient != null && mXWalkView != null) {
178             mXWalkClient.onLoadResource(mXWalkView, url);
179         }
180     }
181
182     @Override
183     public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
184         return false;
185     }
186
187     @CalledByNative
188     public void onReceivedHttpAuthRequest(XWalkHttpAuthHandler handler, String host, String realm) {
189         if (mXWalkClient != null && mXWalkView != null) {
190             mXWalkClient.onReceivedHttpAuthRequest(mXWalkView, handler, host, realm);
191         }
192     }
193
194     @Override
195     public void onReceivedSslError(ValueCallback<Boolean> callback, SslError error) {
196         if (mXWalkClient != null && mXWalkView != null) {
197             mXWalkClient.onReceivedSslError(mXWalkView, callback, error);
198         }
199     }
200
201     @Override
202     public void onReceivedLoginRequest(String realm, String account, String args) {
203     }
204
205     @Override
206     public void onGeolocationPermissionsShowPrompt(String origin,
207             XWalkGeolocationPermissions.Callback callback) {
208         if (mXWalkWebChromeClient != null) {
209             mXWalkWebChromeClient.onGeolocationPermissionsShowPrompt(origin, callback);
210         }
211     }
212
213     @Override
214     public void onGeolocationPermissionsHidePrompt() {
215         if (mXWalkWebChromeClient != null) {
216             mXWalkWebChromeClient.onGeolocationPermissionsHidePrompt();
217         }
218     }
219
220     @Override
221     public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
222             boolean isDoneCounting) {
223     }
224
225     @Override
226     public void onNewPicture(Picture picture) {
227     }
228
229     @Override
230     public void onPageStarted(String url) {
231         if (mXWalkClient != null && mXWalkView != null) {
232             mXWalkClient.onPageStarted(mXWalkView, url);
233         }
234     }
235
236     @Override
237     public void onPageFinished(String url) {
238         if (mPageLoadListener != null) mPageLoadListener.onPageFinished(url);
239         if (mXWalkClient != null && mXWalkView != null) {
240             mXWalkClient.onPageFinished(mXWalkView, url);
241         }
242     }
243
244     @Override
245     public void onReceivedError(int errorCode, String description, String failingUrl) {
246         mXWalkResourceClient.onReceivedLoadError(mXWalkView, errorCode, description, failingUrl);
247     }
248
249     @Override
250     public void onRendererUnresponsive() {
251         if (mXWalkClient != null && mXWalkView != null) {
252             mXWalkClient.onRendererUnresponsive(mXWalkView);
253         }
254     }
255
256     @Override
257     public void onRendererResponsive() {
258         if (mXWalkClient != null && mXWalkView != null) {
259             mXWalkClient.onRendererResponsive(mXWalkView);
260         }
261     }
262
263     @Override
264     public void onFormResubmission(Message dontResend, Message resend) {
265         dontResend.sendToTarget();
266     }
267
268     @Override
269     public void onDownloadStart(String url,
270                                 String userAgent,
271                                 String contentDisposition,
272                                 String mimeType,
273                                 long contentLength) {
274     }
275
276     @Override
277     public boolean onCreateWindow(boolean isDialog, boolean isUserGesture) {
278         return false;
279     }
280
281     @Override
282     public void onRequestFocus() {
283         mXWalkUIClient.onRequestFocus(mXWalkView);
284     }
285
286     @Override
287     public void onCloseWindow() {
288         mXWalkUIClient.onJavascriptCloseWindow(mXWalkView);
289     }
290
291     @Override
292     public void onReceivedTouchIconUrl(String url, boolean precomposed) {
293         if (mXWalkWebChromeClient != null && mXWalkView != null) {
294             mXWalkWebChromeClient.onReceivedTouchIconUrl(mXWalkView, url, precomposed);
295         }
296     }
297
298     @Override
299     public void onReceivedIcon(Bitmap bitmap) {
300         if (mXWalkWebChromeClient != null && mXWalkView != null) {
301             mXWalkWebChromeClient.onReceivedIcon(mXWalkView, bitmap);
302         }
303         mFavicon = bitmap;
304     }
305
306     @Override
307     public void onShowCustomView(View view, XWalkWebChromeClient.CustomViewCallback callback) {
308         if (mXWalkWebChromeClient != null) {
309             mXWalkWebChromeClient.onShowCustomView(view, callback);
310         }
311     }
312
313     @Override
314     public void onHideCustomView() {
315         if (mXWalkWebChromeClient != null) {
316             mXWalkWebChromeClient.onHideCustomView();
317         }
318     }
319
320     @Override
321     public void onScaleChangedScaled(float oldScale, float newScale) {
322         mXWalkUIClient.onScaleChanged(mXWalkView, oldScale, newScale);
323     }
324
325     @Override
326     protected View getVideoLoadingProgressView() {
327         if (mXWalkWebChromeClient != null)
328             return mXWalkWebChromeClient.getVideoLoadingProgressView();
329         return null;
330     }
331
332     @Override
333     public Bitmap getDefaultVideoPoster() {
334         return null;
335     }
336
337     @Override
338     public void didFinishLoad(String url) {
339     }
340
341     @Override
342     public void onTitleChanged(String title) {
343         if (mXWalkWebChromeClient != null && mXWalkView != null) {
344             mXWalkWebChromeClient.onReceivedTitle(mXWalkView, title);
345         }
346     }
347
348     @Override
349     public void onToggleFullscreen(boolean enterFullscreen) {
350         mIsFullscreen = enterFullscreen;
351         mXWalkUIClient.onFullscreenToggled(mXWalkView, enterFullscreen);
352     }
353
354     @Override
355     public boolean hasEnteredFullscreen() {
356         return mIsFullscreen;
357     }
358
359     @Override
360     public ContentVideoViewClient getContentVideoViewClient() {
361         return new XWalkContentVideoViewClient(this, mXWalkView.getActivity());
362     }
363
364     // Used by the native peer to set/reset a weak ref to the native peer.
365     @CalledByNative
366     private void setNativeContentsClientBridge(int nativeContentsClientBridge) {
367         mNativeContentsClientBridge = nativeContentsClientBridge;
368     }
369
370     // If returns false, the request is immediately canceled, and any call to proceedSslError
371     // has no effect. If returns true, the request should be canceled or proceeded using
372     // proceedSslError().
373     // Unlike the webview classic, we do not keep keep a database of certificates that
374     // are allowed by the user, because this functionality is already handled via
375     // ssl_policy in native layers.
376     @CalledByNative
377     private boolean allowCertificateError(int certError, byte[] derBytes, final String url,
378             final int id) {
379         final SslCertificate cert = SslUtil.getCertificateFromDerBytes(derBytes);
380         if (cert == null) {
381             // if the certificate or the client is null, cancel the request
382             return false;
383         }
384         final SslError sslError = SslUtil.sslErrorFromNetErrorCode(certError, cert, url);
385         ValueCallback<Boolean> callback = new ValueCallback<Boolean>() {
386             @Override
387             public void onReceiveValue(Boolean value) {
388                 proceedSslError(value.booleanValue(), id);
389             }
390         };
391         onReceivedSslError(callback, sslError);
392         return true;
393     }
394
395     private void proceedSslError(boolean proceed, int id) {
396         if (mNativeContentsClientBridge == 0) return;
397         nativeProceedSslError(mNativeContentsClientBridge, proceed, id);
398     }
399
400     @CalledByNative
401     private void handleJsAlert(String url, String message, int id) {
402         XWalkJavascriptResultHandler result = new XWalkJavascriptResultHandler(this, id);
403         mXWalkUIClient.onJavascriptModalDialog(mXWalkView,
404                 XWalkUIClient.JavascriptMessageType.JAVASCRIPT_ALERT, url, message, "", result);
405     }
406
407     @CalledByNative
408     private void handleJsConfirm(String url, String message, int id) {
409         XWalkJavascriptResultHandler result = new XWalkJavascriptResultHandler(this, id);
410         mXWalkUIClient.onJavascriptModalDialog(mXWalkView,
411                 XWalkUIClient.JavascriptMessageType.JAVASCRIPT_CONFIRM, url, message, "", result);
412     }
413
414     @CalledByNative
415     private void handleJsPrompt(String url, String message, String defaultValue, int id) {
416         XWalkJavascriptResultHandler result = new XWalkJavascriptResultHandler(this, id);
417         mXWalkUIClient.onJavascriptModalDialog(mXWalkView,
418                 XWalkUIClient.JavascriptMessageType.JAVASCRIPT_PROMPT, url, message, defaultValue,
419                         result);
420     }
421
422     @CalledByNative
423     private void handleJsBeforeUnload(String url, String message, int id) {
424         XWalkJavascriptResultHandler result = new XWalkJavascriptResultHandler(this, id);
425         mXWalkUIClient.onJavascriptModalDialog(mXWalkView,
426                 XWalkUIClient.JavascriptMessageType.JAVASCRIPT_BEFOREUNLOAD, url, message, "",
427                         result);
428     }
429
430     // @CalledByNative
431     // TODO(yongsheng): Native side should call file chooser.
432     public void runFileChooser(final int processId, final int renderId, final int mode_flags,
433             String acceptTypes, String title, String defaultFilename, boolean capture) {
434         // TODO(yongsheng): Implement it.
435         // mXWalkUIClient.openFileChooser(mXWalkView, ...);
436         // See https://crosswalk-project.org/jira/browse/XWALK-1241.
437     }
438
439     @CalledByNative
440     private void updateNotificationIcon(int notificationId, Bitmap icon) {
441         mNotificationService.updateNotificationIcon(notificationId, icon);
442     }
443
444     @CalledByNative
445     private void showNotification(String title, String message, String replaceId,
446             int notificationId, int processId, int routeId) {
447         // FIXME(wang16): use replaceId to replace exist notification. It happens when
448         //                a notification with same name and tag fires.
449         mNotificationService.showNotification(
450                 title, message, notificationId, processId, routeId);
451     }
452
453     @CalledByNative
454     private void cancelNotification(int notificationId, int processId, int routeId) {
455         mNotificationService.cancelNotification(notificationId, processId, routeId);
456     }
457
458     void confirmJsResult(int id, String prompt) {
459         if (mNativeContentsClientBridge == 0) return;
460         nativeConfirmJsResult(mNativeContentsClientBridge, id, prompt);
461     }
462
463     void cancelJsResult(int id) {
464         if (mNativeContentsClientBridge == 0) return;
465         nativeCancelJsResult(mNativeContentsClientBridge, id);
466     }
467
468     void exitFullscreen(int nativeWebContents) {
469         if (mNativeContentsClientBridge == 0) return;
470         nativeExitFullscreen(mNativeContentsClientBridge, nativeWebContents);
471     }
472
473     public void notificationDisplayed(int id, int processId, int routeId) {
474         if (mNativeContentsClientBridge == 0) return;
475         nativeNotificationDisplayed(mNativeContentsClientBridge, id, processId, routeId);
476     }
477
478     public void notificationError(int id, String error, int processId, int routeId) {
479         if (mNativeContentsClientBridge == 0) return;
480         nativeNotificationError(mNativeContentsClientBridge, id, error, processId, routeId);
481     }
482
483     public void notificationClicked(int id, int processId, int routeId) {
484         if (mNativeContentsClientBridge == 0) return;
485         nativeNotificationClicked(mNativeContentsClientBridge, id, processId, routeId);
486     }
487
488     public void notificationClosed(int id, boolean byUser, int processId, int routeId) {
489         if (mNativeContentsClientBridge == 0) return;
490         nativeNotificationClosed(mNativeContentsClientBridge, id, byUser, processId, routeId);
491     }
492
493     void setDownloadListener(DownloadListener listener) {
494         mDownloadListener = listener;
495     }
496
497     // Implement ContentViewDownloadDelegate methods.
498     public void requestHttpGetDownload(DownloadInfo downloadInfo) {
499         if (mDownloadListener != null) {
500             mDownloadListener.onDownloadStart(downloadInfo.getUrl(), downloadInfo.getUserAgent(),
501             downloadInfo.getContentDisposition(), downloadInfo.getMimeType(), downloadInfo.getContentLength());
502         }
503     }
504
505     public void onDownloadStarted(String filename, String mimeType) {
506     }
507
508     public void onDangerousDownload(String filename, int downloadId) {
509     }
510
511     //--------------------------------------------------------------------------------------------
512     //  Native methods
513     //--------------------------------------------------------------------------------------------
514     private native void nativeProceedSslError(int nativeXWalkContentsClientBridge,
515             boolean proceed, int id);
516
517     private native void nativeConfirmJsResult(int nativeXWalkContentsClientBridge, int id,
518             String prompt);
519     private native void nativeCancelJsResult(int nativeXWalkContentsClientBridge, int id);
520     private native void nativeExitFullscreen(int nativeXWalkContentsClientBridge, int nativeWebContents);
521     private native void nativeNotificationDisplayed(int nativeXWalkContentsClientBridge, int id,
522             int processId, int routeId);
523     private native void nativeNotificationError(int nativeXWalkContentsClientBridge, int id,
524             String error, int processId, int routeId);
525     private native void nativeNotificationClicked(int nativeXWalkContentsClientBridge, int id,
526             int processId, int routeId);
527     private native void nativeNotificationClosed(int nativeXWalkContentsClientBridge, int id,
528             boolean byUser, int processId, int routeId);
529 }