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