WebViewContentsClientAdapter.java revision 1a0ca658d1d188ed9dc9b2163be0f2ee89e06a1e
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.webview.chromium; 18 19import android.content.ActivityNotFoundException; 20import android.content.Context; 21import android.content.Intent; 22import android.graphics.Bitmap; 23import android.graphics.Picture; 24import android.net.http.ErrorStrings; 25import android.net.http.SslError; 26import android.os.Handler; 27import android.os.Looper; 28import android.os.Message; 29import android.provider.Browser; 30import android.util.Log; 31import android.view.KeyEvent; 32import android.view.View; 33import android.webkit.ConsoleMessage; 34import android.webkit.DownloadListener; 35import android.webkit.GeolocationPermissions; 36import android.webkit.JsDialogHelper; 37import android.webkit.JsPromptResult; 38import android.webkit.JsResult; 39import android.webkit.SslErrorHandler; 40import android.webkit.ValueCallback; 41import android.webkit.WebChromeClient; 42import android.webkit.WebChromeClient.CustomViewCallback; 43import android.webkit.WebResourceResponse; 44import android.webkit.WebView; 45import android.webkit.WebViewClient; 46 47import org.chromium.android_webview.AwContentsClient; 48import org.chromium.android_webview.AwHttpAuthHandler; 49import org.chromium.android_webview.InterceptedRequestData; 50import org.chromium.android_webview.JsPromptResultReceiver; 51import org.chromium.android_webview.JsResultReceiver; 52import org.chromium.content.browser.ContentView; 53import org.chromium.content.browser.ContentViewClient; 54import org.chromium.content.common.TraceEvent; 55 56import java.net.URISyntaxException; 57 58/** 59 * An adapter class that forwards the callbacks from {@link ContentViewClient} 60 * to the appropriate {@link WebViewClient} or {@link WebChromeClient}. 61 * 62 * An instance of this class is associated with one {@link WebViewChromium} 63 * instance. A WebViewChromium is a WebView implementation provider (that is 64 * android.webkit.WebView delegates all functionality to it) and has exactly 65 * one corresponding {@link ContentView} instance. 66 * 67 * A {@link ContentViewClient} may be shared between multiple {@link ContentView}s, 68 * and hence multiple WebViews. Many WebViewClient methods pass the source 69 * WebView as an argument. This means that we either need to pass the 70 * corresponding ContentView to the corresponding ContentViewClient methods, 71 * or use an instance of ContentViewClientAdapter per WebViewChromium, to 72 * allow the source WebView to be injected by ContentViewClientAdapter. We 73 * choose the latter, because it makes for a cleaner design. 74 */ 75public class WebViewContentsClientAdapter extends AwContentsClient { 76 // TAG is chosen for consistency with classic webview tracing. 77 private static final String TAG = "WebViewCallback"; 78 // Enables API callback tracing 79 private static final boolean TRACE = android.webkit.DebugFlags.TRACE_CALLBACK; 80 // The WebView instance that this adapter is serving. 81 private final WebView mWebView; 82 // The WebViewClient instance that was passed to WebView.setWebViewClient(). 83 private WebViewClient mWebViewClient; 84 // The WebChromeClient instance that was passed to WebView.setContentViewClient(). 85 private WebChromeClient mWebChromeClient; 86 // The listener receiving find-in-page API results. 87 private WebView.FindListener mFindListener; 88 // The listener receiving notifications of screen updates. 89 private WebView.PictureListener mPictureListener; 90 91 private DownloadListener mDownloadListener; 92 93 private Handler mUiThreadHandler; 94 95 private static final int NEW_WEBVIEW_CREATED = 100; 96 97 /** 98 * Adapter constructor. 99 * 100 * @param webView the {@link WebView} instance that this adapter is serving. 101 */ 102 WebViewContentsClientAdapter(WebView webView) { 103 if (webView == null) { 104 throw new IllegalArgumentException("webView can't be null"); 105 } 106 107 mWebView = webView; 108 setWebViewClient(null); 109 110 mUiThreadHandler = new Handler() { 111 112 @Override 113 public void handleMessage(Message msg) { 114 switch(msg.what) { 115 case NEW_WEBVIEW_CREATED: 116 WebView.WebViewTransport t = (WebView.WebViewTransport) msg.obj; 117 WebView newWebView = t.getWebView(); 118 if (newWebView == mWebView) { 119 throw new IllegalArgumentException( 120 "Parent WebView cannot host it's own popup window. Please " + 121 "use WebSettings.setSupportMultipleWindows(false)"); 122 } 123 124 if (newWebView != null && newWebView.copyBackForwardList().getSize() != 0) { 125 throw new IllegalArgumentException( 126 "New WebView for popup window must not have been previously " + 127 "navigated."); 128 } 129 130 WebViewChromium.completeWindowCreation(mWebView, newWebView); 131 break; 132 default: 133 throw new IllegalStateException(); 134 } 135 } 136 }; 137 138 } 139 140 // WebViewClassic is coded in such a way that even if a null WebViewClient is set, 141 // certain actions take place. 142 // We choose to replicate this behavior by using a NullWebViewClient implementation (also known 143 // as the Null Object pattern) rather than duplicating the WebViewClassic approach in 144 // ContentView. 145 static class NullWebViewClient extends WebViewClient { 146 @Override 147 public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) { 148 // TODO: Investigate more and add a test case. 149 // This is a copy of what Clank does. The WebViewCore key handling code and Clank key 150 // handling code differ enough that it's not trivial to figure out how keycodes are 151 // being filtered. 152 int keyCode = event.getKeyCode(); 153 if (keyCode == KeyEvent.KEYCODE_MENU || 154 keyCode == KeyEvent.KEYCODE_HOME || 155 keyCode == KeyEvent.KEYCODE_BACK || 156 keyCode == KeyEvent.KEYCODE_CALL || 157 keyCode == KeyEvent.KEYCODE_ENDCALL || 158 keyCode == KeyEvent.KEYCODE_POWER || 159 keyCode == KeyEvent.KEYCODE_HEADSETHOOK || 160 keyCode == KeyEvent.KEYCODE_CAMERA || 161 keyCode == KeyEvent.KEYCODE_FOCUS || 162 keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || 163 keyCode == KeyEvent.KEYCODE_VOLUME_MUTE || 164 keyCode == KeyEvent.KEYCODE_VOLUME_UP) { 165 return true; 166 } 167 return false; 168 } 169 170 @Override 171 public boolean shouldOverrideUrlLoading(WebView view, String url) { 172 Intent intent; 173 // Perform generic parsing of the URI to turn it into an Intent. 174 try { 175 intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME); 176 } catch (URISyntaxException ex) { 177 Log.w(TAG, "Bad URI " + url + ": " + ex.getMessage()); 178 return false; 179 } 180 // Sanitize the Intent, ensuring web pages can not bypass browser 181 // security (only access to BROWSABLE activities). 182 intent.addCategory(Intent.CATEGORY_BROWSABLE); 183 intent.setComponent(null); 184 // Pass the package name as application ID so that the intent from the 185 // same application can be opened in the same tab. 186 intent.putExtra(Browser.EXTRA_APPLICATION_ID, 187 view.getContext().getPackageName()); 188 try { 189 view.getContext().startActivity(intent); 190 } catch (ActivityNotFoundException ex) { 191 Log.w(TAG, "No application can handle " + url); 192 return false; 193 } 194 return true; 195 } 196 } 197 198 void setWebViewClient(WebViewClient client) { 199 if (client != null) { 200 mWebViewClient = client; 201 } else { 202 mWebViewClient = new NullWebViewClient(); 203 } 204 } 205 206 void setWebChromeClient(WebChromeClient client) { 207 mWebChromeClient = client; 208 } 209 210 void setDownloadListener(DownloadListener listener) { 211 mDownloadListener = listener; 212 } 213 214 void setFindListener(WebView.FindListener listener) { 215 mFindListener = listener; 216 } 217 218 void setPictureListener(WebView.PictureListener listener) { 219 mPictureListener = listener; 220 } 221 222 //-------------------------------------------------------------------------------------------- 223 // Adapter for all the methods. 224 //-------------------------------------------------------------------------------------------- 225 226 /** 227 * @see AwContentsClient#getVisitedHistory 228 */ 229 @Override 230 public void getVisitedHistory(ValueCallback<String[]> callback) { 231 TraceEvent.begin(); 232 if (mWebChromeClient != null) { 233 if (TRACE) Log.d(TAG, "getVisitedHistory"); 234 mWebChromeClient.getVisitedHistory(callback); 235 } 236 TraceEvent.end(); 237 } 238 239 /** 240 * @see AwContentsClient#doUpdateVisiteHistory(String, boolean) 241 */ 242 @Override 243 public void doUpdateVisitedHistory(String url, boolean isReload) { 244 TraceEvent.begin(); 245 if (TRACE) Log.d(TAG, "doUpdateVisitedHistory=" + url + " reload=" + isReload); 246 mWebViewClient.doUpdateVisitedHistory(mWebView, url, isReload); 247 TraceEvent.end(); 248 } 249 250 /** 251 * @see AwContentsClient#onProgressChanged(int) 252 */ 253 @Override 254 public void onProgressChanged(int progress) { 255 TraceEvent.begin(); 256 if (mWebChromeClient != null) { 257 if (TRACE) Log.d(TAG, "onProgressChanged=" + progress); 258 mWebChromeClient.onProgressChanged(mWebView, progress); 259 } 260 TraceEvent.end(); 261 } 262 263 /** 264 * @see AwContentsClient#shouldInterceptRequest(java.lang.String) 265 */ 266 @Override 267 public InterceptedRequestData shouldInterceptRequest(String url) { 268 TraceEvent.begin(); 269 if (TRACE) Log.d(TAG, "shouldInterceptRequest=" + url); 270 WebResourceResponse response = mWebViewClient.shouldInterceptRequest(mWebView, url); 271 TraceEvent.end(); 272 if (response == null) return null; 273 return new InterceptedRequestData( 274 response.getMimeType(), 275 response.getEncoding(), 276 response.getData()); 277 } 278 279 /** 280 * @see AwContentsClient#shouldOverrideUrlLoading(java.lang.String) 281 */ 282 @Override 283 public boolean shouldOverrideUrlLoading(String url) { 284 TraceEvent.begin(); 285 if (TRACE) Log.d(TAG, "shouldOverrideUrlLoading=" + url); 286 boolean result = mWebViewClient.shouldOverrideUrlLoading(mWebView, url); 287 TraceEvent.end(); 288 return result; 289 } 290 291 /** 292 * @see AwContentsClient#onUnhandledKeyEvent(android.view.KeyEvent) 293 */ 294 @Override 295 public void onUnhandledKeyEvent(KeyEvent event) { 296 TraceEvent.begin(); 297 if (TRACE) Log.d(TAG, "onUnhandledKeyEvent"); 298 mWebViewClient.onUnhandledKeyEvent(mWebView, event); 299 TraceEvent.end(); 300 } 301 302 /** 303 * @see AwContentsClient#onConsoleMessage(android.webkit.ConsoleMessage) 304 */ 305 @Override 306 public boolean onConsoleMessage(ConsoleMessage consoleMessage) { 307 TraceEvent.begin(); 308 boolean result; 309 if (mWebChromeClient != null) { 310 if (TRACE) Log.d(TAG, "onConsoleMessage"); 311 result = mWebChromeClient.onConsoleMessage(consoleMessage); 312 String message = consoleMessage.message(); 313 if (result && message != null && message.startsWith("[blocked]")) { 314 Log.e(TAG, "Blocked URL: " + message); 315 } 316 } else { 317 result = false; 318 } 319 TraceEvent.end(); 320 return result; 321 } 322 323 /** 324 * @see AwContentsClient#onFindResultReceived(int,int,boolean) 325 */ 326 @Override 327 public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, 328 boolean isDoneCounting) { 329 if (mFindListener == null) return; 330 TraceEvent.begin(); 331 if (TRACE) Log.d(TAG, "onFindResultReceived"); 332 mFindListener.onFindResultReceived(activeMatchOrdinal, numberOfMatches, isDoneCounting); 333 TraceEvent.end(); 334 } 335 336 /** 337 * @See AwContentsClient#onNewPicture(Picture) 338 */ 339 @Override 340 public void onNewPicture(Picture picture) { 341 if (mPictureListener == null) return; 342 TraceEvent.begin(); 343 if (TRACE) Log.d(TAG, "onNewPicture"); 344 mPictureListener.onNewPicture(mWebView, picture); 345 TraceEvent.end(); 346 } 347 348 @Override 349 public void onLoadResource(String url) { 350 TraceEvent.begin(); 351 if (TRACE) Log.d(TAG, "onLoadResource=" + url); 352 mWebViewClient.onLoadResource(mWebView, url); 353 TraceEvent.end(); 354 } 355 356 @Override 357 public boolean onCreateWindow(boolean isDialog, boolean isUserGesture) { 358 Message m = mUiThreadHandler.obtainMessage( 359 NEW_WEBVIEW_CREATED, mWebView.new WebViewTransport()); 360 TraceEvent.begin(); 361 boolean result; 362 if (mWebChromeClient != null) { 363 if (TRACE) Log.d(TAG, "onCreateWindow"); 364 result = mWebChromeClient.onCreateWindow(mWebView, isDialog, isUserGesture, m); 365 } else { 366 result = false; 367 } 368 TraceEvent.end(); 369 return result; 370 } 371 372 /** 373 * @see AwContentsClient#onCloseWindow() 374 */ 375 @Override 376 public void onCloseWindow() { 377 TraceEvent.begin(); 378 if (mWebChromeClient != null) { 379 if (TRACE) Log.d(TAG, "onCloseWindow"); 380 mWebChromeClient.onCloseWindow(mWebView); 381 } 382 TraceEvent.end(); 383 } 384 385 /** 386 * @see AwContentsClient#onRequestFocus() 387 */ 388 @Override 389 public void onRequestFocus() { 390 TraceEvent.begin(); 391 if (mWebChromeClient != null) { 392 if (TRACE) Log.d(TAG, "onRequestFocus"); 393 mWebChromeClient.onRequestFocus(mWebView); 394 } 395 TraceEvent.end(); 396 } 397 398 /** 399 * @see AwContentsClient#onReceivedTouchIconUrl(String url, boolean precomposed) 400 */ 401 @Override 402 public void onReceivedTouchIconUrl(String url, boolean precomposed) { 403 TraceEvent.begin(); 404 if (mWebChromeClient != null) { 405 if (TRACE) Log.d(TAG, "onReceivedTouchIconUrl=" + url); 406 mWebChromeClient.onReceivedTouchIconUrl(mWebView, url, precomposed); 407 } 408 TraceEvent.end(); 409 } 410 411 /** 412 * @see AwContentsClient#onReceivedIcon(Bitmap bitmap) 413 */ 414 @Override 415 public void onReceivedIcon(Bitmap bitmap) { 416 TraceEvent.begin(); 417 if (mWebChromeClient != null) { 418 if (TRACE) Log.d(TAG, "onReceivedIcon"); 419 mWebChromeClient.onReceivedIcon(mWebView, bitmap); 420 } 421 TraceEvent.end(); 422 } 423 424 /** 425 * @see ContentViewClient#onPageStarted(String) 426 */ 427 @Override 428 public void onPageStarted(String url) { 429 TraceEvent.begin(); 430 if (TRACE) Log.d(TAG, "onPageStarted=" + url); 431 mWebViewClient.onPageStarted(mWebView, url, mWebView.getFavicon()); 432 TraceEvent.end(); 433 } 434 435 /** 436 * @see ContentViewClient#onPageFinished(String) 437 */ 438 @Override 439 public void onPageFinished(String url) { 440 TraceEvent.begin(); 441 if (TRACE) Log.d(TAG, "onPageFinished=" + url); 442 mWebViewClient.onPageFinished(mWebView, url); 443 TraceEvent.end(); 444 445 // See b/8208948 446 // This fakes an onNewPicture callback after onPageFinished to allow 447 // CTS tests to run in an un-flaky manner. This is required as the 448 // path for sending Picture updates in Chromium are decoupled from the 449 // page loading callbacks, i.e. the Chrome compositor may draw our 450 // content and send the Picture before onPageStarted or onPageFinished 451 // are invoked. The CTS harness discards any pictures it receives before 452 // onPageStarted is invoked, so in the case we get the Picture before that and 453 // no further updates after onPageStarted, we'll fail the test by timing 454 // out waiting for a Picture. 455 // To ensure backwards compatibility, we need to defer sending Picture updates 456 // until onPageFinished has been invoked. This work is being done 457 // upstream, and we can revert this hack when it lands. 458 if (mPictureListener != null) { 459 new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { 460 @Override 461 public void run() { 462 UnimplementedWebViewApi.invoke(); 463 if (mPictureListener != null) { 464 if (TRACE) Log.d(TAG, "onPageFinished-fake"); 465 mPictureListener.onNewPicture(mWebView, new Picture()); 466 } 467 } 468 }, 100); 469 } 470 } 471 472 /** 473 * @see ContentViewClient#onReceivedError(int,String,String) 474 */ 475 @Override 476 public void onReceivedError(int errorCode, String description, String failingUrl) { 477 if (description == null || description.isEmpty()) { 478 // ErrorStrings is @hidden, so we can't do this in AwContents. 479 // Normally the net/ layer will set a valid description, but for synthesized callbacks 480 // (like in the case for intercepted requests) AwContents will pass in null. 481 description = ErrorStrings.getString(errorCode, mWebView.getContext()); 482 } 483 TraceEvent.begin(); 484 if (TRACE) Log.d(TAG, "onReceivedError=" + failingUrl); 485 mWebViewClient.onReceivedError(mWebView, errorCode, description, failingUrl); 486 TraceEvent.end(); 487 } 488 489 /** 490 * @see ContentViewClient#onReceivedTitle(String) 491 */ 492 @Override 493 public void onReceivedTitle(String title) { 494 TraceEvent.begin(); 495 if (mWebChromeClient != null) { 496 if (TRACE) Log.d(TAG, "onReceivedTitle"); 497 mWebChromeClient.onReceivedTitle(mWebView, title); 498 } 499 TraceEvent.end(); 500 } 501 502 503 /** 504 * @see ContentViewClient#shouldOverrideKeyEvent(KeyEvent) 505 */ 506 @Override 507 public boolean shouldOverrideKeyEvent(KeyEvent event) { 508 // TODO(joth): The expression here is a workaround for http://b/7697782 :- 509 // 1. The check for system key should be made in AwContents or ContentViewCore, 510 // before shouldOverrideKeyEvent() is called at all. 511 // 2. shouldOverrideKeyEvent() should be called in onKeyDown/onKeyUp, not from 512 // dispatchKeyEvent(). 513 if (event.isSystem()) return true; 514 TraceEvent.begin(); 515 if (TRACE) Log.d(TAG, "shouldOverrideKeyEvent"); 516 boolean result = mWebViewClient.shouldOverrideKeyEvent(mWebView, event); 517 TraceEvent.end(); 518 return result; 519 } 520 521 522 /** 523 * @see ContentViewClient#onStartContentIntent(Context, String) 524 * Callback when detecting a click on a content link. 525 */ 526 // TODO: Delete this method when removed from base class. 527 public void onStartContentIntent(Context context, String contentUrl) { 528 TraceEvent.begin(); 529 if (TRACE) Log.d(TAG, "shouldOverrideUrlLoading=" + contentUrl); 530 mWebViewClient.shouldOverrideUrlLoading(mWebView, contentUrl); 531 TraceEvent.end(); 532 } 533 534 @Override 535 public void onGeolocationPermissionsShowPrompt(String origin, 536 GeolocationPermissions.Callback callback) { 537 TraceEvent.begin(); 538 if (mWebChromeClient != null) { 539 if (TRACE) Log.d(TAG, "onGeolocationPermissionsShowPrompt"); 540 mWebChromeClient.onGeolocationPermissionsShowPrompt(origin, callback); 541 } 542 TraceEvent.end(); 543 } 544 545 @Override 546 public void onGeolocationPermissionsHidePrompt() { 547 TraceEvent.begin(); 548 if (mWebChromeClient != null) { 549 if (TRACE) Log.d(TAG, "onGeolocationPermissionsHidePrompt"); 550 mWebChromeClient.onGeolocationPermissionsHidePrompt(); 551 } 552 TraceEvent.end(); 553 } 554 555 private static class JsPromptResultReceiverAdapter implements JsResult.ResultReceiver { 556 private JsPromptResultReceiver mChromePromptResultReceiver; 557 private JsResultReceiver mChromeResultReceiver; 558 // We hold onto the JsPromptResult here, just to avoid the need to downcast 559 // in onJsResultComplete. 560 private final JsPromptResult mPromptResult = new JsPromptResult(this); 561 562 public JsPromptResultReceiverAdapter(JsPromptResultReceiver receiver) { 563 mChromePromptResultReceiver = receiver; 564 } 565 566 public JsPromptResultReceiverAdapter(JsResultReceiver receiver) { 567 mChromeResultReceiver = receiver; 568 } 569 570 public JsPromptResult getPromptResult() { 571 return mPromptResult; 572 } 573 574 @Override 575 public void onJsResultComplete(JsResult result) { 576 if (mChromePromptResultReceiver != null) { 577 if (mPromptResult.getResult()) { 578 mChromePromptResultReceiver.confirm(mPromptResult.getStringResult()); 579 } else { 580 mChromePromptResultReceiver.cancel(); 581 } 582 } else { 583 if (mPromptResult.getResult()) { 584 mChromeResultReceiver.confirm(); 585 } else { 586 mChromeResultReceiver.cancel(); 587 } 588 } 589 } 590 } 591 592 @Override 593 public void handleJsAlert(String url, String message, JsResultReceiver receiver) { 594 TraceEvent.begin(); 595 if (mWebChromeClient != null) { 596 final JsPromptResult res = 597 new JsPromptResultReceiverAdapter(receiver).getPromptResult(); 598 if (TRACE) Log.d(TAG, "onJsAlert"); 599 if (!mWebChromeClient.onJsAlert(mWebView, url, message, res)) { 600 new JsDialogHelper(res, JsDialogHelper.ALERT, null, message, url) 601 .showDialog(mWebView.getContext()); 602 } 603 } else { 604 receiver.cancel(); 605 } 606 TraceEvent.end(); 607 } 608 609 @Override 610 public void handleJsBeforeUnload(String url, String message, JsResultReceiver receiver) { 611 TraceEvent.begin(); 612 if (mWebChromeClient != null) { 613 final JsPromptResult res = 614 new JsPromptResultReceiverAdapter(receiver).getPromptResult(); 615 if (TRACE) Log.d(TAG, "onJsBeforeUnload"); 616 if (!mWebChromeClient.onJsBeforeUnload(mWebView, url, message, res)) { 617 new JsDialogHelper(res, JsDialogHelper.UNLOAD, null, message, url) 618 .showDialog(mWebView.getContext()); 619 } 620 } else { 621 receiver.cancel(); 622 } 623 TraceEvent.end(); 624 } 625 626 @Override 627 public void handleJsConfirm(String url, String message, JsResultReceiver receiver) { 628 TraceEvent.begin(); 629 if (mWebChromeClient != null) { 630 final JsPromptResult res = 631 new JsPromptResultReceiverAdapter(receiver).getPromptResult(); 632 if (TRACE) Log.d(TAG, "onJsConfirm"); 633 if (!mWebChromeClient.onJsConfirm(mWebView, url, message, res)) { 634 new JsDialogHelper(res, JsDialogHelper.CONFIRM, null, message, url) 635 .showDialog(mWebView.getContext()); 636 } 637 } else { 638 receiver.cancel(); 639 } 640 TraceEvent.end(); 641 } 642 643 @Override 644 public void handleJsPrompt(String url, String message, String defaultValue, 645 JsPromptResultReceiver receiver) { 646 TraceEvent.begin(); 647 if (mWebChromeClient != null) { 648 final JsPromptResult res = 649 new JsPromptResultReceiverAdapter(receiver).getPromptResult(); 650 if (TRACE) Log.d(TAG, "onJsPrompt"); 651 if (!mWebChromeClient.onJsPrompt(mWebView, url, message, defaultValue, res)) { 652 new JsDialogHelper(res, JsDialogHelper.PROMPT, defaultValue, message, url) 653 .showDialog(mWebView.getContext()); 654 } 655 } else { 656 receiver.cancel(); 657 } 658 TraceEvent.end(); 659 } 660 661 @Override 662 public void onReceivedHttpAuthRequest(AwHttpAuthHandler handler, String host, String realm) { 663 TraceEvent.begin(); 664 if (TRACE) Log.d(TAG, "onReceivedHttpAuthRequest=" + host); 665 mWebViewClient.onReceivedHttpAuthRequest(mWebView, 666 new AwHttpAuthHandlerAdapter(handler), host, realm); 667 TraceEvent.end(); 668 } 669 670 @Override 671 public void onReceivedSslError(final ValueCallback<Boolean> callback, SslError error) { 672 SslErrorHandler handler = new SslErrorHandler() { 673 @Override 674 public void proceed() { 675 postProceed(true); 676 } 677 @Override 678 public void cancel() { 679 postProceed(false); 680 } 681 private void postProceed(final boolean proceed) { 682 post(new Runnable() { 683 @Override 684 public void run() { 685 callback.onReceiveValue(proceed); 686 } 687 }); 688 } 689 }; 690 TraceEvent.begin(); 691 if (TRACE) Log.d(TAG, "onReceivedSslError"); 692 mWebViewClient.onReceivedSslError(mWebView, handler, error); 693 TraceEvent.end(); 694 } 695 696 @Override 697 public void onReceivedLoginRequest(String realm, String account, String args) { 698 TraceEvent.begin(); 699 if (TRACE) Log.d(TAG, "onReceivedLoginRequest=" + realm); 700 mWebViewClient.onReceivedLoginRequest(mWebView, realm, account, args); 701 TraceEvent.end(); 702 } 703 704 @Override 705 public void onFormResubmission(Message dontResend, Message resend) { 706 TraceEvent.begin(); 707 if (TRACE) Log.d(TAG, "onFormResubmission"); 708 mWebViewClient.onFormResubmission(mWebView, dontResend, resend); 709 TraceEvent.end(); 710 } 711 712 @Override 713 public void onDownloadStart(String url, 714 String userAgent, 715 String contentDisposition, 716 String mimeType, 717 long contentLength) { 718 if (mDownloadListener != null) { 719 TraceEvent.begin(); 720 if (TRACE) Log.d(TAG, "onDownloadStart"); 721 mDownloadListener.onDownloadStart(url, 722 userAgent, 723 contentDisposition, 724 mimeType, 725 contentLength); 726 TraceEvent.end(); 727 } 728 } 729 730 @Override 731 public void onScaleChangedScaled(float oldScale, float newScale) { 732 TraceEvent.begin(); 733 if (TRACE) Log.d(TAG, " onScaleChangedScaled"); 734 mWebViewClient.onScaleChanged(mWebView, oldScale, newScale); 735 TraceEvent.end(); 736 } 737 738 @Override 739 public void onShowCustomView(View view, CustomViewCallback cb) { 740 TraceEvent.begin(); 741 if (mWebChromeClient != null) { 742 if (TRACE) Log.d(TAG, "onShowCustomView"); 743 mWebChromeClient.onShowCustomView(view, cb); 744 } 745 TraceEvent.end(); 746 } 747 748 @Override 749 public void onHideCustomView() { 750 TraceEvent.begin(); 751 if (mWebChromeClient != null) { 752 if (TRACE) Log.d(TAG, "onHideCustomView"); 753 mWebChromeClient.onHideCustomView(); 754 } 755 TraceEvent.end(); 756 } 757 758 @Override 759 protected View getVideoLoadingProgressView() { 760 TraceEvent.begin(); 761 View result; 762 if (mWebChromeClient != null) { 763 if (TRACE) Log.d(TAG, "getVideoLoadingProgressView"); 764 result = mWebChromeClient.getVideoLoadingProgressView(); 765 } else { 766 result = null; 767 } 768 TraceEvent.end(); 769 return result; 770 } 771 772 @Override 773 public Bitmap getDefaultVideoPoster() { 774 TraceEvent.begin(); 775 Bitmap result; 776 if (mWebChromeClient != null) { 777 if (TRACE) Log.d(TAG, "getDefaultVideoPoster"); 778 result = mWebChromeClient.getDefaultVideoPoster(); 779 } else { 780 result = null; 781 } 782 TraceEvent.end(); 783 return result; 784 } 785 786 private static class AwHttpAuthHandlerAdapter extends android.webkit.HttpAuthHandler { 787 private AwHttpAuthHandler mAwHandler; 788 789 public AwHttpAuthHandlerAdapter(AwHttpAuthHandler awHandler) { 790 mAwHandler = awHandler; 791 } 792 793 @Override 794 public void proceed(String username, String password) { 795 if (username == null) { 796 username = ""; 797 } 798 799 if (password == null) { 800 password = ""; 801 } 802 mAwHandler.proceed(username, password); 803 } 804 805 @Override 806 public void cancel() { 807 mAwHandler.cancel(); 808 } 809 810 @Override 811 public boolean useHttpAuthUsernamePassword() { 812 return mAwHandler.isFirstAttempt(); 813 } 814 } 815} 816