1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Copyright (c) 2013 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.
6 package org.xwalk.core;
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;
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;
30 // Help bridge callback in XWalkContentsClient to XWalkViewClient and
31 // WebChromeClient; Also handle the JNI conmmunication logic.
32 @JNINamespace("xwalk")
33 class XWalkContentsClientBridge extends XWalkContentsClient
34 implements ContentViewDownloadDelegate {
36 private XWalkView mXWalkView;
37 private XWalkClient mXWalkClient;
38 private XWalkWebChromeClient mXWalkWebChromeClient;
39 private Bitmap mFavicon;
40 private DownloadListener mDownloadListener;
41 private InterceptNavigationDelegate mInterceptNavigationDelegate;
42 private PageLoadListener mPageLoadListener;
43 private XWalkNavigationHandler mNavigationHandler;
44 private XWalkNotificationService mNotificationService;
46 // The native peer of the object
47 private int mNativeContentsClientBridge;
49 private class InterceptNavigationDelegateImpl implements InterceptNavigationDelegate {
50 private XWalkContentsClient mContentsClient;
52 public InterceptNavigationDelegateImpl(XWalkContentsClient client) {
53 mContentsClient = client;
56 public boolean shouldIgnoreNavigation(NavigationParams navigationParams) {
57 final String url = navigationParams.url;
58 boolean ignoreNavigation = shouldOverrideUrlLoading(url) ||
59 (mNavigationHandler != null &&
60 mNavigationHandler.handleNavigation(navigationParams));
62 if (!ignoreNavigation) {
63 // Post a message to UI thread to notify the page is starting to load.
64 mContentsClient.getCallbackHelper().postOnPageStarted(url);
67 return ignoreNavigation;
71 public XWalkContentsClientBridge(XWalkView xwView) {
74 mInterceptNavigationDelegate = new InterceptNavigationDelegateImpl(this);
77 public void setXWalkWebChromeClient(XWalkWebChromeClient client) {
78 mXWalkWebChromeClient = client;
81 public XWalkWebChromeClient getXWalkWebChromeClient() {
82 return mXWalkWebChromeClient;
85 public void setXWalkClient(XWalkClient client) {
86 mXWalkClient = client;
89 public void setNavigationHandler(XWalkNavigationHandler handler) {
90 mNavigationHandler = handler;
93 void registerPageLoadListener(PageLoadListener listener) {
94 mPageLoadListener = listener;
97 public void setNotificationService(XWalkNotificationService service) {
98 if (mNotificationService != null) mNotificationService.shutdown();
99 mNotificationService = service;
100 if (mNotificationService != null) mNotificationService.setBridge(this);
103 public boolean onNewIntent(Intent intent) {
104 return mNotificationService.maybeHandleIntent(intent);
107 public InterceptNavigationDelegate getInterceptNavigationDelegate() {
108 return mInterceptNavigationDelegate;
111 // TODO(Xingnan): All the empty functions need to be implemented.
113 public boolean shouldOverrideUrlLoading(String url) {
114 if (mXWalkClient != null && mXWalkView != null)
115 return mXWalkClient.shouldOverrideUrlLoading(mXWalkView, url);
120 public void onUnhandledKeyEvent(KeyEvent event) {
124 public void getVisitedHistory(ValueCallback<String[]> callback) {
128 public void doUpdateVisitedHistory(String url, boolean isReload) {
132 public void onProgressChanged(int progress) {
133 if (mXWalkWebChromeClient != null && mXWalkView != null)
134 mXWalkWebChromeClient.onProgressChanged(mXWalkView, progress);
138 public WebResourceResponse shouldInterceptRequest(String url) {
139 if (mXWalkClient != null && mXWalkView != null)
140 return mXWalkClient.shouldInterceptRequest(mXWalkView, url);
145 public void onLoadResource(String url) {
146 if (mXWalkClient != null && mXWalkView != null)
147 mXWalkClient.onLoadResource(mXWalkView, url);
151 public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
156 public void onReceivedHttpAuthRequest(XWalkHttpAuthHandler handler, String host, String realm) {
157 if (mXWalkClient != null && mXWalkView != null)
158 mXWalkClient.onReceivedHttpAuthRequest(mXWalkView, handler, host, realm);
162 public void onReceivedSslError(ValueCallback<Boolean> callback, SslError error) {
163 if (mXWalkClient != null && mXWalkView != null) {
164 mXWalkClient.onReceivedSslError(mXWalkView, callback, error);
169 public void onReceivedLoginRequest(String realm, String account, String args) {
173 public void onGeolocationPermissionsShowPrompt(String origin,
174 XWalkGeolocationPermissions.Callback callback) {
175 if (mXWalkWebChromeClient != null) {
176 mXWalkWebChromeClient.onGeolocationPermissionsShowPrompt(origin, callback);
181 public void onGeolocationPermissionsHidePrompt() {
182 if (mXWalkWebChromeClient != null) {
183 mXWalkWebChromeClient.onGeolocationPermissionsHidePrompt();
188 public void handleJsAlert(String url, String message, JsResult result) {
189 if (mXWalkWebChromeClient != null && mXWalkView != null) {
190 mXWalkWebChromeClient.onJsAlert(mXWalkView, url, message, result);
195 public void handleJsBeforeUnload(String url, String message, JsResult result) {
196 if (mXWalkWebChromeClient != null && mXWalkView != null) {
197 mXWalkWebChromeClient.onJsBeforeUnload(mXWalkView, url, message, result);
202 public void handleJsConfirm(String url, String message, JsResult result) {
203 if (mXWalkWebChromeClient != null && mXWalkView != null) {
204 mXWalkWebChromeClient.onJsConfirm(mXWalkView, url, message, result);
209 public void handleJsPrompt(
210 String url, String message, String defaultValue, JsPromptResult result) {
211 if (mXWalkWebChromeClient != null && mXWalkView != null) {
212 mXWalkWebChromeClient.onJsPrompt(mXWalkView, url, message, defaultValue, result);
217 public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
218 boolean isDoneCounting) {
222 public void onNewPicture(Picture picture) {
226 public void onPageStarted(String url) {
227 if (mXWalkClient != null && mXWalkView != null) {
228 mXWalkClient.onPageStarted(mXWalkView, url, mFavicon);
233 public void onPageFinished(String url) {
234 if (mPageLoadListener != null) mPageLoadListener.onPageFinished(url);
235 if (mXWalkClient != null && mXWalkView != null) {
236 mXWalkClient.onPageFinished(mXWalkView, url);
241 public void onReceivedError(int errorCode, String description, String failingUrl) {
242 if (mXWalkClient != null && mXWalkView != null) {
243 mXWalkClient.onReceivedError(mXWalkView, errorCode, description, failingUrl);
248 public void onRendererUnresponsive() {
249 if (mXWalkClient != null && mXWalkView != null) {
250 mXWalkClient.onRendererUnresponsive(mXWalkView);
255 public void onRendererResponsive() {
256 if (mXWalkClient != null && mXWalkView != null) {
257 mXWalkClient.onRendererResponsive(mXWalkView);
262 public void onFormResubmission(Message dontResend, Message resend) {
263 dontResend.sendToTarget();
267 public void onDownloadStart(String url,
269 String contentDisposition,
271 long contentLength) {
275 public boolean onCreateWindow(boolean isDialog, boolean isUserGesture) {
280 public void onCloseWindow() {
281 if (mXWalkClient != null) {
282 mXWalkClient.onCloseWindow(mXWalkView);
287 public void onRequestFocus() {
291 public void onReceivedTouchIconUrl(String url, boolean precomposed) {
292 if (mXWalkWebChromeClient != null && mXWalkView != null) {
293 mXWalkWebChromeClient.onReceivedTouchIconUrl(mXWalkView, url, precomposed);
298 public void onReceivedIcon(Bitmap bitmap) {
299 if (mXWalkWebChromeClient != null && mXWalkView != null) {
300 mXWalkWebChromeClient.onReceivedIcon(mXWalkView, bitmap);
306 public void onShowCustomView(View view, XWalkWebChromeClient.CustomViewCallback callback) {
307 if (mXWalkWebChromeClient != null) {
308 mXWalkWebChromeClient.onShowCustomView(view, callback);
313 public void onHideCustomView() {
314 if (mXWalkWebChromeClient != null) {
315 mXWalkWebChromeClient.onHideCustomView();
320 public void onScaleChangedScaled(float oldScale, float newScale) {
324 protected View getVideoLoadingProgressView() {
325 if (mXWalkWebChromeClient != null)
326 return mXWalkWebChromeClient.getVideoLoadingProgressView();
331 public Bitmap getDefaultVideoPoster() {
336 public void didFinishLoad(String url) {
340 public void onTitleChanged(String title) {
341 if (mXWalkWebChromeClient != null && mXWalkView != null) {
342 mXWalkWebChromeClient.onReceivedTitle(mXWalkView, title);
347 public void onToggleFullscreen(boolean enterFullscreen) {
348 if (mXWalkWebChromeClient != null) {
349 mXWalkWebChromeClient.onToggleFullscreen(enterFullscreen);
354 public boolean isFullscreen() {
355 if (mXWalkWebChromeClient != null) return mXWalkWebChromeClient.isFullscreen();
361 public ContentVideoViewClient getContentVideoViewClient() {
362 return new XWalkContentVideoViewClient(this, mXWalkView.getActivity());
365 // Used by the native peer to set/reset a weak ref to the native peer.
367 private void setNativeContentsClientBridge(int nativeContentsClientBridge) {
368 mNativeContentsClientBridge = nativeContentsClientBridge;
371 // If returns false, the request is immediately canceled, and any call to proceedSslError
372 // has no effect. If returns true, the request should be canceled or proceeded using
373 // proceedSslError().
374 // Unlike the webview classic, we do not keep keep a database of certificates that
375 // are allowed by the user, because this functionality is already handled via
376 // ssl_policy in native layers.
378 private boolean allowCertificateError(int certError, byte[] derBytes, final String url,
380 final SslCertificate cert = SslUtil.getCertificateFromDerBytes(derBytes);
382 // if the certificate or the client is null, cancel the request
385 final SslError sslError = SslUtil.sslErrorFromNetErrorCode(certError, cert, url);
386 ValueCallback<Boolean> callback = new ValueCallback<Boolean>() {
388 public void onReceiveValue(Boolean value) {
389 proceedSslError(value.booleanValue(), id);
392 onReceivedSslError(callback, sslError);
396 private void proceedSslError(boolean proceed, int id) {
397 if (mNativeContentsClientBridge == 0) return;
398 nativeProceedSslError(mNativeContentsClientBridge, proceed, id);
402 private void handleJsAlert(String url, String message, int id) {
403 JsResultHandler handler = new JsResultHandler(this, id);
404 handleJsAlert(url, message, handler);
408 private void handleJsConfirm(String url, String message, int id) {
409 JsResultHandler handler = new JsResultHandler(this, id);
410 handleJsConfirm(url, message, handler);
414 private void handleJsPrompt(String url, String message, String defaultValue, int id) {
415 JsResultHandler handler = new JsResultHandler(this, id);
416 handleJsPrompt(url, message, defaultValue, handler);
420 private void handleJsBeforeUnload(String url, String message, int id) {
421 JsResultHandler handler = new JsResultHandler(this, id);
422 handleJsBeforeUnload(url, message, handler);
426 private void updateNotificationIcon(int notificationId, Bitmap icon) {
427 mNotificationService.updateNotificationIcon(notificationId, icon);
431 private void showNotification(String title, String message, String replaceId,
432 int notificationId, int processId, int routeId) {
433 // FIXME(wang16): use replaceId to replace exist notification. It happens when
434 // a notification with same name and tag fires.
435 mNotificationService.showNotification(
436 title, message, notificationId, processId, routeId);
440 private void cancelNotification(int notificationId, int processId, int routeId) {
441 mNotificationService.cancelNotification(notificationId, processId, routeId);
444 void confirmJsResult(int id, String prompt) {
445 if (mNativeContentsClientBridge == 0) return;
446 nativeConfirmJsResult(mNativeContentsClientBridge, id, prompt);
449 void cancelJsResult(int id) {
450 if (mNativeContentsClientBridge == 0) return;
451 nativeCancelJsResult(mNativeContentsClientBridge, id);
454 void exitFullscreen(int nativeWebContents) {
455 if (mNativeContentsClientBridge == 0) return;
456 nativeExitFullscreen(mNativeContentsClientBridge, nativeWebContents);
459 public void notificationDisplayed(int id, int processId, int routeId) {
460 if (mNativeContentsClientBridge == 0) return;
461 nativeNotificationDisplayed(mNativeContentsClientBridge, id, processId, routeId);
464 public void notificationError(int id, String error, int processId, int routeId) {
465 if (mNativeContentsClientBridge == 0) return;
466 nativeNotificationError(mNativeContentsClientBridge, id, error, processId, routeId);
469 public void notificationClicked(int id, int processId, int routeId) {
470 if (mNativeContentsClientBridge == 0) return;
471 nativeNotificationClicked(mNativeContentsClientBridge, id, processId, routeId);
474 public void notificationClosed(int id, boolean byUser, int processId, int routeId) {
475 if (mNativeContentsClientBridge == 0) return;
476 nativeNotificationClosed(mNativeContentsClientBridge, id, byUser, processId, routeId);
479 void setDownloadListener(DownloadListener listener) {
480 mDownloadListener = listener;
483 // Implement ContentViewDownloadDelegate methods.
484 public void requestHttpGetDownload(DownloadInfo downloadInfo) {
485 if (mDownloadListener != null) {
486 mDownloadListener.onDownloadStart(downloadInfo.getUrl(), downloadInfo.getUserAgent(),
487 downloadInfo.getContentDisposition(), downloadInfo.getMimeType(), downloadInfo.getContentLength());
491 public void onDownloadStarted(String filename, String mimeType) {
494 public void onDangerousDownload(String filename, int downloadId) {
497 //--------------------------------------------------------------------------------------------
499 //--------------------------------------------------------------------------------------------
500 private native void nativeProceedSslError(int nativeXWalkContentsClientBridge,
501 boolean proceed, int id);
503 private native void nativeConfirmJsResult(int nativeXWalkContentsClientBridge, int id,
505 private native void nativeCancelJsResult(int nativeXWalkContentsClientBridge, int id);
506 private native void nativeExitFullscreen(int nativeXWalkContentsClientBridge, int nativeWebContents);
507 private native void nativeNotificationDisplayed(int nativeXWalkContentsClientBridge, int id,
508 int processId, int routeId);
509 private native void nativeNotificationError(int nativeXWalkContentsClientBridge, int id,
510 String error, int processId, int routeId);
511 private native void nativeNotificationClicked(int nativeXWalkContentsClientBridge, int id,
512 int processId, int routeId);
513 private native void nativeNotificationClosed(int nativeXWalkContentsClientBridge, int id,
514 boolean byUser, int processId, int routeId);