WebViewContentsClientAdapter.java revision f8f270cb5b54adc9546566b283b83df911fc516f
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: " + consoleMessage.message()); 311 result = mWebChromeClient.onConsoleMessage(consoleMessage); 312 } else { 313 result = false; 314 } 315 TraceEvent.end(); 316 return result; 317 } 318 319 /** 320 * @see AwContentsClient#onFindResultReceived(int,int,boolean) 321 */ 322 @Override 323 public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, 324 boolean isDoneCounting) { 325 if (mFindListener == null) return; 326 TraceEvent.begin(); 327 if (TRACE) Log.d(TAG, "onFindResultReceived"); 328 mFindListener.onFindResultReceived(activeMatchOrdinal, numberOfMatches, isDoneCounting); 329 TraceEvent.end(); 330 } 331 332 /** 333 * @See AwContentsClient#onNewPicture(Picture) 334 */ 335 @Override 336 public void onNewPicture(Picture picture) { 337 if (mPictureListener == null) return; 338 TraceEvent.begin(); 339 if (TRACE) Log.d(TAG, "onNewPicture"); 340 mPictureListener.onNewPicture(mWebView, picture); 341 TraceEvent.end(); 342 } 343 344 @Override 345 public void onLoadResource(String url) { 346 TraceEvent.begin(); 347 if (TRACE) Log.d(TAG, "onLoadResource=" + url); 348 mWebViewClient.onLoadResource(mWebView, url); 349 TraceEvent.end(); 350 } 351 352 @Override 353 public boolean onCreateWindow(boolean isDialog, boolean isUserGesture) { 354 Message m = mUiThreadHandler.obtainMessage( 355 NEW_WEBVIEW_CREATED, mWebView.new WebViewTransport()); 356 TraceEvent.begin(); 357 boolean result; 358 if (mWebChromeClient != null) { 359 if (TRACE) Log.d(TAG, "onCreateWindow"); 360 result = mWebChromeClient.onCreateWindow(mWebView, isDialog, isUserGesture, m); 361 } else { 362 result = false; 363 } 364 TraceEvent.end(); 365 return result; 366 } 367 368 /** 369 * @see AwContentsClient#onCloseWindow() 370 */ 371 @Override 372 public void onCloseWindow() { 373 TraceEvent.begin(); 374 if (mWebChromeClient != null) { 375 if (TRACE) Log.d(TAG, "onCloseWindow"); 376 mWebChromeClient.onCloseWindow(mWebView); 377 } 378 TraceEvent.end(); 379 } 380 381 /** 382 * @see AwContentsClient#onRequestFocus() 383 */ 384 @Override 385 public void onRequestFocus() { 386 TraceEvent.begin(); 387 if (mWebChromeClient != null) { 388 if (TRACE) Log.d(TAG, "onRequestFocus"); 389 mWebChromeClient.onRequestFocus(mWebView); 390 } 391 TraceEvent.end(); 392 } 393 394 /** 395 * @see AwContentsClient#onReceivedTouchIconUrl(String url, boolean precomposed) 396 */ 397 @Override 398 public void onReceivedTouchIconUrl(String url, boolean precomposed) { 399 TraceEvent.begin(); 400 if (mWebChromeClient != null) { 401 if (TRACE) Log.d(TAG, "onReceivedTouchIconUrl=" + url); 402 mWebChromeClient.onReceivedTouchIconUrl(mWebView, url, precomposed); 403 } 404 TraceEvent.end(); 405 } 406 407 /** 408 * @see AwContentsClient#onReceivedIcon(Bitmap bitmap) 409 */ 410 @Override 411 public void onReceivedIcon(Bitmap bitmap) { 412 TraceEvent.begin(); 413 if (mWebChromeClient != null) { 414 if (TRACE) Log.d(TAG, "onReceivedIcon"); 415 mWebChromeClient.onReceivedIcon(mWebView, bitmap); 416 } 417 TraceEvent.end(); 418 } 419 420 /** 421 * @see ContentViewClient#onPageStarted(String) 422 */ 423 @Override 424 public void onPageStarted(String url) { 425 TraceEvent.begin(); 426 if (TRACE) Log.d(TAG, "onPageStarted=" + url); 427 mWebViewClient.onPageStarted(mWebView, url, mWebView.getFavicon()); 428 TraceEvent.end(); 429 } 430 431 /** 432 * @see ContentViewClient#onPageFinished(String) 433 */ 434 @Override 435 public void onPageFinished(String url) { 436 TraceEvent.begin(); 437 if (TRACE) Log.d(TAG, "onPageFinished=" + url); 438 mWebViewClient.onPageFinished(mWebView, url); 439 TraceEvent.end(); 440 441 // See b/8208948 442 // This fakes an onNewPicture callback after onPageFinished to allow 443 // CTS tests to run in an un-flaky manner. This is required as the 444 // path for sending Picture updates in Chromium are decoupled from the 445 // page loading callbacks, i.e. the Chrome compositor may draw our 446 // content and send the Picture before onPageStarted or onPageFinished 447 // are invoked. The CTS harness discards any pictures it receives before 448 // onPageStarted is invoked, so in the case we get the Picture before that and 449 // no further updates after onPageStarted, we'll fail the test by timing 450 // out waiting for a Picture. 451 // To ensure backwards compatibility, we need to defer sending Picture updates 452 // until onPageFinished has been invoked. This work is being done 453 // upstream, and we can revert this hack when it lands. 454 if (mPictureListener != null) { 455 new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { 456 @Override 457 public void run() { 458 UnimplementedWebViewApi.invoke(); 459 if (mPictureListener != null) { 460 if (TRACE) Log.d(TAG, "onPageFinished-fake"); 461 mPictureListener.onNewPicture(mWebView, new Picture()); 462 } 463 } 464 }, 100); 465 } 466 } 467 468 /** 469 * @see ContentViewClient#onReceivedError(int,String,String) 470 */ 471 @Override 472 public void onReceivedError(int errorCode, String description, String failingUrl) { 473 if (description == null || description.isEmpty()) { 474 // ErrorStrings is @hidden, so we can't do this in AwContents. 475 // Normally the net/ layer will set a valid description, but for synthesized callbacks 476 // (like in the case for intercepted requests) AwContents will pass in null. 477 description = ErrorStrings.getString(errorCode, mWebView.getContext()); 478 } 479 TraceEvent.begin(); 480 if (TRACE) Log.d(TAG, "onReceivedError=" + failingUrl); 481 mWebViewClient.onReceivedError(mWebView, errorCode, description, failingUrl); 482 TraceEvent.end(); 483 } 484 485 /** 486 * @see ContentViewClient#onReceivedTitle(String) 487 */ 488 @Override 489 public void onReceivedTitle(String title) { 490 TraceEvent.begin(); 491 if (mWebChromeClient != null) { 492 if (TRACE) Log.d(TAG, "onReceivedTitle"); 493 mWebChromeClient.onReceivedTitle(mWebView, title); 494 } 495 TraceEvent.end(); 496 } 497 498 499 /** 500 * @see ContentViewClient#shouldOverrideKeyEvent(KeyEvent) 501 */ 502 @Override 503 public boolean shouldOverrideKeyEvent(KeyEvent event) { 504 // TODO(joth): The expression here is a workaround for http://b/7697782 :- 505 // 1. The check for system key should be made in AwContents or ContentViewCore, 506 // before shouldOverrideKeyEvent() is called at all. 507 // 2. shouldOverrideKeyEvent() should be called in onKeyDown/onKeyUp, not from 508 // dispatchKeyEvent(). 509 if (event.isSystem()) return true; 510 TraceEvent.begin(); 511 if (TRACE) Log.d(TAG, "shouldOverrideKeyEvent"); 512 boolean result = mWebViewClient.shouldOverrideKeyEvent(mWebView, event); 513 TraceEvent.end(); 514 return result; 515 } 516 517 518 /** 519 * @see ContentViewClient#onStartContentIntent(Context, String) 520 * Callback when detecting a click on a content link. 521 */ 522 // TODO: Delete this method when removed from base class. 523 public void onStartContentIntent(Context context, String contentUrl) { 524 TraceEvent.begin(); 525 if (TRACE) Log.d(TAG, "shouldOverrideUrlLoading=" + contentUrl); 526 mWebViewClient.shouldOverrideUrlLoading(mWebView, contentUrl); 527 TraceEvent.end(); 528 } 529 530 @Override 531 public void onGeolocationPermissionsShowPrompt(String origin, 532 GeolocationPermissions.Callback callback) { 533 TraceEvent.begin(); 534 if (mWebChromeClient != null) { 535 if (TRACE) Log.d(TAG, "onGeolocationPermissionsShowPrompt"); 536 mWebChromeClient.onGeolocationPermissionsShowPrompt(origin, callback); 537 } 538 TraceEvent.end(); 539 } 540 541 @Override 542 public void onGeolocationPermissionsHidePrompt() { 543 TraceEvent.begin(); 544 if (mWebChromeClient != null) { 545 if (TRACE) Log.d(TAG, "onGeolocationPermissionsHidePrompt"); 546 mWebChromeClient.onGeolocationPermissionsHidePrompt(); 547 } 548 TraceEvent.end(); 549 } 550 551 private static class JsPromptResultReceiverAdapter implements JsResult.ResultReceiver { 552 private JsPromptResultReceiver mChromePromptResultReceiver; 553 private JsResultReceiver mChromeResultReceiver; 554 // We hold onto the JsPromptResult here, just to avoid the need to downcast 555 // in onJsResultComplete. 556 private final JsPromptResult mPromptResult = new JsPromptResult(this); 557 558 public JsPromptResultReceiverAdapter(JsPromptResultReceiver receiver) { 559 mChromePromptResultReceiver = receiver; 560 } 561 562 public JsPromptResultReceiverAdapter(JsResultReceiver receiver) { 563 mChromeResultReceiver = receiver; 564 } 565 566 public JsPromptResult getPromptResult() { 567 return mPromptResult; 568 } 569 570 @Override 571 public void onJsResultComplete(JsResult result) { 572 if (mChromePromptResultReceiver != null) { 573 if (mPromptResult.getResult()) { 574 mChromePromptResultReceiver.confirm(mPromptResult.getStringResult()); 575 } else { 576 mChromePromptResultReceiver.cancel(); 577 } 578 } else { 579 if (mPromptResult.getResult()) { 580 mChromeResultReceiver.confirm(); 581 } else { 582 mChromeResultReceiver.cancel(); 583 } 584 } 585 } 586 } 587 588 @Override 589 public void handleJsAlert(String url, String message, JsResultReceiver receiver) { 590 TraceEvent.begin(); 591 if (mWebChromeClient != null) { 592 final JsPromptResult res = 593 new JsPromptResultReceiverAdapter(receiver).getPromptResult(); 594 if (TRACE) Log.d(TAG, "onJsAlert"); 595 if (!mWebChromeClient.onJsAlert(mWebView, url, message, res)) { 596 new JsDialogHelper(res, JsDialogHelper.ALERT, null, message, url) 597 .showDialog(mWebView.getContext()); 598 } 599 } else { 600 receiver.cancel(); 601 } 602 TraceEvent.end(); 603 } 604 605 @Override 606 public void handleJsBeforeUnload(String url, String message, JsResultReceiver receiver) { 607 TraceEvent.begin(); 608 if (mWebChromeClient != null) { 609 final JsPromptResult res = 610 new JsPromptResultReceiverAdapter(receiver).getPromptResult(); 611 if (TRACE) Log.d(TAG, "onJsBeforeUnload"); 612 if (!mWebChromeClient.onJsBeforeUnload(mWebView, url, message, res)) { 613 new JsDialogHelper(res, JsDialogHelper.UNLOAD, null, message, url) 614 .showDialog(mWebView.getContext()); 615 } 616 } else { 617 receiver.cancel(); 618 } 619 TraceEvent.end(); 620 } 621 622 @Override 623 public void handleJsConfirm(String url, String message, JsResultReceiver receiver) { 624 TraceEvent.begin(); 625 if (mWebChromeClient != null) { 626 final JsPromptResult res = 627 new JsPromptResultReceiverAdapter(receiver).getPromptResult(); 628 if (TRACE) Log.d(TAG, "onJsConfirm"); 629 if (!mWebChromeClient.onJsConfirm(mWebView, url, message, res)) { 630 new JsDialogHelper(res, JsDialogHelper.CONFIRM, null, message, url) 631 .showDialog(mWebView.getContext()); 632 } 633 } else { 634 receiver.cancel(); 635 } 636 TraceEvent.end(); 637 } 638 639 @Override 640 public void handleJsPrompt(String url, String message, String defaultValue, 641 JsPromptResultReceiver receiver) { 642 TraceEvent.begin(); 643 if (mWebChromeClient != null) { 644 final JsPromptResult res = 645 new JsPromptResultReceiverAdapter(receiver).getPromptResult(); 646 if (TRACE) Log.d(TAG, "onJsPrompt"); 647 if (!mWebChromeClient.onJsPrompt(mWebView, url, message, defaultValue, res)) { 648 new JsDialogHelper(res, JsDialogHelper.PROMPT, defaultValue, message, url) 649 .showDialog(mWebView.getContext()); 650 } 651 } else { 652 receiver.cancel(); 653 } 654 TraceEvent.end(); 655 } 656 657 @Override 658 public void onReceivedHttpAuthRequest(AwHttpAuthHandler handler, String host, String realm) { 659 TraceEvent.begin(); 660 if (TRACE) Log.d(TAG, "onReceivedHttpAuthRequest=" + host); 661 mWebViewClient.onReceivedHttpAuthRequest(mWebView, 662 new AwHttpAuthHandlerAdapter(handler), host, realm); 663 TraceEvent.end(); 664 } 665 666 @Override 667 public void onReceivedSslError(final ValueCallback<Boolean> callback, SslError error) { 668 SslErrorHandler handler = new SslErrorHandler() { 669 @Override 670 public void proceed() { 671 postProceed(true); 672 } 673 @Override 674 public void cancel() { 675 postProceed(false); 676 } 677 private void postProceed(final boolean proceed) { 678 post(new Runnable() { 679 @Override 680 public void run() { 681 callback.onReceiveValue(proceed); 682 } 683 }); 684 } 685 }; 686 TraceEvent.begin(); 687 if (TRACE) Log.d(TAG, "onReceivedSslError"); 688 mWebViewClient.onReceivedSslError(mWebView, handler, error); 689 TraceEvent.end(); 690 } 691 692 @Override 693 public void onReceivedLoginRequest(String realm, String account, String args) { 694 TraceEvent.begin(); 695 if (TRACE) Log.d(TAG, "onReceivedLoginRequest=" + realm); 696 mWebViewClient.onReceivedLoginRequest(mWebView, realm, account, args); 697 TraceEvent.end(); 698 } 699 700 @Override 701 public void onFormResubmission(Message dontResend, Message resend) { 702 TraceEvent.begin(); 703 if (TRACE) Log.d(TAG, "onFormResubmission"); 704 mWebViewClient.onFormResubmission(mWebView, dontResend, resend); 705 TraceEvent.end(); 706 } 707 708 @Override 709 public void onDownloadStart(String url, 710 String userAgent, 711 String contentDisposition, 712 String mimeType, 713 long contentLength) { 714 if (mDownloadListener != null) { 715 TraceEvent.begin(); 716 if (TRACE) Log.d(TAG, "onDownloadStart"); 717 mDownloadListener.onDownloadStart(url, 718 userAgent, 719 contentDisposition, 720 mimeType, 721 contentLength); 722 TraceEvent.end(); 723 } 724 } 725 726 @Override 727 public void onScaleChangedScaled(float oldScale, float newScale) { 728 TraceEvent.begin(); 729 if (TRACE) Log.d(TAG, " onScaleChangedScaled"); 730 mWebViewClient.onScaleChanged(mWebView, oldScale, newScale); 731 TraceEvent.end(); 732 } 733 734 @Override 735 public void onShowCustomView(View view, CustomViewCallback cb) { 736 TraceEvent.begin(); 737 if (mWebChromeClient != null) { 738 if (TRACE) Log.d(TAG, "onShowCustomView"); 739 mWebChromeClient.onShowCustomView(view, cb); 740 } 741 TraceEvent.end(); 742 } 743 744 @Override 745 public void onHideCustomView() { 746 TraceEvent.begin(); 747 if (mWebChromeClient != null) { 748 if (TRACE) Log.d(TAG, "onHideCustomView"); 749 mWebChromeClient.onHideCustomView(); 750 } 751 TraceEvent.end(); 752 } 753 754 @Override 755 protected View getVideoLoadingProgressView() { 756 TraceEvent.begin(); 757 View result; 758 if (mWebChromeClient != null) { 759 if (TRACE) Log.d(TAG, "getVideoLoadingProgressView"); 760 result = mWebChromeClient.getVideoLoadingProgressView(); 761 } else { 762 result = null; 763 } 764 TraceEvent.end(); 765 return result; 766 } 767 768 @Override 769 public Bitmap getDefaultVideoPoster() { 770 TraceEvent.begin(); 771 Bitmap result; 772 if (mWebChromeClient != null) { 773 if (TRACE) Log.d(TAG, "getDefaultVideoPoster"); 774 result = mWebChromeClient.getDefaultVideoPoster(); 775 } else { 776 result = null; 777 } 778 TraceEvent.end(); 779 return result; 780 } 781 782 private static class AwHttpAuthHandlerAdapter extends android.webkit.HttpAuthHandler { 783 private AwHttpAuthHandler mAwHandler; 784 785 public AwHttpAuthHandlerAdapter(AwHttpAuthHandler awHandler) { 786 mAwHandler = awHandler; 787 } 788 789 @Override 790 public void proceed(String username, String password) { 791 if (username == null) { 792 username = ""; 793 } 794 795 if (password == null) { 796 password = ""; 797 } 798 mAwHandler.proceed(username, password); 799 } 800 801 @Override 802 public void cancel() { 803 mAwHandler.cancel(); 804 } 805 806 @Override 807 public boolean useHttpAuthUsernamePassword() { 808 return mAwHandler.isFirstAttempt(); 809 } 810 } 811} 812