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