CallbackProxy.java revision f013e1afd1e68af5e3b868c26a653bbfb39538f8
1/* 2 * Copyright (C) 2007 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 android.webkit; 18 19import android.content.ActivityNotFoundException; 20import android.content.Context; 21import android.content.Intent; 22import android.graphics.Bitmap; 23import android.net.Uri; 24import android.net.http.SslCertificate; 25import android.net.http.SslError; 26import android.os.Bundle; 27import android.os.Handler; 28import android.os.Message; 29import android.os.SystemClock; 30import android.util.Config; 31import android.util.Log; 32import android.view.KeyEvent; 33 34import java.util.HashMap; 35 36/** 37 * This class is a proxy class for handling WebCore -> UI thread messaging. All 38 * the callback functions are called from the WebCore thread and messages are 39 * posted to the UI thread for the actual client callback. 40 */ 41/* 42 * This class is created in the UI thread so its handler and any private classes 43 * that extend Handler will operate in the UI thread. 44 */ 45class CallbackProxy extends Handler { 46 // Logging tag 47 private static final String LOGTAG = "CallbackProxy"; 48 // Instance of WebViewClient that is the client callback. 49 private volatile WebViewClient mWebViewClient; 50 // Instance of WebChromeClient for handling all chrome functions. 51 private volatile WebChromeClient mWebChromeClient; 52 // Instance of WebView for handling UI requests. 53 private final WebView mWebView; 54 // Client registered callback listener for download events 55 private volatile DownloadListener mDownloadListener; 56 // Keep track of multiple progress updates. 57 private boolean mProgressUpdatePending; 58 // Keep track of the last progress amount. 59 private volatile int mLatestProgress; 60 // Back/Forward list 61 private final WebBackForwardList mBackForwardList; 62 // Used to call startActivity during url override. 63 private final Context mContext; 64 65 // Message Ids 66 private static final int PAGE_STARTED = 100; 67 private static final int RECEIVED_ICON = 101; 68 private static final int RECEIVED_TITLE = 102; 69 private static final int OVERRIDE_URL = 103; 70 private static final int AUTH_REQUEST = 104; 71 private static final int SSL_ERROR = 105; 72 private static final int PROGRESS = 106; 73 private static final int UPDATE_VISITED = 107; 74 private static final int LOAD_RESOURCE = 108; 75 private static final int CREATE_WINDOW = 109; 76 private static final int CLOSE_WINDOW = 110; 77 private static final int SAVE_PASSWORD = 111; 78 private static final int JS_ALERT = 112; 79 private static final int JS_CONFIRM = 113; 80 private static final int JS_PROMPT = 114; 81 private static final int JS_UNLOAD = 115; 82 private static final int ASYNC_KEYEVENTS = 116; 83 private static final int TOO_MANY_REDIRECTS = 117; 84 private static final int DOWNLOAD_FILE = 118; 85 private static final int REPORT_ERROR = 119; 86 private static final int RESEND_POST_DATA = 120; 87 private static final int PAGE_FINISHED = 121; 88 private static final int REQUEST_FOCUS = 122; 89 private static final int SCALE_CHANGED = 123; 90 private static final int RECEIVED_CERTIFICATE = 124; 91 private static final int SWITCH_OUT_HISTORY = 125; 92 93 // Message triggered by the client to resume execution 94 private static final int NOTIFY = 200; 95 96 // Result transportation object for returning results across thread 97 // boundaries. 98 private class ResultTransport<E> { 99 // Private result object 100 private E mResult; 101 102 public synchronized void setResult(E result) { 103 mResult = result; 104 } 105 106 public synchronized E getResult() { 107 return mResult; 108 } 109 } 110 111 /** 112 * Construct a new CallbackProxy. 113 */ 114 public CallbackProxy(Context context, WebView w) { 115 // Used to start a default activity. 116 mContext = context; 117 mWebView = w; 118 mBackForwardList = new WebBackForwardList(); 119 } 120 121 /** 122 * Set the WebViewClient. 123 * @param client An implementation of WebViewClient. 124 */ 125 public void setWebViewClient(WebViewClient client) { 126 mWebViewClient = client; 127 } 128 129 /** 130 * Set the WebChromeClient. 131 * @param client An implementation of WebChromeClient. 132 */ 133 public void setWebChromeClient(WebChromeClient client) { 134 mWebChromeClient = client; 135 } 136 137 /** 138 * Set the client DownloadListener. 139 * @param client An implementation of DownloadListener. 140 */ 141 public void setDownloadListener(DownloadListener client) { 142 mDownloadListener = client; 143 } 144 145 /** 146 * Get the Back/Forward list to return to the user or to update the cached 147 * history list. 148 */ 149 public WebBackForwardList getBackForwardList() { 150 return mBackForwardList; 151 } 152 153 /** 154 * Called by the UI side. Calling overrideUrlLoading from the WebCore 155 * side will post a message to call this method. 156 */ 157 public boolean uiOverrideUrlLoading(String overrideUrl) { 158 if (overrideUrl == null || overrideUrl.length() == 0) { 159 return false; 160 } 161 boolean override = false; 162 if (mWebViewClient != null) { 163 override = mWebViewClient.shouldOverrideUrlLoading(mWebView, 164 overrideUrl); 165 } else { 166 Intent intent = new Intent(Intent.ACTION_VIEW, 167 Uri.parse(overrideUrl)); 168 intent.addCategory(Intent.CATEGORY_BROWSABLE); 169 try { 170 mContext.startActivity(intent); 171 override = true; 172 } catch (ActivityNotFoundException ex) { 173 // If no application can handle the URL, assume that the 174 // browser can handle it. 175 } 176 } 177 return override; 178 } 179 180 /** 181 * Called by UI side. 182 */ 183 public boolean uiOverrideKeyEvent(KeyEvent event) { 184 if (mWebViewClient != null) { 185 return mWebViewClient.shouldOverrideKeyEvent(mWebView, event); 186 } 187 return false; 188 } 189 190 @Override 191 public void handleMessage(Message msg) { 192 // We don't have to do synchronization because this function operates 193 // in the UI thread. The WebViewClient and WebChromeClient functions 194 // that check for a non-null callback are ok because java ensures atomic 195 // 32-bit reads and writes. 196 switch (msg.what) { 197 case PAGE_STARTED: 198 if (mWebViewClient != null) { 199 mWebViewClient.onPageStarted(mWebView, 200 msg.getData().getString("url"), 201 (Bitmap) msg.obj); 202 } 203 break; 204 205 case PAGE_FINISHED: 206 if (mWebViewClient != null) { 207 mWebViewClient.onPageFinished(mWebView, (String) msg.obj); 208 } 209 break; 210 211 case RECEIVED_ICON: 212 if (mWebChromeClient != null) { 213 mWebChromeClient.onReceivedIcon(mWebView, (Bitmap) msg.obj); 214 } 215 break; 216 217 case RECEIVED_TITLE: 218 if (mWebChromeClient != null) { 219 mWebChromeClient.onReceivedTitle(mWebView, 220 (String) msg.obj); 221 } 222 break; 223 224 case TOO_MANY_REDIRECTS: 225 Message cancelMsg = 226 (Message) msg.getData().getParcelable("cancelMsg"); 227 Message continueMsg = 228 (Message) msg.getData().getParcelable("continueMsg"); 229 if (mWebViewClient != null) { 230 mWebViewClient.onTooManyRedirects(mWebView, cancelMsg, 231 continueMsg); 232 } else { 233 cancelMsg.sendToTarget(); 234 } 235 break; 236 237 case REPORT_ERROR: 238 if (mWebViewClient != null) { 239 int reasonCode = msg.arg1; 240 final String description = msg.getData().getString("description"); 241 final String failUrl = msg.getData().getString("failingUrl"); 242 mWebViewClient.onReceivedError(mWebView, reasonCode, 243 description, failUrl); 244 } 245 break; 246 247 case RESEND_POST_DATA: 248 Message resend = 249 (Message) msg.getData().getParcelable("resend"); 250 Message dontResend = 251 (Message) msg.getData().getParcelable("dontResend"); 252 if (mWebViewClient != null) { 253 mWebViewClient.onFormResubmission(mWebView, dontResend, 254 resend); 255 } else { 256 dontResend.sendToTarget(); 257 } 258 break; 259 260 case OVERRIDE_URL: 261 String overrideUrl = msg.getData().getString("url"); 262 boolean override = uiOverrideUrlLoading(overrideUrl); 263 ResultTransport<Boolean> result = 264 (ResultTransport<Boolean>) msg.obj; 265 synchronized (this) { 266 result.setResult(override); 267 notify(); 268 } 269 break; 270 271 case AUTH_REQUEST: 272 if (mWebViewClient != null) { 273 HttpAuthHandler handler = (HttpAuthHandler) msg.obj; 274 String host = msg.getData().getString("host"); 275 String realm = msg.getData().getString("realm"); 276 mWebViewClient.onReceivedHttpAuthRequest(mWebView, handler, 277 host, realm); 278 } 279 break; 280 281 case SSL_ERROR: 282 if (mWebViewClient != null) { 283 HashMap<String, Object> map = 284 (HashMap<String, Object>) msg.obj; 285 mWebViewClient.onReceivedSslError(mWebView, 286 (SslErrorHandler) map.get("handler"), 287 (SslError) map.get("error")); 288 } 289 break; 290 291 case PROGRESS: 292 // Synchronize to ensure mLatestProgress is not modified after 293 // setProgress is called and before mProgressUpdatePending is 294 // changed. 295 synchronized (this) { 296 if (mWebChromeClient != null) { 297 mWebChromeClient.onProgressChanged(mWebView, 298 mLatestProgress); 299 } 300 mProgressUpdatePending = false; 301 } 302 break; 303 304 case UPDATE_VISITED: 305 if (mWebViewClient != null) { 306 mWebViewClient.doUpdateVisitedHistory(mWebView, 307 (String) msg.obj, msg.arg1 != 0); 308 } 309 break; 310 311 case LOAD_RESOURCE: 312 if (mWebViewClient != null) { 313 mWebViewClient.onLoadResource(mWebView, (String) msg.obj); 314 } 315 break; 316 317 case DOWNLOAD_FILE: 318 if (mDownloadListener != null) { 319 String url = msg.getData().getString("url"); 320 String userAgent = msg.getData().getString("userAgent"); 321 String contentDisposition = 322 msg.getData().getString("contentDisposition"); 323 String mimetype = msg.getData().getString("mimetype"); 324 Long contentLength = msg.getData().getLong("contentLength"); 325 326 mDownloadListener.onDownloadStart(url, userAgent, 327 contentDisposition, mimetype, contentLength); 328 } 329 break; 330 331 case CREATE_WINDOW: 332 if (mWebChromeClient != null) { 333 if (!mWebChromeClient.onCreateWindow(mWebView, 334 msg.arg1 == 1, msg.arg2 == 1, 335 (Message) msg.obj)) { 336 synchronized (this) { 337 notify(); 338 } 339 } 340 } 341 break; 342 343 case REQUEST_FOCUS: 344 if (mWebChromeClient != null) { 345 mWebChromeClient.onRequestFocus(mWebView); 346 } 347 break; 348 349 case CLOSE_WINDOW: 350 if (mWebChromeClient != null) { 351 mWebChromeClient.onCloseWindow((WebView) msg.obj); 352 } 353 break; 354 355 case SAVE_PASSWORD: 356 Bundle bundle = msg.getData(); 357 String schemePlusHost = bundle.getString("host"); 358 String username = bundle.getString("username"); 359 String password = bundle.getString("password"); 360 // If the client returned false it means that the notify message 361 // will not be sent and we should notify WebCore ourselves. 362 if (!mWebView.onSavePassword(schemePlusHost, username, password, 363 (Message) msg.obj)) { 364 synchronized (this) { 365 notify(); 366 } 367 } 368 break; 369 370 case ASYNC_KEYEVENTS: 371 if (mWebViewClient != null) { 372 mWebViewClient.onUnhandledKeyEvent(mWebView, 373 (KeyEvent) msg.obj); 374 } 375 break; 376 377 case JS_ALERT: 378 if (mWebChromeClient != null) { 379 JsResult res = (JsResult) msg.obj; 380 String message = msg.getData().getString("message"); 381 String url = msg.getData().getString("url"); 382 if (!mWebChromeClient.onJsAlert(mWebView, url, message, 383 res)) { 384 res.handleDefault(); 385 } 386 res.setReady(); 387 } 388 break; 389 390 case JS_CONFIRM: 391 if (mWebChromeClient != null) { 392 JsResult res = (JsResult) msg.obj; 393 String message = msg.getData().getString("message"); 394 String url = msg.getData().getString("url"); 395 if (!mWebChromeClient.onJsConfirm(mWebView, url, message, 396 res)) { 397 res.handleDefault(); 398 } 399 // Tell the JsResult that it is ready for client 400 // interaction. 401 res.setReady(); 402 } 403 break; 404 405 case JS_PROMPT: 406 if (mWebChromeClient != null) { 407 JsPromptResult res = (JsPromptResult) msg.obj; 408 String message = msg.getData().getString("message"); 409 String defaultVal = msg.getData().getString("default"); 410 String url = msg.getData().getString("url"); 411 if (!mWebChromeClient.onJsPrompt(mWebView, url, message, 412 defaultVal, res)) { 413 res.handleDefault(); 414 } 415 // Tell the JsResult that it is ready for client 416 // interaction. 417 res.setReady(); 418 } 419 break; 420 421 case JS_UNLOAD: 422 if (mWebChromeClient != null) { 423 JsResult res = (JsResult) msg.obj; 424 String message = msg.getData().getString("message"); 425 String url = msg.getData().getString("url"); 426 if (!mWebChromeClient.onJsBeforeUnload(mWebView, url, 427 message, res)) { 428 res.handleDefault(); 429 } 430 res.setReady(); 431 } 432 break; 433 434 case RECEIVED_CERTIFICATE: 435 mWebView.setCertificate((SslCertificate) msg.obj); 436 break; 437 438 case NOTIFY: 439 synchronized (this) { 440 notify(); 441 } 442 break; 443 444 case SCALE_CHANGED: 445 if (mWebViewClient != null) { 446 mWebViewClient.onScaleChanged(mWebView, msg.getData() 447 .getFloat("old"), msg.getData().getFloat("new")); 448 } 449 break; 450 451 case SWITCH_OUT_HISTORY: 452 mWebView.switchOutDrawHistory(); 453 break; 454 } 455 } 456 457 /** 458 * Return the latest progress. 459 */ 460 public int getProgress() { 461 return mLatestProgress; 462 } 463 464 /** 465 * Called by WebCore side to switch out of history Picture drawing mode 466 */ 467 void switchOutDrawHistory() { 468 sendMessage(obtainMessage(SWITCH_OUT_HISTORY)); 469 } 470 471 //-------------------------------------------------------------------------- 472 // WebViewClient functions. 473 // NOTE: shouldOverrideKeyEvent is never called from the WebCore thread so 474 // it is not necessary to include it here. 475 //-------------------------------------------------------------------------- 476 477 // Performance probe 478 private long mWebCoreThreadTime; 479 480 public void onPageStarted(String url, Bitmap favicon) { 481 // Do an unsynchronized quick check to avoid posting if no callback has 482 // been set. 483 if (mWebViewClient == null) { 484 return; 485 } 486 // Performance probe 487 if (false) { 488 mWebCoreThreadTime = SystemClock.currentThreadTimeMillis(); 489 Network.getInstance(mContext).startTiming(); 490 } 491 Message msg = obtainMessage(PAGE_STARTED); 492 msg.obj = favicon; 493 msg.getData().putString("url", url); 494 sendMessage(msg); 495 } 496 497 public void onPageFinished(String url) { 498 // Do an unsynchronized quick check to avoid posting if no callback has 499 // been set. 500 if (mWebViewClient == null) { 501 return; 502 } 503 // Performance probe 504 if (false) { 505 Log.d("WebCore", "WebCore thread used " + 506 (SystemClock.currentThreadTimeMillis() - mWebCoreThreadTime) 507 + " ms"); 508 Network.getInstance(mContext).stopTiming(); 509 } 510 Message msg = obtainMessage(PAGE_FINISHED, url); 511 sendMessage(msg); 512 } 513 514 public void onTooManyRedirects(Message cancelMsg, Message continueMsg) { 515 // Do an unsynchronized quick check to avoid posting if no callback has 516 // been set. 517 if (mWebViewClient == null) { 518 cancelMsg.sendToTarget(); 519 return; 520 } 521 522 Message msg = obtainMessage(TOO_MANY_REDIRECTS); 523 Bundle bundle = msg.getData(); 524 bundle.putParcelable("cancelMsg", cancelMsg); 525 bundle.putParcelable("continueMsg", continueMsg); 526 sendMessage(msg); 527 } 528 529 public void onReceivedError(int errorCode, String description, 530 String failingUrl) { 531 // Do an unsynchronized quick check to avoid posting if no callback has 532 // been set. 533 if (mWebViewClient == null) { 534 return; 535 } 536 537 Message msg = obtainMessage(REPORT_ERROR); 538 msg.arg1 = errorCode; 539 msg.getData().putString("description", description); 540 msg.getData().putString("failingUrl", failingUrl); 541 sendMessage(msg); 542 } 543 544 public void onFormResubmission(Message dontResend, 545 Message resend) { 546 // Do an unsynchronized quick check to avoid posting if no callback has 547 // been set. 548 if (mWebViewClient == null) { 549 dontResend.sendToTarget(); 550 return; 551 } 552 553 Message msg = obtainMessage(RESEND_POST_DATA); 554 Bundle bundle = msg.getData(); 555 bundle.putParcelable("resend", resend); 556 bundle.putParcelable("dontResend", dontResend); 557 sendMessage(msg); 558 } 559 560 /** 561 * Called by the WebCore side 562 */ 563 public boolean shouldOverrideUrlLoading(String url) { 564 // We have a default behavior if no client exists so always send the 565 // message. 566 ResultTransport<Boolean> res = new ResultTransport<Boolean>(); 567 Message msg = obtainMessage(OVERRIDE_URL); 568 msg.getData().putString("url", url); 569 msg.obj = res; 570 synchronized (this) { 571 sendMessage(msg); 572 try { 573 wait(); 574 } catch (InterruptedException e) { 575 Log.e(LOGTAG, "Caught exception while waiting for overrideUrl"); 576 Log.e(LOGTAG, Log.getStackTraceString(e)); 577 } 578 } 579 return res.getResult().booleanValue(); 580 } 581 582 public void onReceivedHttpAuthRequest(HttpAuthHandler handler, 583 String hostName, String realmName) { 584 // Do an unsynchronized quick check to avoid posting if no callback has 585 // been set. 586 if (mWebViewClient == null) { 587 handler.cancel(); 588 return; 589 } 590 Message msg = obtainMessage(AUTH_REQUEST, handler); 591 msg.getData().putString("host", hostName); 592 msg.getData().putString("realm", realmName); 593 sendMessage(msg); 594 } 595 /** 596 * @hide - hide this because it contains a parameter of type SslError. 597 * SslError is located in a hidden package. 598 */ 599 public void onReceivedSslError(SslErrorHandler handler, SslError error) { 600 // Do an unsynchronized quick check to avoid posting if no callback has 601 // been set. 602 if (mWebViewClient == null) { 603 handler.cancel(); 604 return; 605 } 606 Message msg = obtainMessage(SSL_ERROR); 607 //, handler); 608 HashMap<String, Object> map = new HashMap(); 609 map.put("handler", handler); 610 map.put("error", error); 611 msg.obj = map; 612 sendMessage(msg); 613 } 614 /** 615 * @hide - hide this because it contains a parameter of type SslCertificate, 616 * which is located in a hidden package. 617 */ 618 619 public void onReceivedCertificate(SslCertificate certificate) { 620 // Do an unsynchronized quick check to avoid posting if no callback has 621 // been set. 622 if (mWebViewClient == null) { 623 return; 624 } 625 // here, certificate can be null (if the site is not secure) 626 sendMessage(obtainMessage(RECEIVED_CERTIFICATE, certificate)); 627 } 628 629 public void doUpdateVisitedHistory(String url, boolean isReload) { 630 // Do an unsynchronized quick check to avoid posting if no callback has 631 // been set. 632 if (mWebViewClient == null) { 633 return; 634 } 635 sendMessage(obtainMessage(UPDATE_VISITED, isReload ? 1 : 0, 0, url)); 636 } 637 638 public void onLoadResource(String url) { 639 // Do an unsynchronized quick check to avoid posting if no callback has 640 // been set. 641 if (mWebViewClient == null) { 642 return; 643 } 644 sendMessage(obtainMessage(LOAD_RESOURCE, url)); 645 } 646 647 public void onUnhandledKeyEvent(KeyEvent event) { 648 // Do an unsynchronized quick check to avoid posting if no callback has 649 // been set. 650 if (mWebViewClient == null) { 651 return; 652 } 653 sendMessage(obtainMessage(ASYNC_KEYEVENTS, event)); 654 } 655 656 public void onScaleChanged(float oldScale, float newScale) { 657 // Do an unsynchronized quick check to avoid posting if no callback has 658 // been set. 659 if (mWebViewClient == null) { 660 return; 661 } 662 Message msg = obtainMessage(SCALE_CHANGED); 663 Bundle bundle = msg.getData(); 664 bundle.putFloat("old", oldScale); 665 bundle.putFloat("new", newScale); 666 sendMessage(msg); 667 } 668 669 //-------------------------------------------------------------------------- 670 // DownloadListener functions. 671 //-------------------------------------------------------------------------- 672 673 /** 674 * Starts a download if a download listener has been registered, otherwise 675 * return false. 676 */ 677 public boolean onDownloadStart(String url, String userAgent, 678 String contentDisposition, String mimetype, long contentLength) { 679 // Do an unsynchronized quick check to avoid posting if no callback has 680 // been set. 681 if (mDownloadListener == null) { 682 // Cancel the download if there is no browser client. 683 return false; 684 } 685 686 Message msg = obtainMessage(DOWNLOAD_FILE); 687 Bundle bundle = msg.getData(); 688 bundle.putString("url", url); 689 bundle.putString("userAgent", userAgent); 690 bundle.putString("mimetype", mimetype); 691 bundle.putLong("contentLength", contentLength); 692 bundle.putString("contentDisposition", contentDisposition); 693 sendMessage(msg); 694 return true; 695 } 696 697 698 //-------------------------------------------------------------------------- 699 // WebView specific functions that do not interact with a client. These 700 // functions just need to operate within the UI thread. 701 //-------------------------------------------------------------------------- 702 703 public boolean onSavePassword(String schemePlusHost, String username, 704 String password, Message resumeMsg) { 705 // resumeMsg should be null at this point because we want to create it 706 // within the CallbackProxy. 707 if (Config.DEBUG) { 708 junit.framework.Assert.assertNull(resumeMsg); 709 } 710 resumeMsg = obtainMessage(NOTIFY); 711 712 Message msg = obtainMessage(SAVE_PASSWORD, resumeMsg); 713 Bundle bundle = msg.getData(); 714 bundle.putString("host", schemePlusHost); 715 bundle.putString("username", username); 716 bundle.putString("password", password); 717 synchronized (this) { 718 sendMessage(msg); 719 try { 720 wait(); 721 } catch (InterruptedException e) { 722 Log.e(LOGTAG, 723 "Caught exception while waiting for onSavePassword"); 724 Log.e(LOGTAG, Log.getStackTraceString(e)); 725 } 726 } 727 // Doesn't matter here 728 return false; 729 } 730 731 //-------------------------------------------------------------------------- 732 // WebChromeClient methods 733 //-------------------------------------------------------------------------- 734 735 public void onProgressChanged(int newProgress) { 736 // Synchronize so that mLatestProgress is up-to-date. 737 synchronized (this) { 738 mLatestProgress = newProgress; 739 if (mWebChromeClient == null) { 740 return; 741 } 742 if (!mProgressUpdatePending) { 743 sendEmptyMessage(PROGRESS); 744 mProgressUpdatePending = true; 745 } 746 } 747 } 748 749 public WebView createWindow(boolean dialog, boolean userGesture) { 750 // Do an unsynchronized quick check to avoid posting if no callback has 751 // been set. 752 if (mWebChromeClient == null) { 753 return null; 754 } 755 756 WebView.WebViewTransport transport = mWebView.new WebViewTransport(); 757 final Message msg = obtainMessage(NOTIFY); 758 msg.obj = transport; 759 synchronized (this) { 760 sendMessage(obtainMessage(CREATE_WINDOW, dialog ? 1 : 0, 761 userGesture ? 1 : 0, msg)); 762 try { 763 wait(); 764 } catch (InterruptedException e) { 765 Log.e(LOGTAG, 766 "Caught exception while waiting for createWindow"); 767 Log.e(LOGTAG, Log.getStackTraceString(e)); 768 } 769 } 770 771 WebView w = transport.getWebView(); 772 if (w != null) { 773 w.getWebViewCore().initializeSubwindow(); 774 } 775 return w; 776 } 777 778 public void onRequestFocus() { 779 // Do an unsynchronized quick check to avoid posting if no callback has 780 // been set. 781 if (mWebChromeClient == null) { 782 return; 783 } 784 785 sendEmptyMessage(REQUEST_FOCUS); 786 } 787 788 public void onCloseWindow(WebView window) { 789 // Do an unsynchronized quick check to avoid posting if no callback has 790 // been set. 791 if (mWebChromeClient == null) { 792 return; 793 } 794 sendMessage(obtainMessage(CLOSE_WINDOW, window)); 795 } 796 797 public void onReceivedIcon(Bitmap icon) { 798 if (Config.DEBUG && mBackForwardList.getCurrentItem() == null) { 799 throw new AssertionError(); 800 } 801 mBackForwardList.getCurrentItem().setFavicon(icon); 802 // Do an unsynchronized quick check to avoid posting if no callback has 803 // been set. 804 if (mWebChromeClient == null) { 805 return; 806 } 807 sendMessage(obtainMessage(RECEIVED_ICON, icon)); 808 } 809 810 public void onReceivedTitle(String title) { 811 // Do an unsynchronized quick check to avoid posting if no callback has 812 // been set. 813 if (mWebChromeClient == null) { 814 return; 815 } 816 sendMessage(obtainMessage(RECEIVED_TITLE, title)); 817 } 818 819 public void onJsAlert(String url, String message) { 820 // Do an unsynchronized quick check to avoid posting if no callback has 821 // been set. 822 if (mWebChromeClient == null) { 823 return; 824 } 825 JsResult result = new JsResult(this, false); 826 Message alert = obtainMessage(JS_ALERT, result); 827 alert.getData().putString("message", message); 828 alert.getData().putString("url", url); 829 synchronized (this) { 830 sendMessage(alert); 831 try { 832 wait(); 833 } catch (InterruptedException e) { 834 Log.e(LOGTAG, "Caught exception while waiting for jsAlert"); 835 Log.e(LOGTAG, Log.getStackTraceString(e)); 836 } 837 } 838 } 839 840 public boolean onJsConfirm(String url, String message) { 841 // Do an unsynchronized quick check to avoid posting if no callback has 842 // been set. 843 if (mWebChromeClient == null) { 844 return false; 845 } 846 JsResult result = new JsResult(this, false); 847 Message confirm = obtainMessage(JS_CONFIRM, result); 848 confirm.getData().putString("message", message); 849 confirm.getData().putString("url", url); 850 synchronized (this) { 851 sendMessage(confirm); 852 try { 853 wait(); 854 } catch (InterruptedException e) { 855 Log.e(LOGTAG, "Caught exception while waiting for jsConfirm"); 856 Log.e(LOGTAG, Log.getStackTraceString(e)); 857 } 858 } 859 return result.getResult(); 860 } 861 862 public String onJsPrompt(String url, String message, String defaultValue) { 863 // Do an unsynchronized quick check to avoid posting if no callback has 864 // been set. 865 if (mWebChromeClient == null) { 866 return null; 867 } 868 JsPromptResult result = new JsPromptResult(this); 869 Message prompt = obtainMessage(JS_PROMPT, result); 870 prompt.getData().putString("message", message); 871 prompt.getData().putString("default", defaultValue); 872 prompt.getData().putString("url", url); 873 synchronized (this) { 874 sendMessage(prompt); 875 try { 876 wait(); 877 } catch (InterruptedException e) { 878 Log.e(LOGTAG, "Caught exception while waiting for jsPrompt"); 879 Log.e(LOGTAG, Log.getStackTraceString(e)); 880 } 881 } 882 return result.getStringResult(); 883 } 884 885 public boolean onJsBeforeUnload(String url, String message) { 886 // Do an unsynchronized quick check to avoid posting if no callback has 887 // been set. 888 if (mWebChromeClient == null) { 889 return true; 890 } 891 JsResult result = new JsResult(this, true); 892 Message confirm = obtainMessage(JS_UNLOAD, result); 893 confirm.getData().putString("message", message); 894 confirm.getData().putString("url", url); 895 synchronized (this) { 896 sendMessage(confirm); 897 try { 898 wait(); 899 } catch (InterruptedException e) { 900 Log.e(LOGTAG, "Caught exception while waiting for jsUnload"); 901 Log.e(LOGTAG, Log.getStackTraceString(e)); 902 } 903 } 904 return result.getResult(); 905 } 906} 907