WebViewChromium.java revision 2c11b458a21170c4eacba6c072f695c465f1c083
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.res.Configuration; 20import android.graphics.Bitmap; 21import android.graphics.Canvas; 22import android.graphics.Paint; 23import android.graphics.Picture; 24import android.graphics.Rect; 25import android.graphics.drawable.Drawable; 26import android.net.http.SslCertificate; 27import android.os.Build; 28import android.os.Bundle; 29import android.os.CancellationSignal; 30import android.os.Message; 31import android.os.ParcelFileDescriptor; 32import android.print.PrintAttributes; 33import android.text.TextUtils; 34import android.util.Base64; 35import android.util.Log; 36import android.view.HardwareCanvas; 37import android.view.KeyEvent; 38import android.view.MotionEvent; 39import android.view.View; 40import android.view.ViewGroup; 41import android.view.accessibility.AccessibilityEvent; 42import android.view.accessibility.AccessibilityNodeInfo; 43import android.view.accessibility.AccessibilityNodeProvider; 44import android.view.inputmethod.EditorInfo; 45import android.view.inputmethod.InputConnection; 46import android.webkit.DownloadListener; 47import android.webkit.FindActionModeCallback; 48import android.webkit.JavascriptInterface; 49import android.webkit.ValueCallback; 50import android.webkit.WebBackForwardList; 51import android.webkit.WebChromeClient; 52import android.webkit.WebSettings; 53import android.webkit.WebView; 54import android.webkit.WebViewClient; 55import android.webkit.WebViewProvider; 56import android.widget.TextView; 57 58import org.chromium.android_webview.AwBrowserContext; 59import org.chromium.android_webview.AwContents; 60import org.chromium.android_webview.AwLayoutSizer; 61import org.chromium.android_webview.AwPdfExportAttributes; 62import org.chromium.base.ThreadUtils; 63import org.chromium.content.browser.LoadUrlParams; 64import org.chromium.net.NetworkChangeNotifier; 65 66import java.io.BufferedWriter; 67import java.io.File; 68import java.lang.annotation.Annotation; 69import java.util.concurrent.Callable; 70import java.util.concurrent.FutureTask; 71import java.util.concurrent.TimeUnit; 72import java.util.HashMap; 73import java.util.Map; 74 75/** 76 * This class is the delegate to which WebViewProxy forwards all API calls. 77 * 78 * Most of the actual functionality is implemented by AwContents (or ContentViewCore within 79 * it). This class also contains WebView-specific APIs that require the creation of other 80 * adapters (otherwise org.chromium.content would depend on the webview.chromium package) 81 * and a small set of no-op deprecated APIs. 82 */ 83class WebViewChromium implements WebViewProvider, 84 WebViewProvider.ScrollDelegate, WebViewProvider.ViewDelegate { 85 86 private static final String TAG = WebViewChromium.class.getSimpleName(); 87 88 // The WebView that this WebViewChromium is the provider for. 89 WebView mWebView; 90 // Lets us access protected View-derived methods on the WebView instance we're backing. 91 WebView.PrivateAccess mWebViewPrivate; 92 // The client adapter class. 93 private WebViewContentsClientAdapter mContentsClientAdapter; 94 95 // Variables for functionality provided by this adapter --------------------------------------- 96 // WebSettings adapter, lazily initialized in the getter 97 private WebSettings mWebSettings; 98 // The WebView wrapper for ContentViewCore and required browser compontents. 99 private AwContents mAwContents; 100 // Non-null if this webview is using the GL accelerated draw path. 101 private DrawGLFunctor mGLfunctor; 102 103 private AwBrowserContext mBrowserContext; 104 105 private final WebView.HitTestResult mHitTestResult; 106 107 private final int mAppTargetSdkVersion; 108 109 // This does not touch any global / non-threadsafe state, but note that 110 // init is ofter called right after and is NOT threadsafe. 111 public WebViewChromium(WebView webView, WebView.PrivateAccess webViewPrivate, 112 AwBrowserContext browserContext) { 113 mWebView = webView; 114 mWebViewPrivate = webViewPrivate; 115 mHitTestResult = new WebView.HitTestResult(); 116 mBrowserContext = browserContext; 117 mAppTargetSdkVersion = mWebView.getContext().getApplicationInfo().targetSdkVersion; 118 } 119 120 static void completeWindowCreation(WebView parent, WebView child) { 121 AwContents parentContents = ((WebViewChromium) parent.getWebViewProvider()).mAwContents; 122 AwContents childContents = 123 child == null ? null : ((WebViewChromium) child.getWebViewProvider()).mAwContents; 124 parentContents.supplyContentsForPopup(childContents); 125 } 126 127 private static <T> T runBlockingFuture(FutureTask<T> task) { 128 if (ThreadUtils.runningOnUiThread()) { 129 throw new IllegalStateException("This method should only be called off the UI thread"); 130 } 131 ThreadUtils.postOnUiThread(task); 132 try { 133 return task.get(4, TimeUnit.SECONDS); 134 } catch (Exception e) { // Timeout is one of the possible exceptions here 135 throw new RuntimeException("Probable deadlock detected due to WebView API being called " 136 + "on incorrect thread while the UI thread is blocked.", e); 137 } 138 } 139 140 // We have a 4 second timeout to try to detect deadlocks to detect and aid in debuggin 141 // deadlocks. 142 // Do not call this method while on the UI thread! 143 private void runVoidTaskOnUiThreadBlocking(Runnable r) { 144 FutureTask<Void> task = new FutureTask<Void>(r, null); 145 runBlockingFuture(task); 146 } 147 148 private static <T> T runOnUiThreadBlocking(Callable<T> c) { 149 return runBlockingFuture(new FutureTask<T>(c)); 150 } 151 152 // WebViewProvider methods -------------------------------------------------------------------- 153 154 @Override 155 public void init(final Map<String, Object> javaScriptInterfaces, 156 final boolean privateBrowsing) { 157 if (!ThreadUtils.runningOnUiThread()) { 158 runVoidTaskOnUiThreadBlocking(new Runnable() { 159 @Override 160 public void run() { 161 init(javaScriptInterfaces, privateBrowsing); 162 } 163 }); 164 return; 165 } 166 // BUG=6790250 |javaScriptInterfaces| was only ever used by the obsolete DumpRenderTree 167 // so is ignored. TODO: remove it from WebViewProvider. 168 final boolean isAccessFromFileURLsGrantedByDefault = 169 mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN; 170 final boolean areLegacyQuirksEnabled = 171 mAppTargetSdkVersion < Build.VERSION_CODES.KITKAT; 172 mContentsClientAdapter = new WebViewContentsClientAdapter(mWebView); 173 mAwContents = new AwContents(mBrowserContext, mWebView, new InternalAccessAdapter(), 174 mContentsClientAdapter, isAccessFromFileURLsGrantedByDefault, 175 new AwLayoutSizer(), areLegacyQuirksEnabled); 176 mWebSettings = new ContentSettingsAdapter(mAwContents.getSettings()); 177 178 if (privateBrowsing) { 179 final String msg = "Private browsing is not supported in WebView."; 180 if (mAppTargetSdkVersion >= Build.VERSION_CODES.KITKAT) { 181 throw new IllegalArgumentException(msg); 182 } else { 183 Log.w(TAG, msg); 184 // Intentionally irreversibly disable the webview instance, so that private 185 // user data cannot leak through misuse of a non-privateBrowing WebView instance. 186 // Can't just null out mAwContents as we never null-check it before use. 187 mAwContents.destroy(); 188 TextView warningLabel = new TextView(mWebView.getContext()); 189 warningLabel.setText(mWebView.getContext().getString( 190 com.android.internal.R.string.webviewchromium_private_browsing_warning)); 191 mWebView.addView(warningLabel); 192 } 193 } 194 195 } 196 197 private RuntimeException createThreadException() { 198 return new IllegalStateException("Calling View methods on another thread than the UI " + 199 "thread. PLEASE FILE A BUG! go/klp-webview-bug"); 200 } 201 202 // Intentionally not static, as no need to check thread on static methods 203 private void checkThread() { 204 if (!ThreadUtils.runningOnUiThread()) { 205 final RuntimeException threadViolation = createThreadException(); 206 ThreadUtils.postOnUiThread(new Runnable() { 207 @Override 208 public void run() { 209 throw threadViolation; 210 } 211 }); 212 throw createThreadException(); 213 } 214 } 215 216 @Override 217 public void setHorizontalScrollbarOverlay(final boolean overlay) { 218 if (!ThreadUtils.runningOnUiThread()) { 219 ThreadUtils.postOnUiThread(new Runnable() { 220 @Override 221 public void run() { 222 setHorizontalScrollbarOverlay(overlay); 223 } 224 }); 225 return; 226 } 227 mAwContents.setHorizontalScrollbarOverlay(overlay); 228 } 229 230 @Override 231 public void setVerticalScrollbarOverlay(final boolean overlay) { 232 if (!ThreadUtils.runningOnUiThread()) { 233 ThreadUtils.postOnUiThread(new Runnable() { 234 @Override 235 public void run() { 236 setVerticalScrollbarOverlay(overlay); 237 } 238 }); 239 return; 240 } 241 mAwContents.setVerticalScrollbarOverlay(overlay); 242 } 243 244 @Override 245 public boolean overlayHorizontalScrollbar() { 246 if (!ThreadUtils.runningOnUiThread()) { 247 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 248 @Override 249 public Boolean call() { 250 return overlayHorizontalScrollbar(); 251 } 252 }); 253 return ret; 254 } 255 return mAwContents.overlayHorizontalScrollbar(); 256 } 257 258 @Override 259 public boolean overlayVerticalScrollbar() { 260 if (!ThreadUtils.runningOnUiThread()) { 261 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 262 @Override 263 public Boolean call() { 264 return overlayVerticalScrollbar(); 265 } 266 }); 267 return ret; 268 } 269 return mAwContents.overlayVerticalScrollbar(); 270 } 271 272 @Override 273 public int getVisibleTitleHeight() { 274 // This is deprecated in WebView and should always return 0. 275 return 0; 276 } 277 278 @Override 279 public SslCertificate getCertificate() { 280 if (!ThreadUtils.runningOnUiThread()) { 281 SslCertificate ret = runOnUiThreadBlocking(new Callable<SslCertificate>() { 282 @Override 283 public SslCertificate call() { 284 return getCertificate(); 285 } 286 }); 287 return ret; 288 } 289 return mAwContents.getCertificate(); 290 } 291 292 @Override 293 public void setCertificate(SslCertificate certificate) { 294 // intentional no-op 295 } 296 297 @Override 298 public void savePassword(String host, String username, String password) { 299 // This is a deprecated API: intentional no-op. 300 } 301 302 @Override 303 public void setHttpAuthUsernamePassword(final String host, final String realm, 304 final String username, final String password) { 305 if (!ThreadUtils.runningOnUiThread()) { 306 ThreadUtils.postOnUiThread(new Runnable() { 307 @Override 308 public void run() { 309 setHttpAuthUsernamePassword(host, realm, username, password); 310 } 311 }); 312 return; 313 } 314 mAwContents.setHttpAuthUsernamePassword(host, realm, username, password); 315 } 316 317 @Override 318 public String[] getHttpAuthUsernamePassword(final String host, final String realm) { 319 if (!ThreadUtils.runningOnUiThread()) { 320 String[] ret = runOnUiThreadBlocking(new Callable<String[]>() { 321 @Override 322 public String[] call() { 323 return getHttpAuthUsernamePassword(host, realm); 324 } 325 }); 326 return ret; 327 } 328 return mAwContents.getHttpAuthUsernamePassword(host, realm); 329 } 330 331 @Override 332 public void destroy() { 333 if (!ThreadUtils.runningOnUiThread()) { 334 ThreadUtils.postOnUiThread(new Runnable() { 335 @Override 336 public void run() { 337 destroy(); 338 } 339 }); 340 return; 341 } 342 343 mAwContents.destroy(); 344 if (mGLfunctor != null) { 345 mGLfunctor.destroy(); 346 mGLfunctor = null; 347 } 348 } 349 350 @Override 351 public void setNetworkAvailable(final boolean networkUp) { 352 // Note that this purely toggles the JS navigator.online property. 353 // It does not in affect chromium or network stack state in any way. 354 if (!ThreadUtils.runningOnUiThread()) { 355 ThreadUtils.postOnUiThread(new Runnable() { 356 @Override 357 public void run() { 358 setNetworkAvailable(networkUp); 359 } 360 }); 361 return; 362 } 363 mAwContents.setNetworkAvailable(networkUp); 364 } 365 366 @Override 367 public WebBackForwardList saveState(final Bundle outState) { 368 if (!ThreadUtils.runningOnUiThread()) { 369 WebBackForwardList ret = runOnUiThreadBlocking(new Callable<WebBackForwardList>() { 370 @Override 371 public WebBackForwardList call() { 372 return saveState(outState); 373 } 374 }); 375 return ret; 376 } 377 if (outState == null) return null; 378 if (!mAwContents.saveState(outState)) return null; 379 return copyBackForwardList(); 380 } 381 382 @Override 383 public boolean savePicture(Bundle b, File dest) { 384 // Intentional no-op: hidden method on WebView. 385 return false; 386 } 387 388 @Override 389 public boolean restorePicture(Bundle b, File src) { 390 // Intentional no-op: hidden method on WebView. 391 return false; 392 } 393 394 @Override 395 public WebBackForwardList restoreState(final Bundle inState) { 396 if (!ThreadUtils.runningOnUiThread()) { 397 WebBackForwardList ret = runOnUiThreadBlocking(new Callable<WebBackForwardList>() { 398 @Override 399 public WebBackForwardList call() { 400 return restoreState(inState); 401 } 402 }); 403 return ret; 404 } 405 if (inState == null) return null; 406 if (!mAwContents.restoreState(inState)) return null; 407 return copyBackForwardList(); 408 } 409 410 @Override 411 public void loadUrl(String url, Map<String, String> additionalHttpHeaders) { 412 // TODO: We may actually want to do some sanity checks here (like filter about://chrome). 413 414 // For backwards compatibility, apps targeting less than K will have JS URLs evaluated 415 // directly and any result of the evaluation will not replace the current page content. 416 // Matching Chrome behavior more closely; apps targetting >= K that load a JS URL will 417 // have the result of that URL replace the content of the current page. 418 final String JAVASCRIPT_SCHEME = "javascript:"; 419 if (mAppTargetSdkVersion < Build.VERSION_CODES.KITKAT && 420 url != null && url.startsWith(JAVASCRIPT_SCHEME)) { 421 mAwContents.evaluateJavaScriptEvenIfNotYetNavigated( 422 url.substring(JAVASCRIPT_SCHEME.length())); 423 return; 424 } 425 426 LoadUrlParams params = new LoadUrlParams(url); 427 if (additionalHttpHeaders != null) params.setExtraHeaders(additionalHttpHeaders); 428 loadUrlOnUiThread(params); 429 } 430 431 @Override 432 public void loadUrl(String url) { 433 // Early out to match old WebView implementation 434 if (url == null) { 435 return; 436 } 437 loadUrl(url, null); 438 } 439 440 @Override 441 public void postUrl(String url, byte[] postData) { 442 LoadUrlParams params = LoadUrlParams.createLoadHttpPostParams(url, postData); 443 Map<String,String> headers = new HashMap<String,String>(); 444 headers.put("Content-Type", "application/x-www-form-urlencoded"); 445 params.setExtraHeaders(headers); 446 loadUrlOnUiThread(params); 447 } 448 449 private static String fixupMimeType(String mimeType) { 450 return TextUtils.isEmpty(mimeType) ? "text/html" : mimeType; 451 } 452 453 private static String fixupData(String data) { 454 return TextUtils.isEmpty(data) ? "" : data; 455 } 456 457 private static String fixupBase(String url) { 458 return TextUtils.isEmpty(url) ? "about:blank" : url; 459 } 460 461 private static String fixupHistory(String url) { 462 return TextUtils.isEmpty(url) ? "about:blank" : url; 463 } 464 465 private static boolean isBase64Encoded(String encoding) { 466 return "base64".equals(encoding); 467 } 468 469 @Override 470 public void loadData(String data, String mimeType, String encoding) { 471 loadUrlOnUiThread(LoadUrlParams.createLoadDataParams( 472 fixupData(data), fixupMimeType(mimeType), isBase64Encoded(encoding))); 473 } 474 475 @Override 476 public void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, 477 String historyUrl) { 478 data = fixupData(data); 479 mimeType = fixupMimeType(mimeType); 480 LoadUrlParams loadUrlParams; 481 baseUrl = fixupBase(baseUrl); 482 historyUrl = fixupHistory(historyUrl); 483 484 if (baseUrl.startsWith("data:")) { 485 // For backwards compatibility with WebViewClassic, we use the value of |encoding| 486 // as the charset, as long as it's not "base64". 487 boolean isBase64 = isBase64Encoded(encoding); 488 loadUrlParams = LoadUrlParams.createLoadDataParamsWithBaseUrl( 489 data, mimeType, isBase64, baseUrl, historyUrl, isBase64 ? null : encoding); 490 } else { 491 // When loading data with a non-data: base URL, the classic WebView would effectively 492 // "dump" that string of data into the WebView without going through regular URL 493 // loading steps such as decoding URL-encoded entities. We achieve this same behavior by 494 // base64 encoding the data that is passed here and then loading that as a data: URL. 495 try { 496 loadUrlParams = LoadUrlParams.createLoadDataParamsWithBaseUrl( 497 Base64.encodeToString(data.getBytes("utf-8"), Base64.DEFAULT), mimeType, 498 true, baseUrl, historyUrl, "utf-8"); 499 } catch (java.io.UnsupportedEncodingException e) { 500 Log.wtf(TAG, "Unable to load data string " + data, e); 501 return; 502 } 503 } 504 loadUrlOnUiThread(loadUrlParams); 505 } 506 507 private void loadUrlOnUiThread(final LoadUrlParams loadUrlParams) { 508 if (ThreadUtils.runningOnUiThread()) { 509 mAwContents.loadUrl(loadUrlParams); 510 } else { 511 // Disallowed in WebView API for apps targetting a new SDK 512 assert mAppTargetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2; 513 ThreadUtils.postOnUiThread(new Runnable() { 514 @Override 515 public void run() { 516 mAwContents.loadUrl(loadUrlParams); 517 } 518 }); 519 } 520 } 521 522 public void evaluateJavaScript(String script, ValueCallback<String> resultCallback) { 523 checkThread(); 524 mAwContents.evaluateJavaScript(script, resultCallback); 525 } 526 527 @Override 528 public void saveWebArchive(String filename) { 529 saveWebArchive(filename, false, null); 530 } 531 532 @Override 533 public void saveWebArchive(final String basename, final boolean autoname, 534 final ValueCallback<String> callback) { 535 if (!ThreadUtils.runningOnUiThread()) { 536 ThreadUtils.postOnUiThread(new Runnable() { 537 @Override 538 public void run() { 539 saveWebArchive(basename, autoname, callback); 540 } 541 }); 542 return; 543 } 544 mAwContents.saveWebArchive(basename, autoname, callback); 545 } 546 547 @Override 548 public void stopLoading() { 549 if (!ThreadUtils.runningOnUiThread()) { 550 ThreadUtils.postOnUiThread(new Runnable() { 551 @Override 552 public void run() { 553 stopLoading(); 554 } 555 }); 556 return; 557 } 558 559 mAwContents.stopLoading(); 560 } 561 562 @Override 563 public void reload() { 564 if (!ThreadUtils.runningOnUiThread()) { 565 ThreadUtils.postOnUiThread(new Runnable() { 566 @Override 567 public void run() { 568 reload(); 569 } 570 }); 571 return; 572 } 573 mAwContents.reload(); 574 } 575 576 @Override 577 public boolean canGoBack() { 578 if (!ThreadUtils.runningOnUiThread()) { 579 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 580 @Override 581 public Boolean call() { 582 return canGoBack(); 583 } 584 }); 585 return ret; 586 } 587 return mAwContents.canGoBack(); 588 } 589 590 @Override 591 public void goBack() { 592 if (!ThreadUtils.runningOnUiThread()) { 593 ThreadUtils.postOnUiThread(new Runnable() { 594 @Override 595 public void run() { 596 goBack(); 597 } 598 }); 599 return; 600 } 601 mAwContents.goBack(); 602 } 603 604 @Override 605 public boolean canGoForward() { 606 if (!ThreadUtils.runningOnUiThread()) { 607 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 608 @Override 609 public Boolean call() { 610 return canGoForward(); 611 } 612 }); 613 return ret; 614 } 615 return mAwContents.canGoForward(); 616 } 617 618 @Override 619 public void goForward() { 620 if (!ThreadUtils.runningOnUiThread()) { 621 ThreadUtils.postOnUiThread(new Runnable() { 622 @Override 623 public void run() { 624 goForward(); 625 } 626 }); 627 return; 628 } 629 mAwContents.goForward(); 630 } 631 632 @Override 633 public boolean canGoBackOrForward(final int steps) { 634 if (!ThreadUtils.runningOnUiThread()) { 635 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 636 @Override 637 public Boolean call() { 638 return canGoBackOrForward(steps); 639 } 640 }); 641 return ret; 642 } 643 return mAwContents.canGoBackOrForward(steps); 644 } 645 646 @Override 647 public void goBackOrForward(final int steps) { 648 if (!ThreadUtils.runningOnUiThread()) { 649 ThreadUtils.postOnUiThread(new Runnable() { 650 @Override 651 public void run() { 652 goBackOrForward(steps); 653 } 654 }); 655 return; 656 } 657 mAwContents.goBackOrForward(steps); 658 } 659 660 @Override 661 public boolean isPrivateBrowsingEnabled() { 662 // Not supported in this WebView implementation. 663 return false; 664 } 665 666 @Override 667 public boolean pageUp(final boolean top) { 668 if (!ThreadUtils.runningOnUiThread()) { 669 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 670 @Override 671 public Boolean call() { 672 return pageUp(top); 673 } 674 }); 675 return ret; 676 } 677 return mAwContents.pageUp(top); 678 } 679 680 @Override 681 public boolean pageDown(final boolean bottom) { 682 if (!ThreadUtils.runningOnUiThread()) { 683 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 684 @Override 685 public Boolean call() { 686 return pageDown(bottom); 687 } 688 }); 689 return ret; 690 } 691 return mAwContents.pageDown(bottom); 692 } 693 694 @Override 695 public void clearView() { 696 if (!ThreadUtils.runningOnUiThread()) { 697 ThreadUtils.postOnUiThread(new Runnable() { 698 @Override 699 public void run() { 700 clearView(); 701 } 702 }); 703 return; 704 } 705 UnimplementedWebViewApi.invoke(); 706 } 707 708 @Override 709 public Picture capturePicture() { 710 if (!ThreadUtils.runningOnUiThread()) { 711 Picture ret = runOnUiThreadBlocking(new Callable<Picture>() { 712 @Override 713 public Picture call() { 714 return capturePicture(); 715 } 716 }); 717 return ret; 718 } 719 return mAwContents.capturePicture(); 720 } 721 722 @Override 723 public void exportToPdf(ParcelFileDescriptor fd, PrintAttributes attributes, 724 ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal) 725 throws java.io.IOException { 726 checkThread(); 727 // We convert frameworks attributes to an android_webview specific print attributes 728 // so we do not tie upstreaming android_webview changes to installation of correct 729 // SDK to try bots. 730 if (attributes == null) { 731 throw new IllegalArgumentException("attributes cannot be null"); 732 } 733 if (attributes.getMediaSize() == null) { 734 throw new IllegalArgumentException("attributes must specify a media size"); 735 } 736 if (attributes.getResolution() == null) { 737 throw new IllegalArgumentException("attributes must specify print resolution"); 738 } 739 if (attributes.getMargins() == null) { 740 throw new IllegalArgumentException("attributes must specify margins"); 741 } 742 AwPdfExportAttributes pdfAttributes = new AwPdfExportAttributes(); 743 pdfAttributes.pageWidth = attributes.getMediaSize().getWidthMils(); 744 pdfAttributes.pageHeight = attributes.getMediaSize().getHeightMils(); 745 pdfAttributes.dpi = getPrintDpi(attributes); 746 pdfAttributes.leftMargin = attributes.getMargins().getLeftMils(); 747 pdfAttributes.rightMargin = attributes.getMargins().getRightMils(); 748 pdfAttributes.topMargin = attributes.getMargins().getTopMils(); 749 pdfAttributes.bottomMargin = attributes.getMargins().getBottomMils(); 750 751 mAwContents.getPdfExporter().exportToPdf(fd, pdfAttributes, resultCallback, 752 cancellationSignal); 753 } 754 755 private static int getPrintDpi(PrintAttributes attributes) { 756 // TODO(sgurun) android print attributes support horizontal and 757 // vertical DPI. Chrome has only one DPI. Revisit this. 758 int horizontalDpi = attributes.getResolution().getHorizontalDpi(); 759 int verticalDpi = attributes.getResolution().getVerticalDpi(); 760 if (horizontalDpi != verticalDpi) { 761 Log.w(TAG, "Horizontal and vertical DPIs differ. Using horizontal DPI " + 762 " hDpi=" + horizontalDpi + " vDPI=" + verticalDpi); 763 } 764 return horizontalDpi; 765 } 766 767 @Override 768 public float getScale() { 769 // No checkThread() as it is mostly thread safe (workaround for b/10652991). 770 return mAwContents.getScale(); 771 } 772 773 @Override 774 public void setInitialScale(final int scaleInPercent) { 775 if (!ThreadUtils.runningOnUiThread()) { 776 ThreadUtils.postOnUiThread(new Runnable() { 777 @Override 778 public void run() { 779 setInitialScale(scaleInPercent); 780 } 781 }); 782 return; 783 } 784 mAwContents.getSettings().setInitialPageScale(scaleInPercent); 785 } 786 787 @Override 788 public void invokeZoomPicker() { 789 if (!ThreadUtils.runningOnUiThread()) { 790 ThreadUtils.postOnUiThread(new Runnable() { 791 @Override 792 public void run() { 793 invokeZoomPicker(); 794 } 795 }); 796 return; 797 } 798 mAwContents.invokeZoomPicker(); 799 } 800 801 @Override 802 public WebView.HitTestResult getHitTestResult() { 803 if (!ThreadUtils.runningOnUiThread()) { 804 WebView.HitTestResult ret = runOnUiThreadBlocking( 805 new Callable<WebView.HitTestResult>() { 806 @Override 807 public WebView.HitTestResult call() { 808 return getHitTestResult(); 809 } 810 }); 811 return ret; 812 } 813 AwContents.HitTestData data = mAwContents.getLastHitTestResult(); 814 mHitTestResult.setType(data.hitTestResultType); 815 mHitTestResult.setExtra(data.hitTestResultExtraData); 816 return mHitTestResult; 817 } 818 819 @Override 820 public void requestFocusNodeHref(final Message hrefMsg) { 821 if (!ThreadUtils.runningOnUiThread()) { 822 ThreadUtils.postOnUiThread(new Runnable() { 823 @Override 824 public void run() { 825 requestFocusNodeHref(hrefMsg); 826 } 827 }); 828 return; 829 } 830 mAwContents.requestFocusNodeHref(hrefMsg); 831 } 832 833 @Override 834 public void requestImageRef(final Message msg) { 835 if (!ThreadUtils.runningOnUiThread()) { 836 ThreadUtils.postOnUiThread(new Runnable() { 837 @Override 838 public void run() { 839 requestImageRef(msg); 840 } 841 }); 842 return; 843 } 844 mAwContents.requestImageRef(msg); 845 } 846 847 @Override 848 public String getUrl() { 849 if (!ThreadUtils.runningOnUiThread()) { 850 String ret = runOnUiThreadBlocking(new Callable<String>() { 851 @Override 852 public String call() { 853 return getUrl(); 854 } 855 }); 856 return ret; 857 } 858 String url = mAwContents.getUrl(); 859 if (url == null || url.trim().isEmpty()) return null; 860 return url; 861 } 862 863 @Override 864 public String getOriginalUrl() { 865 if (!ThreadUtils.runningOnUiThread()) { 866 String ret = runOnUiThreadBlocking(new Callable<String>() { 867 @Override 868 public String call() { 869 return getOriginalUrl(); 870 } 871 }); 872 return ret; 873 } 874 String url = mAwContents.getOriginalUrl(); 875 if (url == null || url.trim().isEmpty()) return null; 876 return url; 877 } 878 879 @Override 880 public String getTitle() { 881 if (!ThreadUtils.runningOnUiThread()) { 882 String ret = runOnUiThreadBlocking(new Callable<String>() { 883 @Override 884 public String call() { 885 return getTitle(); 886 } 887 }); 888 return ret; 889 } 890 return mAwContents.getTitle(); 891 } 892 893 @Override 894 public Bitmap getFavicon() { 895 if (!ThreadUtils.runningOnUiThread()) { 896 Bitmap ret = runOnUiThreadBlocking(new Callable<Bitmap>() { 897 @Override 898 public Bitmap call() { 899 return getFavicon(); 900 } 901 }); 902 return ret; 903 } 904 return mAwContents.getFavicon(); 905 } 906 907 @Override 908 public String getTouchIconUrl() { 909 // Intentional no-op: hidden method on WebView. 910 return null; 911 } 912 913 @Override 914 public int getProgress() { 915 // No checkThread() because the value is cached java side (workaround for b/10533304). 916 return mAwContents.getMostRecentProgress(); 917 } 918 919 @Override 920 public int getContentHeight() { 921 // No checkThread() as it is mostly thread safe (workaround for b/10594869). 922 return mAwContents.getContentHeightCss(); 923 } 924 925 @Override 926 public int getContentWidth() { 927 // No checkThread() as it is mostly thread safe (workaround for b/10594869). 928 return mAwContents.getContentWidthCss(); 929 } 930 931 @Override 932 public void pauseTimers() { 933 if (!ThreadUtils.runningOnUiThread()) { 934 ThreadUtils.postOnUiThread(new Runnable() { 935 @Override 936 public void run() { 937 pauseTimers(); 938 } 939 }); 940 return; 941 } 942 mAwContents.pauseTimers(); 943 } 944 945 @Override 946 public void resumeTimers() { 947 if (!ThreadUtils.runningOnUiThread()) { 948 ThreadUtils.postOnUiThread(new Runnable() { 949 @Override 950 public void run() { 951 resumeTimers(); 952 } 953 }); 954 return; 955 } 956 mAwContents.resumeTimers(); 957 } 958 959 @Override 960 public void onPause() { 961 if (!ThreadUtils.runningOnUiThread()) { 962 ThreadUtils.postOnUiThread(new Runnable() { 963 @Override 964 public void run() { 965 onPause(); 966 } 967 }); 968 return; 969 } 970 mAwContents.onPause(); 971 } 972 973 @Override 974 public void onResume() { 975 if (!ThreadUtils.runningOnUiThread()) { 976 ThreadUtils.postOnUiThread(new Runnable() { 977 @Override 978 public void run() { 979 onResume(); 980 } 981 }); 982 return; 983 } 984 mAwContents.onResume(); 985 } 986 987 @Override 988 public boolean isPaused() { 989 if (!ThreadUtils.runningOnUiThread()) { 990 Boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 991 @Override 992 public Boolean call() { 993 return isPaused(); 994 } 995 }); 996 return ret; 997 } 998 return mAwContents.isPaused(); 999 } 1000 1001 @Override 1002 public void freeMemory() { 1003 // Intentional no-op. Memory is managed automatically by Chromium. 1004 } 1005 1006 @Override 1007 public void clearCache(final boolean includeDiskFiles) { 1008 if (!ThreadUtils.runningOnUiThread()) { 1009 ThreadUtils.postOnUiThread(new Runnable() { 1010 @Override 1011 public void run() { 1012 clearCache(includeDiskFiles); 1013 } 1014 }); 1015 return; 1016 } 1017 mAwContents.clearCache(includeDiskFiles); 1018 } 1019 1020 /** 1021 * This is a poorly named method, but we keep it for historical reasons. 1022 */ 1023 @Override 1024 public void clearFormData() { 1025 if (!ThreadUtils.runningOnUiThread()) { 1026 ThreadUtils.postOnUiThread(new Runnable() { 1027 @Override 1028 public void run() { 1029 clearFormData(); 1030 } 1031 }); 1032 return; 1033 } 1034 mAwContents.hideAutofillPopup(); 1035 } 1036 1037 @Override 1038 public void clearHistory() { 1039 if (!ThreadUtils.runningOnUiThread()) { 1040 ThreadUtils.postOnUiThread(new Runnable() { 1041 @Override 1042 public void run() { 1043 clearHistory(); 1044 } 1045 }); 1046 return; 1047 } 1048 mAwContents.clearHistory(); 1049 } 1050 1051 @Override 1052 public void clearSslPreferences() { 1053 if (!ThreadUtils.runningOnUiThread()) { 1054 ThreadUtils.postOnUiThread(new Runnable() { 1055 @Override 1056 public void run() { 1057 clearSslPreferences(); 1058 } 1059 }); 1060 return; 1061 } 1062 mAwContents.clearSslPreferences(); 1063 } 1064 1065 @Override 1066 public WebBackForwardList copyBackForwardList() { 1067 if (!ThreadUtils.runningOnUiThread()) { 1068 WebBackForwardList ret = runOnUiThreadBlocking(new Callable<WebBackForwardList>() { 1069 @Override 1070 public WebBackForwardList call() { 1071 return copyBackForwardList(); 1072 } 1073 }); 1074 return ret; 1075 } 1076 return new WebBackForwardListChromium( 1077 mAwContents.getNavigationHistory()); 1078 } 1079 1080 @Override 1081 public void setFindListener(WebView.FindListener listener) { 1082 mContentsClientAdapter.setFindListener(listener); 1083 } 1084 1085 @Override 1086 public void findNext(final boolean forwards) { 1087 if (!ThreadUtils.runningOnUiThread()) { 1088 ThreadUtils.postOnUiThread(new Runnable() { 1089 @Override 1090 public void run() { 1091 findNext(forwards); 1092 } 1093 }); 1094 return; 1095 } 1096 mAwContents.findNext(forwards); 1097 } 1098 1099 @Override 1100 public int findAll(final String searchString) { 1101 findAllAsync(searchString); 1102 return 0; 1103 } 1104 1105 @Override 1106 public void findAllAsync(final String searchString) { 1107 if (!ThreadUtils.runningOnUiThread()) { 1108 ThreadUtils.postOnUiThread(new Runnable() { 1109 @Override 1110 public void run() { 1111 findAllAsync(searchString); 1112 } 1113 }); 1114 return; 1115 } 1116 mAwContents.findAllAsync(searchString); 1117 } 1118 1119 @Override 1120 public boolean showFindDialog(final String text, final boolean showIme) { 1121 if (!ThreadUtils.runningOnUiThread()) { 1122 return false; 1123 } 1124 if (mWebView.getParent() == null) { 1125 return false; 1126 } 1127 1128 FindActionModeCallback findAction = new FindActionModeCallback(mWebView.getContext()); 1129 if (findAction == null) { 1130 return false; 1131 } 1132 1133 mWebView.startActionMode(findAction); 1134 findAction.setWebView(mWebView); 1135 if (showIme) { 1136 findAction.showSoftInput(); 1137 } 1138 1139 if (text != null) { 1140 findAction.setText(text); 1141 findAction.findAll(); 1142 } 1143 1144 return true; 1145 } 1146 1147 @Override 1148 public void notifyFindDialogDismissed() { 1149 if (!ThreadUtils.runningOnUiThread()) { 1150 ThreadUtils.postOnUiThread(new Runnable() { 1151 @Override 1152 public void run() { 1153 notifyFindDialogDismissed(); 1154 } 1155 }); 1156 return; 1157 } 1158 clearMatches(); 1159 } 1160 1161 @Override 1162 public void clearMatches() { 1163 if (!ThreadUtils.runningOnUiThread()) { 1164 ThreadUtils.postOnUiThread(new Runnable() { 1165 @Override 1166 public void run() { 1167 clearMatches(); 1168 } 1169 }); 1170 return; 1171 } 1172 mAwContents.clearMatches(); 1173 } 1174 1175 @Override 1176 public void documentHasImages(final Message response) { 1177 if (!ThreadUtils.runningOnUiThread()) { 1178 ThreadUtils.postOnUiThread(new Runnable() { 1179 @Override 1180 public void run() { 1181 documentHasImages(response); 1182 } 1183 }); 1184 return; 1185 } 1186 mAwContents.documentHasImages(response); 1187 } 1188 1189 @Override 1190 public void setWebViewClient(WebViewClient client) { 1191 mContentsClientAdapter.setWebViewClient(client); 1192 } 1193 1194 @Override 1195 public void setDownloadListener(DownloadListener listener) { 1196 mContentsClientAdapter.setDownloadListener(listener); 1197 } 1198 1199 @Override 1200 public void setWebChromeClient(WebChromeClient client) { 1201 mContentsClientAdapter.setWebChromeClient(client); 1202 } 1203 1204 @Override 1205 public void setPictureListener(final WebView.PictureListener listener) { 1206 if (!ThreadUtils.runningOnUiThread()) { 1207 ThreadUtils.postOnUiThread(new Runnable() { 1208 @Override 1209 public void run() { 1210 setPictureListener(listener); 1211 } 1212 }); 1213 return; 1214 } 1215 mContentsClientAdapter.setPictureListener(listener); 1216 mAwContents.enableOnNewPicture(listener != null, 1217 mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR2); 1218 } 1219 1220 @Override 1221 public void addJavascriptInterface(final Object obj, final String interfaceName) { 1222 if (!ThreadUtils.runningOnUiThread()) { 1223 ThreadUtils.postOnUiThread(new Runnable() { 1224 @Override 1225 public void run() { 1226 addJavascriptInterface(obj, interfaceName); 1227 } 1228 }); 1229 return; 1230 } 1231 Class<? extends Annotation> requiredAnnotation = null; 1232 if (mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 1233 requiredAnnotation = JavascriptInterface.class; 1234 } 1235 mAwContents.addPossiblyUnsafeJavascriptInterface(obj, interfaceName, requiredAnnotation); 1236 } 1237 1238 @Override 1239 public void removeJavascriptInterface(final String interfaceName) { 1240 if (!ThreadUtils.runningOnUiThread()) { 1241 ThreadUtils.postOnUiThread(new Runnable() { 1242 @Override 1243 public void run() { 1244 removeJavascriptInterface(interfaceName); 1245 } 1246 }); 1247 return; 1248 } 1249 mAwContents.removeJavascriptInterface(interfaceName); 1250 } 1251 1252 @Override 1253 public WebSettings getSettings() { 1254 return mWebSettings; 1255 } 1256 1257 @Override 1258 public void setMapTrackballToArrowKeys(boolean setMap) { 1259 // This is a deprecated API: intentional no-op. 1260 } 1261 1262 @Override 1263 public void flingScroll(final int vx, final int vy) { 1264 if (!ThreadUtils.runningOnUiThread()) { 1265 ThreadUtils.postOnUiThread(new Runnable() { 1266 @Override 1267 public void run() { 1268 flingScroll(vx, vy); 1269 } 1270 }); 1271 return; 1272 } 1273 mAwContents.flingScroll(vx, vy); 1274 } 1275 1276 @Override 1277 public View getZoomControls() { 1278 if (!ThreadUtils.runningOnUiThread()) { 1279 return null; 1280 } 1281 1282 // This was deprecated in 2009 and hidden in JB MR1, so just provide the minimum needed 1283 // to stop very out-dated applications from crashing. 1284 Log.w(TAG, "WebView doesn't support getZoomControls"); 1285 return mAwContents.getSettings().supportZoom() ? new View(mWebView.getContext()) : null; 1286 } 1287 1288 @Override 1289 public boolean canZoomIn() { 1290 if (!ThreadUtils.runningOnUiThread()) { 1291 return false; 1292 } 1293 return mAwContents.canZoomIn(); 1294 } 1295 1296 @Override 1297 public boolean canZoomOut() { 1298 if (!ThreadUtils.runningOnUiThread()) { 1299 return false; 1300 } 1301 return mAwContents.canZoomOut(); 1302 } 1303 1304 @Override 1305 public boolean zoomIn() { 1306 if (!ThreadUtils.runningOnUiThread()) { 1307 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1308 @Override 1309 public Boolean call() { 1310 return zoomIn(); 1311 } 1312 }); 1313 return ret; 1314 } 1315 return mAwContents.zoomIn(); 1316 } 1317 1318 @Override 1319 public boolean zoomOut() { 1320 if (!ThreadUtils.runningOnUiThread()) { 1321 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1322 @Override 1323 public Boolean call() { 1324 return zoomOut(); 1325 } 1326 }); 1327 return ret; 1328 } 1329 return mAwContents.zoomOut(); 1330 } 1331 1332 @Override 1333 public void dumpViewHierarchyWithProperties(BufferedWriter out, int level) { 1334 UnimplementedWebViewApi.invoke(); 1335 } 1336 1337 @Override 1338 public View findHierarchyView(String className, int hashCode) { 1339 UnimplementedWebViewApi.invoke(); 1340 return null; 1341 } 1342 1343 // WebViewProvider glue methods --------------------------------------------------------------- 1344 1345 @Override 1346 // This needs to be kept thread safe! 1347 public WebViewProvider.ViewDelegate getViewDelegate() { 1348 return this; 1349 } 1350 1351 @Override 1352 // This needs to be kept thread safe! 1353 public WebViewProvider.ScrollDelegate getScrollDelegate() { 1354 return this; 1355 } 1356 1357 1358 // WebViewProvider.ViewDelegate implementation ------------------------------------------------ 1359 1360 // TODO: remove from WebViewProvider and use default implementation from 1361 // ViewGroup. 1362 // @Override 1363 public boolean shouldDelayChildPressedState() { 1364 if (!ThreadUtils.runningOnUiThread()) { 1365 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1366 @Override 1367 public Boolean call() { 1368 return shouldDelayChildPressedState(); 1369 } 1370 }); 1371 return ret; 1372 } 1373 return true; 1374 } 1375 1376// @Override 1377 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 1378 if (!ThreadUtils.runningOnUiThread()) { 1379 AccessibilityNodeProvider ret = runOnUiThreadBlocking( 1380 new Callable<AccessibilityNodeProvider>() { 1381 @Override 1382 public AccessibilityNodeProvider call() { 1383 return getAccessibilityNodeProvider(); 1384 } 1385 }); 1386 return ret; 1387 } 1388 return mAwContents.getAccessibilityNodeProvider(); 1389 } 1390 1391 @Override 1392 public void onInitializeAccessibilityNodeInfo(final AccessibilityNodeInfo info) { 1393 if (!ThreadUtils.runningOnUiThread()) { 1394 runVoidTaskOnUiThreadBlocking(new Runnable() { 1395 @Override 1396 public void run() { 1397 onInitializeAccessibilityNodeInfo(info); 1398 } 1399 }); 1400 return; 1401 } 1402 mAwContents.onInitializeAccessibilityNodeInfo(info); 1403 } 1404 1405 @Override 1406 public void onInitializeAccessibilityEvent(final AccessibilityEvent event) { 1407 if (!ThreadUtils.runningOnUiThread()) { 1408 runVoidTaskOnUiThreadBlocking(new Runnable() { 1409 @Override 1410 public void run() { 1411 onInitializeAccessibilityEvent(event); 1412 } 1413 }); 1414 return; 1415 } 1416 mAwContents.onInitializeAccessibilityEvent(event); 1417 } 1418 1419 @Override 1420 public boolean performAccessibilityAction(final int action, final Bundle arguments) { 1421 if (!ThreadUtils.runningOnUiThread()) { 1422 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1423 @Override 1424 public Boolean call() { 1425 return performAccessibilityAction(action, arguments); 1426 } 1427 }); 1428 return ret; 1429 } 1430 if (mAwContents.supportsAccessibilityAction(action)) { 1431 return mAwContents.performAccessibilityAction(action, arguments); 1432 } 1433 return mWebViewPrivate.super_performAccessibilityAction(action, arguments); 1434 } 1435 1436 @Override 1437 public void setOverScrollMode(final int mode) { 1438 if (!ThreadUtils.runningOnUiThread()) { 1439 ThreadUtils.postOnUiThread(new Runnable() { 1440 @Override 1441 public void run() { 1442 setOverScrollMode(mode); 1443 } 1444 }); 1445 return; 1446 } 1447 // This gets called from the android.view.View c'tor that WebView inherits from. This 1448 // causes the method to be called when mAwContents == null. 1449 // It's safe to ignore these calls however since AwContents will read the current value of 1450 // this setting when it's created. 1451 if (mAwContents != null) { 1452 mAwContents.setOverScrollMode(mode); 1453 } 1454 } 1455 1456 @Override 1457 public void setScrollBarStyle(final int style) { 1458 if (!ThreadUtils.runningOnUiThread()) { 1459 ThreadUtils.postOnUiThread(new Runnable() { 1460 @Override 1461 public void run() { 1462 setScrollBarStyle(style); 1463 } 1464 }); 1465 return; 1466 } 1467 mAwContents.setScrollBarStyle(style); 1468 } 1469 1470 @Override 1471 public void onDrawVerticalScrollBar(final Canvas canvas, final Drawable scrollBar, final int l, 1472 final int t, final int r, final int b) { 1473 if (!ThreadUtils.runningOnUiThread()) { 1474 runVoidTaskOnUiThreadBlocking(new Runnable() { 1475 @Override 1476 public void run() { 1477 onDrawVerticalScrollBar(canvas, scrollBar, l, t, r, b); 1478 } 1479 }); 1480 return; 1481 } 1482 // WebViewClassic was overriding this method to handle rubberband over-scroll. Since 1483 // WebViewChromium doesn't support that the vanilla implementation of this method can be 1484 // used. 1485 mWebViewPrivate.super_onDrawVerticalScrollBar(canvas, scrollBar, l, t, r, b); 1486 } 1487 1488 @Override 1489 public void onOverScrolled(final int scrollX, final int scrollY, final boolean clampedX, 1490 final boolean clampedY) { 1491 if (!ThreadUtils.runningOnUiThread()) { 1492 ThreadUtils.postOnUiThread(new Runnable() { 1493 @Override 1494 public void run() { 1495 onOverScrolled(scrollX, scrollY, clampedX, clampedY); 1496 } 1497 }); 1498 return; 1499 } 1500 mAwContents.onContainerViewOverScrolled(scrollX, scrollY, clampedX, clampedY); 1501 } 1502 1503 @Override 1504 public void onWindowVisibilityChanged(final int visibility) { 1505 if (!ThreadUtils.runningOnUiThread()) { 1506 ThreadUtils.postOnUiThread(new Runnable() { 1507 @Override 1508 public void run() { 1509 onWindowVisibilityChanged(visibility); 1510 } 1511 }); 1512 return; 1513 } 1514 mAwContents.onWindowVisibilityChanged(visibility); 1515 } 1516 1517 @Override 1518 public void onDraw(final Canvas canvas) { 1519 if (!ThreadUtils.runningOnUiThread()) { 1520 runVoidTaskOnUiThreadBlocking(new Runnable() { 1521 @Override 1522 public void run() { 1523 onDraw(canvas); 1524 } 1525 }); 1526 return; 1527 } 1528 mAwContents.onDraw(canvas); 1529 } 1530 1531 @Override 1532 public void setLayoutParams(final ViewGroup.LayoutParams layoutParams) { 1533 if (!ThreadUtils.runningOnUiThread()) { 1534 ThreadUtils.postOnUiThread(new Runnable() { 1535 @Override 1536 public void run() { 1537 setLayoutParams(layoutParams); 1538 } 1539 }); 1540 return; 1541 } 1542 mWebViewPrivate.super_setLayoutParams(layoutParams); 1543 } 1544 1545 @Override 1546 public boolean performLongClick() { 1547 if (!ThreadUtils.runningOnUiThread()) { 1548 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1549 @Override 1550 public Boolean call() { 1551 return performLongClick(); 1552 } 1553 }); 1554 return ret; 1555 } 1556 return mWebViewPrivate.super_performLongClick(); 1557 } 1558 1559 @Override 1560 public void onConfigurationChanged(final Configuration newConfig) { 1561 if (!ThreadUtils.runningOnUiThread()) { 1562 ThreadUtils.postOnUiThread(new Runnable() { 1563 @Override 1564 public void run() { 1565 onConfigurationChanged(newConfig); 1566 } 1567 }); 1568 return; 1569 } 1570 mAwContents.onConfigurationChanged(newConfig); 1571 } 1572 1573 @Override 1574 public InputConnection onCreateInputConnection(final EditorInfo outAttrs) { 1575 if (!ThreadUtils.runningOnUiThread()) { 1576 InputConnection ret = runOnUiThreadBlocking(new Callable<InputConnection>() { 1577 @Override 1578 public InputConnection call() { 1579 return onCreateInputConnection(outAttrs); 1580 } 1581 }); 1582 return ret; 1583 } 1584 return mAwContents.onCreateInputConnection(outAttrs); 1585 } 1586 1587 @Override 1588 public boolean onKeyMultiple(final int keyCode, final int repeatCount, final KeyEvent event) { 1589 if (!ThreadUtils.runningOnUiThread()) { 1590 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1591 @Override 1592 public Boolean call() { 1593 return onKeyMultiple(keyCode, repeatCount, event); 1594 } 1595 }); 1596 return ret; 1597 } 1598 UnimplementedWebViewApi.invoke(); 1599 return false; 1600 } 1601 1602 @Override 1603 public boolean onKeyDown(final int keyCode, final KeyEvent event) { 1604 if (!ThreadUtils.runningOnUiThread()) { 1605 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1606 @Override 1607 public Boolean call() { 1608 return onKeyDown(keyCode, event); 1609 } 1610 }); 1611 return ret; 1612 } 1613 UnimplementedWebViewApi.invoke(); 1614 return false; 1615 } 1616 1617 @Override 1618 public boolean onKeyUp(final int keyCode, final KeyEvent event) { 1619 if (!ThreadUtils.runningOnUiThread()) { 1620 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1621 @Override 1622 public Boolean call() { 1623 return onKeyUp(keyCode, event); 1624 } 1625 }); 1626 return ret; 1627 } 1628 return mAwContents.onKeyUp(keyCode, event); 1629 } 1630 1631 @Override 1632 public void onAttachedToWindow() { 1633 if (!ThreadUtils.runningOnUiThread()) { 1634 ThreadUtils.postOnUiThread(new Runnable() { 1635 @Override 1636 public void run() { 1637 onAttachedToWindow(); 1638 } 1639 }); 1640 return; 1641 } 1642 mAwContents.onAttachedToWindow(); 1643 } 1644 1645 @Override 1646 public void onDetachedFromWindow() { 1647 if (!ThreadUtils.runningOnUiThread()) { 1648 ThreadUtils.postOnUiThread(new Runnable() { 1649 @Override 1650 public void run() { 1651 onDetachedFromWindow(); 1652 } 1653 }); 1654 return; 1655 } 1656 mAwContents.onDetachedFromWindow(); 1657 if (mGLfunctor != null) { 1658 mGLfunctor.detach(); 1659 } 1660 } 1661 1662 @Override 1663 public void onVisibilityChanged(final View changedView, final int visibility) { 1664 if (!ThreadUtils.runningOnUiThread()) { 1665 ThreadUtils.postOnUiThread(new Runnable() { 1666 @Override 1667 public void run() { 1668 onVisibilityChanged(changedView, visibility); 1669 } 1670 }); 1671 return; 1672 } 1673 // The AwContents will find out the container view visibility before the first draw so we 1674 // can safely ignore onVisibilityChanged callbacks that happen before init(). 1675 if (mAwContents != null) { 1676 mAwContents.onVisibilityChanged(changedView, visibility); 1677 } 1678 } 1679 1680 @Override 1681 public void onWindowFocusChanged(final boolean hasWindowFocus) { 1682 if (!ThreadUtils.runningOnUiThread()) { 1683 ThreadUtils.postOnUiThread(new Runnable() { 1684 @Override 1685 public void run() { 1686 onWindowFocusChanged(hasWindowFocus); 1687 } 1688 }); 1689 return; 1690 } 1691 mAwContents.onWindowFocusChanged(hasWindowFocus); 1692 } 1693 1694 @Override 1695 public void onFocusChanged(final boolean focused, final int direction, 1696 final Rect previouslyFocusedRect) { 1697 if (!ThreadUtils.runningOnUiThread()) { 1698 ThreadUtils.postOnUiThread(new Runnable() { 1699 @Override 1700 public void run() { 1701 onFocusChanged(focused, direction, previouslyFocusedRect); 1702 } 1703 }); 1704 return; 1705 } 1706 mAwContents.onFocusChanged(focused, direction, previouslyFocusedRect); 1707 } 1708 1709 @Override 1710 public boolean setFrame(final int left, final int top, final int right, final int bottom) { 1711 if (!ThreadUtils.runningOnUiThread()) { 1712 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1713 @Override 1714 public Boolean call() { 1715 return setFrame(left, top, right, bottom); 1716 } 1717 }); 1718 return ret; 1719 } 1720 return mWebViewPrivate.super_setFrame(left, top, right, bottom); 1721 } 1722 1723 @Override 1724 public void onSizeChanged(final int w, final int h, final int ow, final int oh) { 1725 if (!ThreadUtils.runningOnUiThread()) { 1726 ThreadUtils.postOnUiThread(new Runnable() { 1727 @Override 1728 public void run() { 1729 onSizeChanged(w, h, ow, oh); 1730 } 1731 }); 1732 return; 1733 } 1734 mAwContents.onSizeChanged(w, h, ow, oh); 1735 } 1736 1737 @Override 1738 public void onScrollChanged(int l, int t, int oldl, int oldt) { 1739 } 1740 1741 @Override 1742 public boolean dispatchKeyEvent(final KeyEvent event) { 1743 if (!ThreadUtils.runningOnUiThread()) { 1744 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1745 @Override 1746 public Boolean call() { 1747 return dispatchKeyEvent(event); 1748 } 1749 }); 1750 return ret; 1751 } 1752 return mAwContents.dispatchKeyEvent(event); 1753 } 1754 1755 @Override 1756 public boolean onTouchEvent(final MotionEvent ev) { 1757 if (!ThreadUtils.runningOnUiThread()) { 1758 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1759 @Override 1760 public Boolean call() { 1761 return onTouchEvent(ev); 1762 } 1763 }); 1764 return ret; 1765 } 1766 return mAwContents.onTouchEvent(ev); 1767 } 1768 1769 @Override 1770 public boolean onHoverEvent(final MotionEvent event) { 1771 if (!ThreadUtils.runningOnUiThread()) { 1772 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1773 @Override 1774 public Boolean call() { 1775 return onHoverEvent(event); 1776 } 1777 }); 1778 return ret; 1779 } 1780 return mAwContents.onHoverEvent(event); 1781 } 1782 1783 @Override 1784 public boolean onGenericMotionEvent(final MotionEvent event) { 1785 if (!ThreadUtils.runningOnUiThread()) { 1786 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1787 @Override 1788 public Boolean call() { 1789 return onGenericMotionEvent(event); 1790 } 1791 }); 1792 return ret; 1793 } 1794 return mAwContents.onGenericMotionEvent(event); 1795 } 1796 1797 @Override 1798 public boolean onTrackballEvent(MotionEvent ev) { 1799 // Trackball event not handled, which eventually gets converted to DPAD keyevents 1800 return false; 1801 } 1802 1803 @Override 1804 public boolean requestFocus(final int direction, final Rect previouslyFocusedRect) { 1805 if (!ThreadUtils.runningOnUiThread()) { 1806 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1807 @Override 1808 public Boolean call() { 1809 return requestFocus(direction, previouslyFocusedRect); 1810 } 1811 }); 1812 return ret; 1813 } 1814 mAwContents.requestFocus(); 1815 return mWebViewPrivate.super_requestFocus(direction, previouslyFocusedRect); 1816 } 1817 1818 @Override 1819 public void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { 1820 if (!ThreadUtils.runningOnUiThread()) { 1821 ThreadUtils.postOnUiThread(new Runnable() { 1822 @Override 1823 public void run() { 1824 onMeasure(widthMeasureSpec, heightMeasureSpec); 1825 } 1826 }); 1827 return; 1828 } 1829 mAwContents.onMeasure(widthMeasureSpec, heightMeasureSpec); 1830 } 1831 1832 @Override 1833 public boolean requestChildRectangleOnScreen(final View child, final Rect rect, 1834 final boolean immediate) { 1835 if (!ThreadUtils.runningOnUiThread()) { 1836 boolean ret = runOnUiThreadBlocking(new Callable<Boolean>() { 1837 @Override 1838 public Boolean call() { 1839 return requestChildRectangleOnScreen(child, rect, immediate); 1840 } 1841 }); 1842 return ret; 1843 } 1844 return mAwContents.requestChildRectangleOnScreen(child, rect, immediate); 1845 } 1846 1847 @Override 1848 public void setBackgroundColor(final int color) { 1849 if (!ThreadUtils.runningOnUiThread()) { 1850 ThreadUtils.postOnUiThread(new Runnable() { 1851 @Override 1852 public void run() { 1853 setBackgroundColor(color); 1854 } 1855 }); 1856 return; 1857 } 1858 mAwContents.setBackgroundColor(color); 1859 } 1860 1861 @Override 1862 public void setLayerType(int layerType, Paint paint) { 1863 UnimplementedWebViewApi.invoke(); 1864 } 1865 1866 // Remove from superclass 1867 public void preDispatchDraw(Canvas canvas) { 1868 // TODO(leandrogracia): remove this method from WebViewProvider if we think 1869 // we won't need it again. 1870 } 1871 1872 // WebViewProvider.ScrollDelegate implementation ---------------------------------------------- 1873 1874 @Override 1875 public int computeHorizontalScrollRange() { 1876 if (!ThreadUtils.runningOnUiThread()) { 1877 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1878 @Override 1879 public Integer call() { 1880 return computeHorizontalScrollRange(); 1881 } 1882 }); 1883 return ret; 1884 } 1885 return mAwContents.computeHorizontalScrollRange(); 1886 } 1887 1888 @Override 1889 public int computeHorizontalScrollOffset() { 1890 if (!ThreadUtils.runningOnUiThread()) { 1891 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1892 @Override 1893 public Integer call() { 1894 return computeHorizontalScrollOffset(); 1895 } 1896 }); 1897 return ret; 1898 } 1899 return mAwContents.computeHorizontalScrollOffset(); 1900 } 1901 1902 @Override 1903 public int computeVerticalScrollRange() { 1904 if (!ThreadUtils.runningOnUiThread()) { 1905 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1906 @Override 1907 public Integer call() { 1908 return computeVerticalScrollRange(); 1909 } 1910 }); 1911 return ret; 1912 } 1913 return mAwContents.computeVerticalScrollRange(); 1914 } 1915 1916 @Override 1917 public int computeVerticalScrollOffset() { 1918 if (!ThreadUtils.runningOnUiThread()) { 1919 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1920 @Override 1921 public Integer call() { 1922 return computeVerticalScrollOffset(); 1923 } 1924 }); 1925 return ret; 1926 } 1927 return mAwContents.computeVerticalScrollOffset(); 1928 } 1929 1930 @Override 1931 public int computeVerticalScrollExtent() { 1932 if (!ThreadUtils.runningOnUiThread()) { 1933 int ret = runOnUiThreadBlocking(new Callable<Integer>() { 1934 @Override 1935 public Integer call() { 1936 return computeVerticalScrollExtent(); 1937 } 1938 }); 1939 return ret; 1940 } 1941 return mAwContents.computeVerticalScrollExtent(); 1942 } 1943 1944 @Override 1945 public void computeScroll() { 1946 if (!ThreadUtils.runningOnUiThread()) { 1947 ThreadUtils.postOnUiThread(new Runnable() { 1948 @Override 1949 public void run() { 1950 computeScroll(); 1951 } 1952 }); 1953 return; 1954 } 1955 mAwContents.computeScroll(); 1956 } 1957 1958 // AwContents.InternalAccessDelegate implementation -------------------------------------- 1959 private class InternalAccessAdapter implements AwContents.InternalAccessDelegate { 1960 @Override 1961 public boolean drawChild(Canvas arg0, View arg1, long arg2) { 1962 UnimplementedWebViewApi.invoke(); 1963 return false; 1964 } 1965 1966 @Override 1967 public boolean super_onKeyUp(int arg0, KeyEvent arg1) { 1968 UnimplementedWebViewApi.invoke(); 1969 return false; 1970 } 1971 1972 @Override 1973 public boolean super_dispatchKeyEventPreIme(KeyEvent arg0) { 1974 UnimplementedWebViewApi.invoke(); 1975 return false; 1976 } 1977 1978 @Override 1979 public boolean super_dispatchKeyEvent(KeyEvent event) { 1980 return mWebViewPrivate.super_dispatchKeyEvent(event); 1981 } 1982 1983 @Override 1984 public boolean super_onGenericMotionEvent(MotionEvent arg0) { 1985 UnimplementedWebViewApi.invoke(); 1986 return false; 1987 } 1988 1989 @Override 1990 public void super_onConfigurationChanged(Configuration arg0) { 1991 UnimplementedWebViewApi.invoke(); 1992 } 1993 1994 @Override 1995 public int super_getScrollBarStyle() { 1996 return mWebViewPrivate.super_getScrollBarStyle(); 1997 } 1998 1999 @Override 2000 public boolean awakenScrollBars() { 2001 mWebViewPrivate.awakenScrollBars(0); 2002 // TODO: modify the WebView.PrivateAccess to provide a return value. 2003 return true; 2004 } 2005 2006 @Override 2007 public boolean super_awakenScrollBars(int arg0, boolean arg1) { 2008 // TODO: need method on WebView.PrivateAccess? 2009 UnimplementedWebViewApi.invoke(); 2010 return false; 2011 } 2012 2013 @Override 2014 public void onScrollChanged(int l, int t, int oldl, int oldt) { 2015 mWebViewPrivate.setScrollXRaw(l); 2016 mWebViewPrivate.setScrollYRaw(t); 2017 mWebViewPrivate.onScrollChanged(l, t, oldl, oldt); 2018 } 2019 2020 @Override 2021 public void overScrollBy(int deltaX, int deltaY, 2022 int scrollX, int scrollY, 2023 int scrollRangeX, int scrollRangeY, 2024 int maxOverScrollX, int maxOverScrollY, 2025 boolean isTouchEvent) { 2026 mWebViewPrivate.overScrollBy(deltaX, deltaY, scrollX, scrollY, 2027 scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); 2028 } 2029 2030 @Override 2031 public void super_scrollTo(int scrollX, int scrollY) { 2032 mWebViewPrivate.super_scrollTo(scrollX, scrollY); 2033 } 2034 2035 @Override 2036 public void setMeasuredDimension(int measuredWidth, int measuredHeight) { 2037 mWebViewPrivate.setMeasuredDimension(measuredWidth, measuredHeight); 2038 } 2039 2040 @Override 2041 public boolean requestDrawGL(Canvas canvas) { 2042 if (mGLfunctor == null) { 2043 mGLfunctor = new DrawGLFunctor(mAwContents.getAwDrawGLViewContext()); 2044 } 2045 return mGLfunctor.requestDrawGL((HardwareCanvas)canvas, mWebView.getViewRootImpl()); 2046 } 2047 } 2048} 2049