AwContents.java revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
1// Copyright 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5package org.chromium.android_webview; 6 7import android.annotation.SuppressLint; 8import android.app.Activity; 9import android.content.ComponentCallbacks2; 10import android.content.Context; 11import android.content.res.Configuration; 12import android.graphics.Bitmap; 13import android.graphics.Canvas; 14import android.graphics.Color; 15import android.graphics.Paint; 16import android.graphics.Picture; 17import android.graphics.Rect; 18import android.net.Uri; 19import android.net.http.SslCertificate; 20import android.os.AsyncTask; 21import android.os.Build; 22import android.os.Bundle; 23import android.os.Message; 24import android.text.TextUtils; 25import android.util.Log; 26import android.util.Pair; 27import android.view.KeyEvent; 28import android.view.MotionEvent; 29import android.view.View; 30import android.view.ViewGroup; 31import android.view.accessibility.AccessibilityEvent; 32import android.view.accessibility.AccessibilityNodeInfo; 33import android.view.accessibility.AccessibilityNodeProvider; 34import android.view.inputmethod.EditorInfo; 35import android.view.inputmethod.InputConnection; 36import android.webkit.GeolocationPermissions; 37import android.webkit.ValueCallback; 38import android.widget.OverScroller; 39 40import com.google.common.annotations.VisibleForTesting; 41 42import org.chromium.android_webview.permission.AwPermissionRequest; 43import org.chromium.base.CalledByNative; 44import org.chromium.base.JNINamespace; 45import org.chromium.base.ThreadUtils; 46import org.chromium.components.navigation_interception.InterceptNavigationDelegate; 47import org.chromium.components.navigation_interception.NavigationParams; 48import org.chromium.content.browser.ContentSettings; 49import org.chromium.content.browser.ContentViewClient; 50import org.chromium.content.browser.ContentViewCore; 51import org.chromium.content.browser.ContentViewStatics; 52import org.chromium.content.browser.LoadUrlParams; 53import org.chromium.content.browser.NavigationHistory; 54import org.chromium.content.browser.PageTransitionTypes; 55import org.chromium.content.browser.WebContentsObserverAndroid; 56import org.chromium.content.common.CleanupReference; 57import org.chromium.content_public.Referrer; 58import org.chromium.content_public.browser.GestureStateListener; 59import org.chromium.content_public.browser.JavaScriptCallback; 60import org.chromium.ui.base.ActivityWindowAndroid; 61import org.chromium.ui.base.WindowAndroid; 62import org.chromium.ui.gfx.DeviceDisplayInfo; 63 64import java.io.File; 65import java.lang.annotation.Annotation; 66import java.net.MalformedURLException; 67import java.net.URL; 68import java.util.HashMap; 69import java.util.Locale; 70import java.util.Map; 71import java.util.concurrent.Callable; 72 73/** 74 * Exposes the native AwContents class, and together these classes wrap the ContentViewCore 75 * and Browser components that are required to implement Android WebView API. This is the 76 * primary entry point for the WebViewProvider implementation; it holds a 1:1 object 77 * relationship with application WebView instances. 78 * (We define this class independent of the hidden WebViewProvider interfaces, to allow 79 * continuous build & test in the open source SDK-based tree). 80 */ 81@JNINamespace("android_webview") 82public class AwContents { 83 private static final String TAG = "AwContents"; 84 85 private static final String WEB_ARCHIVE_EXTENSION = ".mht"; 86 87 // Used to avoid enabling zooming in / out if resulting zooming will 88 // produce little visible difference. 89 private static final float ZOOM_CONTROLS_EPSILON = 0.007f; 90 91 /** 92 * WebKit hit test related data strcutre. These are used to implement 93 * getHitTestResult, requestFocusNodeHref, requestImageRef methods in WebView. 94 * All values should be updated together. The native counterpart is 95 * AwHitTestData. 96 */ 97 public static class HitTestData { 98 // Used in getHitTestResult. 99 public int hitTestResultType; 100 public String hitTestResultExtraData; 101 102 // Used in requestFocusNodeHref (all three) and requestImageRef (only imgSrc). 103 public String href; 104 public String anchorText; 105 public String imgSrc; 106 } 107 108 /** 109 * Interface that consumers of {@link AwContents} must implement to allow the proper 110 * dispatching of view methods through the containing view. 111 */ 112 public interface InternalAccessDelegate extends ContentViewCore.InternalAccessDelegate { 113 114 /** 115 * @see View#overScrollBy(int, int, int, int, int, int, int, int, boolean); 116 */ 117 void overScrollBy(int deltaX, int deltaY, 118 int scrollX, int scrollY, 119 int scrollRangeX, int scrollRangeY, 120 int maxOverScrollX, int maxOverScrollY, 121 boolean isTouchEvent); 122 123 /** 124 * @see View#scrollTo(int, int) 125 */ 126 void super_scrollTo(int scrollX, int scrollY); 127 128 /** 129 * @see View#setMeasuredDimension(int, int) 130 */ 131 void setMeasuredDimension(int measuredWidth, int measuredHeight); 132 133 /** 134 * @see View#getScrollBarStyle() 135 */ 136 int super_getScrollBarStyle(); 137 } 138 139 /** 140 * Interface that consumers of {@link AwContents} must implement to support 141 * native GL rendering. 142 */ 143 public interface NativeGLDelegate { 144 /** 145 * Requests a callback on the native DrawGL method (see getAwDrawGLFunction) 146 * if called from within onDraw, |canvas| will be non-null and hardware accelerated. 147 * Otherwise, |canvas| will be null, and the container view itself will be hardware 148 * accelerated. If |waitForCompletion| is true, this method will not return until 149 * functor has returned. 150 * Should avoid setting |waitForCompletion| when |canvas| is not null. 151 * |containerView| is the view where the AwContents should be drawn. 152 * 153 * @return false indicates the GL draw request was not accepted, and the caller 154 * should fallback to the SW path. 155 */ 156 boolean requestDrawGL(Canvas canvas, boolean waitForCompletion, View containerView); 157 158 /** 159 * Detaches the GLFunctor from the view tree. 160 */ 161 void detachGLFunctor(); 162 } 163 164 /** 165 * Class to facilitate dependency injection. Subclasses by test code to provide mock versions of 166 * certain AwContents dependencies. 167 */ 168 public static class DependencyFactory { 169 public AwLayoutSizer createLayoutSizer() { 170 return new AwLayoutSizer(); 171 } 172 173 public AwScrollOffsetManager createScrollOffsetManager( 174 AwScrollOffsetManager.Delegate delegate, OverScroller overScroller) { 175 return new AwScrollOffsetManager(delegate, overScroller); 176 } 177 } 178 179 private long mNativeAwContents; 180 private final AwBrowserContext mBrowserContext; 181 private ViewGroup mContainerView; 182 private final AwLayoutChangeListener mLayoutChangeListener; 183 private final Context mContext; 184 private ContentViewCore mContentViewCore; 185 private WindowAndroid mWindowAndroid; 186 private final AwContentsClient mContentsClient; 187 private final AwContentViewClient mContentViewClient; 188 private WebContentsObserverAndroid mWebContentsObserver; 189 private final AwContentsClientBridge mContentsClientBridge; 190 private final AwWebContentsDelegateAdapter mWebContentsDelegate; 191 private final AwContentsIoThreadClient mIoThreadClient; 192 private final InterceptNavigationDelegateImpl mInterceptNavigationDelegate; 193 private InternalAccessDelegate mInternalAccessAdapter; 194 private final NativeGLDelegate mNativeGLDelegate; 195 private final AwLayoutSizer mLayoutSizer; 196 private final AwZoomControls mZoomControls; 197 private final AwScrollOffsetManager mScrollOffsetManager; 198 private OverScrollGlow mOverScrollGlow; 199 // This can be accessed on any thread after construction. See AwContentsIoThreadClient. 200 private final AwSettings mSettings; 201 private final ScrollAccessibilityHelper mScrollAccessibilityHelper; 202 203 private boolean mIsPaused; 204 private boolean mIsViewVisible; 205 private boolean mIsWindowVisible; 206 private boolean mIsAttachedToWindow; 207 private Bitmap mFavicon; 208 private boolean mHasRequestedVisitedHistoryFromClient; 209 // TODO(boliu): This should be in a global context, not per webview. 210 private final double mDIPScale; 211 212 // The base background color, i.e. not accounting for any CSS body from the current page. 213 private int mBaseBackgroundColor = Color.WHITE; 214 215 // Must call nativeUpdateLastHitTestData first to update this before use. 216 private final HitTestData mPossiblyStaleHitTestData = new HitTestData(); 217 218 private final DefaultVideoPosterRequestHandler mDefaultVideoPosterRequestHandler; 219 220 // Bound method for suppling Picture instances to the AwContentsClient. Will be null if the 221 // picture listener API has not yet been enabled, or if it is using invalidation-only mode. 222 private Callable<Picture> mPictureListenerContentProvider; 223 224 private boolean mContainerViewFocused; 225 private boolean mWindowFocused; 226 227 // These come from the compositor and are updated synchronously (in contrast to the values in 228 // ContentViewCore, which are updated at end of every frame). 229 private float mPageScaleFactor = 1.0f; 230 private float mMinPageScaleFactor = 1.0f; 231 private float mMaxPageScaleFactor = 1.0f; 232 private float mContentWidthDip; 233 private float mContentHeightDip; 234 235 private AwAutofillClient mAwAutofillClient; 236 237 private AwPdfExporter mAwPdfExporter; 238 239 private AwViewMethods mAwViewMethods; 240 private final FullScreenTransitionsState mFullScreenTransitionsState; 241 242 // This flag indicates that ShouldOverrideUrlNavigation should be posted 243 // through the resourcethrottle. This is only used for popup windows. 244 private boolean mDeferredShouldOverrideUrlLoadingIsPendingForPopup; 245 246 // The framework may temporarily detach our container view, for example during layout if 247 // we are a child of a ListView. This may cause many toggles of View focus, which we suppress 248 // when in this state. 249 private boolean mTemporarilyDetached; 250 251 private static final class DestroyRunnable implements Runnable { 252 private final long mNativeAwContents; 253 private DestroyRunnable(long nativeAwContents) { 254 mNativeAwContents = nativeAwContents; 255 } 256 @Override 257 public void run() { 258 nativeDestroy(mNativeAwContents); 259 } 260 } 261 262 /** 263 * A class that stores the state needed to enter and exit fullscreen. 264 */ 265 private static class FullScreenTransitionsState { 266 private final ViewGroup mInitialContainerView; 267 private final InternalAccessDelegate mInitialInternalAccessAdapter; 268 private final AwViewMethods mInitialAwViewMethods; 269 private FullScreenView mFullScreenView; 270 271 private FullScreenTransitionsState(ViewGroup initialContainerView, 272 InternalAccessDelegate initialInternalAccessAdapter, 273 AwViewMethods initialAwViewMethods) { 274 mInitialContainerView = initialContainerView; 275 mInitialInternalAccessAdapter = initialInternalAccessAdapter; 276 mInitialAwViewMethods = initialAwViewMethods; 277 } 278 279 private void enterFullScreen(FullScreenView fullScreenView) { 280 mFullScreenView = fullScreenView; 281 } 282 283 private void exitFullScreen() { 284 mFullScreenView = null; 285 } 286 287 private boolean isFullScreen() { 288 return mFullScreenView != null; 289 } 290 291 private ViewGroup getInitialContainerView() { 292 return mInitialContainerView; 293 } 294 295 private InternalAccessDelegate getInitialInternalAccessDelegate() { 296 return mInitialInternalAccessAdapter; 297 } 298 299 private AwViewMethods getInitialAwViewMethods() { 300 return mInitialAwViewMethods; 301 } 302 303 private FullScreenView getFullScreenView() { 304 return mFullScreenView; 305 } 306 } 307 308 // Reference to the active mNativeAwContents pointer while it is active use 309 // (ie before it is destroyed). 310 private CleanupReference mCleanupReference; 311 312 //-------------------------------------------------------------------------------------------- 313 private class IoThreadClientImpl extends AwContentsIoThreadClient { 314 // All methods are called on the IO thread. 315 316 @Override 317 public int getCacheMode() { 318 return mSettings.getCacheMode(); 319 } 320 321 @Override 322 public AwWebResourceResponse shouldInterceptRequest( 323 AwContentsClient.ShouldInterceptRequestParams params) { 324 String url = params.url; 325 AwWebResourceResponse awWebResourceResponse; 326 // Return the response directly if the url is default video poster url. 327 awWebResourceResponse = mDefaultVideoPosterRequestHandler.shouldInterceptRequest(url); 328 if (awWebResourceResponse != null) return awWebResourceResponse; 329 330 awWebResourceResponse = mContentsClient.shouldInterceptRequest(params); 331 332 if (awWebResourceResponse == null) { 333 mContentsClient.getCallbackHelper().postOnLoadResource(url); 334 } 335 336 if (params.isMainFrame && awWebResourceResponse != null && 337 awWebResourceResponse.getData() == null) { 338 // In this case the intercepted URLRequest job will simulate an empty response 339 // which doesn't trigger the onReceivedError callback. For WebViewClassic 340 // compatibility we synthesize that callback. http://crbug.com/180950 341 mContentsClient.getCallbackHelper().postOnReceivedError( 342 ErrorCodeConversionHelper.ERROR_UNKNOWN, 343 null /* filled in by the glue layer */, url); 344 } 345 return awWebResourceResponse; 346 } 347 348 @Override 349 public boolean shouldBlockContentUrls() { 350 return !mSettings.getAllowContentAccess(); 351 } 352 353 @Override 354 public boolean shouldBlockFileUrls() { 355 return !mSettings.getAllowFileAccess(); 356 } 357 358 @Override 359 public boolean shouldBlockNetworkLoads() { 360 return mSettings.getBlockNetworkLoads(); 361 } 362 363 @Override 364 public boolean shouldAcceptThirdPartyCookies() { 365 return mSettings.getAcceptThirdPartyCookies(); 366 } 367 368 @Override 369 public void onDownloadStart(String url, String userAgent, 370 String contentDisposition, String mimeType, long contentLength) { 371 mContentsClient.getCallbackHelper().postOnDownloadStart(url, userAgent, 372 contentDisposition, mimeType, contentLength); 373 } 374 375 @Override 376 public void newLoginRequest(String realm, String account, String args) { 377 mContentsClient.getCallbackHelper().postOnReceivedLoginRequest(realm, account, args); 378 } 379 } 380 381 //-------------------------------------------------------------------------------------------- 382 // When the navigation is for a newly created WebView (i.e. a popup), intercept the navigation 383 // here for implementing shouldOverrideUrlLoading. This is to send the shouldOverrideUrlLoading 384 // callback to the correct WebViewClient that is associated with the WebView. 385 // Otherwise, use this delegate only to post onPageStarted messages. 386 // 387 // We are not using WebContentsObserver.didStartLoading because of stale URLs, out of order 388 // onPageStarted's and double onPageStarted's. 389 // 390 private class InterceptNavigationDelegateImpl implements InterceptNavigationDelegate { 391 @Override 392 public boolean shouldIgnoreNavigation(NavigationParams navigationParams) { 393 final String url = navigationParams.url; 394 boolean ignoreNavigation = false; 395 if (mDeferredShouldOverrideUrlLoadingIsPendingForPopup) { 396 mDeferredShouldOverrideUrlLoadingIsPendingForPopup = false; 397 // If this is used for all navigations in future, cases for application initiated 398 // load, redirect and backforward should also be filtered out. 399 if (!navigationParams.isPost) { 400 ignoreNavigation = mContentsClient.shouldOverrideUrlLoading(url); 401 } 402 } 403 // The shouldOverrideUrlLoading call might have resulted in posting messages to the 404 // UI thread. Using sendMessage here (instead of calling onPageStarted directly) 405 // will allow those to run in order. 406 if (!ignoreNavigation) { 407 mContentsClient.getCallbackHelper().postOnPageStarted(url); 408 } 409 return ignoreNavigation; 410 } 411 } 412 413 //-------------------------------------------------------------------------------------------- 414 private class AwLayoutSizerDelegate implements AwLayoutSizer.Delegate { 415 @Override 416 public void requestLayout() { 417 mContainerView.requestLayout(); 418 } 419 420 @Override 421 public void setMeasuredDimension(int measuredWidth, int measuredHeight) { 422 mInternalAccessAdapter.setMeasuredDimension(measuredWidth, measuredHeight); 423 } 424 425 @Override 426 public boolean isLayoutParamsHeightWrapContent() { 427 return mContainerView.getLayoutParams() != null && 428 mContainerView.getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT; 429 } 430 431 @Override 432 public void setForceZeroLayoutHeight(boolean forceZeroHeight) { 433 getSettings().setForceZeroLayoutHeight(forceZeroHeight); 434 } 435 } 436 437 //-------------------------------------------------------------------------------------------- 438 private class AwScrollOffsetManagerDelegate implements AwScrollOffsetManager.Delegate { 439 @Override 440 public void overScrollContainerViewBy(int deltaX, int deltaY, int scrollX, int scrollY, 441 int scrollRangeX, int scrollRangeY, boolean isTouchEvent) { 442 mInternalAccessAdapter.overScrollBy(deltaX, deltaY, scrollX, scrollY, 443 scrollRangeX, scrollRangeY, 0, 0, isTouchEvent); 444 } 445 446 @Override 447 public void scrollContainerViewTo(int x, int y) { 448 mInternalAccessAdapter.super_scrollTo(x, y); 449 } 450 451 @Override 452 public void scrollNativeTo(int x, int y) { 453 if (mNativeAwContents == 0) return; 454 nativeScrollTo(mNativeAwContents, x, y); 455 } 456 457 @Override 458 public int getContainerViewScrollX() { 459 return mContainerView.getScrollX(); 460 } 461 462 @Override 463 public int getContainerViewScrollY() { 464 return mContainerView.getScrollY(); 465 } 466 467 @Override 468 public void invalidate() { 469 mContainerView.invalidate(); 470 } 471 } 472 473 //-------------------------------------------------------------------------------------------- 474 private class AwGestureStateListener extends GestureStateListener { 475 @Override 476 public void onPinchStarted() { 477 // While it's possible to re-layout the view during a pinch gesture, the effect is very 478 // janky (especially that the page scale update notification comes from the renderer 479 // main thread, not from the impl thread, so it's usually out of sync with what's on 480 // screen). It's also quite expensive to do a re-layout, so we simply postpone 481 // re-layout for the duration of the gesture. This is compatible with what 482 // WebViewClassic does. 483 mLayoutSizer.freezeLayoutRequests(); 484 } 485 486 @Override 487 public void onPinchEnded() { 488 mLayoutSizer.unfreezeLayoutRequests(); 489 } 490 491 @Override 492 public void onFlingCancelGesture() { 493 mScrollOffsetManager.onFlingCancelGesture(); 494 } 495 496 @Override 497 public void onUnhandledFlingStartEvent(int velocityX, int velocityY) { 498 mScrollOffsetManager.onUnhandledFlingStartEvent(velocityX, velocityY); 499 } 500 501 @Override 502 public void onScrollUpdateGestureConsumed() { 503 mScrollAccessibilityHelper.postViewScrolledAccessibilityEventCallback(); 504 } 505 } 506 507 //-------------------------------------------------------------------------------------------- 508 private class AwComponentCallbacks implements ComponentCallbacks2 { 509 @Override 510 public void onTrimMemory(final int level) { 511 if (mNativeAwContents == 0) return; 512 boolean visibleRectEmpty = getGlobalVisibleRect().isEmpty(); 513 final boolean visible = mIsViewVisible && mIsWindowVisible && !visibleRectEmpty; 514 nativeTrimMemory(mNativeAwContents, level, visible); 515 } 516 517 @Override 518 public void onLowMemory() {} 519 520 @Override 521 public void onConfigurationChanged(Configuration configuration) {} 522 }; 523 524 //-------------------------------------------------------------------------------------------- 525 private class AwLayoutChangeListener implements View.OnLayoutChangeListener { 526 @Override 527 public void onLayoutChange(View v, int left, int top, int right, int bottom, 528 int oldLeft, int oldTop, int oldRight, int oldBottom) { 529 assert v == mContainerView; 530 mLayoutSizer.onLayoutChange(); 531 } 532 } 533 534 /** 535 * @param browserContext the browsing context to associate this view contents with. 536 * @param containerView the view-hierarchy item this object will be bound to. 537 * @param context the context to use, usually containerView.getContext(). 538 * @param internalAccessAdapter to access private methods on containerView. 539 * @param nativeGLDelegate to access the GL functor provided by the WebView. 540 * @param contentsClient will receive API callbacks from this WebView Contents. 541 * @param awSettings AwSettings instance used to configure the AwContents. 542 * 543 * This constructor uses the default view sizing policy. 544 */ 545 public AwContents(AwBrowserContext browserContext, ViewGroup containerView, Context context, 546 InternalAccessDelegate internalAccessAdapter, NativeGLDelegate nativeGLDelegate, 547 AwContentsClient contentsClient, AwSettings awSettings) { 548 this(browserContext, containerView, context, internalAccessAdapter, nativeGLDelegate, 549 contentsClient, awSettings, new DependencyFactory()); 550 } 551 552 /** 553 * @param dependencyFactory an instance of the DependencyFactory used to provide instances of 554 * classes that this class depends on. 555 * 556 * This version of the constructor is used in test code to inject test versions of the above 557 * documented classes. 558 */ 559 public AwContents(AwBrowserContext browserContext, ViewGroup containerView, Context context, 560 InternalAccessDelegate internalAccessAdapter, NativeGLDelegate nativeGLDelegate, 561 AwContentsClient contentsClient, AwSettings settings, 562 DependencyFactory dependencyFactory) { 563 mBrowserContext = browserContext; 564 mContainerView = containerView; 565 mContext = context; 566 mInternalAccessAdapter = internalAccessAdapter; 567 mNativeGLDelegate = nativeGLDelegate; 568 mContentsClient = contentsClient; 569 mAwViewMethods = new AwViewMethodsImpl(); 570 mFullScreenTransitionsState = new FullScreenTransitionsState( 571 mContainerView, mInternalAccessAdapter, mAwViewMethods); 572 mContentViewClient = new AwContentViewClient(contentsClient, settings, this, mContext); 573 mLayoutSizer = dependencyFactory.createLayoutSizer(); 574 mSettings = settings; 575 mDIPScale = DeviceDisplayInfo.create(mContext).getDIPScale(); 576 mLayoutSizer.setDelegate(new AwLayoutSizerDelegate()); 577 mLayoutSizer.setDIPScale(mDIPScale); 578 mWebContentsDelegate = new AwWebContentsDelegateAdapter( 579 contentsClient, mContainerView, mContext); 580 mContentsClientBridge = new AwContentsClientBridge(contentsClient, 581 mBrowserContext.getKeyStore(), AwContentsStatics.getClientCertLookupTable()); 582 mZoomControls = new AwZoomControls(this); 583 mIoThreadClient = new IoThreadClientImpl(); 584 mInterceptNavigationDelegate = new InterceptNavigationDelegateImpl(); 585 586 AwSettings.ZoomSupportChangeListener zoomListener = 587 new AwSettings.ZoomSupportChangeListener() { 588 @Override 589 public void onGestureZoomSupportChanged( 590 boolean supportsDoubleTapZoom, boolean supportsMultiTouchZoom) { 591 mContentViewCore.updateDoubleTapSupport(supportsDoubleTapZoom); 592 mContentViewCore.updateMultiTouchZoomSupport(supportsMultiTouchZoom); 593 } 594 595 }; 596 mSettings.setZoomListener(zoomListener); 597 mDefaultVideoPosterRequestHandler = new DefaultVideoPosterRequestHandler(mContentsClient); 598 mSettings.setDefaultVideoPosterURL( 599 mDefaultVideoPosterRequestHandler.getDefaultVideoPosterURL()); 600 mSettings.setDIPScale(mDIPScale); 601 mScrollOffsetManager = dependencyFactory.createScrollOffsetManager( 602 new AwScrollOffsetManagerDelegate(), new OverScroller(mContext)); 603 mScrollAccessibilityHelper = new ScrollAccessibilityHelper(mContainerView); 604 605 setOverScrollMode(mContainerView.getOverScrollMode()); 606 setScrollBarStyle(mInternalAccessAdapter.super_getScrollBarStyle()); 607 mLayoutChangeListener = new AwLayoutChangeListener(); 608 mContainerView.addOnLayoutChangeListener(mLayoutChangeListener); 609 610 setNewAwContents(nativeInit(mBrowserContext)); 611 612 onContainerViewChanged(); 613 } 614 615 private static ContentViewCore createAndInitializeContentViewCore(ViewGroup containerView, 616 Context context, InternalAccessDelegate internalDispatcher, long nativeWebContents, 617 GestureStateListener gestureStateListener, 618 ContentViewClient contentViewClient, 619 ContentViewCore.ZoomControlsDelegate zoomControlsDelegate, 620 WindowAndroid windowAndroid) { 621 ContentViewCore contentViewCore = new ContentViewCore(context); 622 contentViewCore.initialize(containerView, internalDispatcher, nativeWebContents, 623 windowAndroid); 624 contentViewCore.addGestureStateListener(gestureStateListener); 625 contentViewCore.setContentViewClient(contentViewClient); 626 contentViewCore.setZoomControlsDelegate(zoomControlsDelegate); 627 return contentViewCore; 628 } 629 630 boolean isFullScreen() { 631 return mFullScreenTransitionsState.isFullScreen(); 632 } 633 634 /** 635 * Transitions this {@link AwContents} to fullscreen mode and returns the 636 * {@link View} where the contents will be drawn while in fullscreen. 637 */ 638 View enterFullScreen() { 639 assert !isFullScreen(); 640 641 // Detach to tear down the GL functor if this is still associated with the old 642 // container view. It will be recreated during the next call to onDraw attached to 643 // the new container view. 644 onDetachedFromWindow(); 645 646 // In fullscreen mode FullScreenView owns the AwViewMethodsImpl and AwContents 647 // a NullAwViewMethods. 648 FullScreenView fullScreenView = new FullScreenView(mContext, mAwViewMethods); 649 mFullScreenTransitionsState.enterFullScreen(fullScreenView); 650 mAwViewMethods = new NullAwViewMethods(this, mInternalAccessAdapter, mContainerView); 651 mContainerView.removeOnLayoutChangeListener(mLayoutChangeListener); 652 fullScreenView.addOnLayoutChangeListener(mLayoutChangeListener); 653 654 // Associate this AwContents with the FullScreenView. 655 setInternalAccessAdapter(fullScreenView.getInternalAccessAdapter()); 656 setContainerView(fullScreenView); 657 658 return fullScreenView; 659 } 660 661 /** 662 * Returns this {@link AwContents} to embedded mode, where the {@link AwContents} are drawn 663 * in the WebView. 664 */ 665 void exitFullScreen() { 666 assert isFullScreen(); 667 668 // Detach to tear down the GL functor if this is still associated with the old 669 // container view. It will be recreated during the next call to onDraw attached to 670 // the new container view. 671 // NOTE: we cannot use mAwViewMethods here because its type is NullAwViewMethods. 672 AwViewMethods awViewMethodsImpl = mFullScreenTransitionsState.getInitialAwViewMethods(); 673 awViewMethodsImpl.onDetachedFromWindow(); 674 675 // Swap the view delegates. In embedded mode the FullScreenView owns a 676 // NullAwViewMethods and AwContents the AwViewMethodsImpl. 677 FullScreenView fullscreenView = mFullScreenTransitionsState.getFullScreenView(); 678 fullscreenView.setAwViewMethods(new NullAwViewMethods( 679 this, fullscreenView.getInternalAccessAdapter(), fullscreenView)); 680 mAwViewMethods = awViewMethodsImpl; 681 ViewGroup initialContainerView = mFullScreenTransitionsState.getInitialContainerView(); 682 initialContainerView.addOnLayoutChangeListener(mLayoutChangeListener); 683 fullscreenView.removeOnLayoutChangeListener(mLayoutChangeListener); 684 685 // Re-associate this AwContents with the WebView. 686 setInternalAccessAdapter(mFullScreenTransitionsState.getInitialInternalAccessDelegate()); 687 setContainerView(initialContainerView); 688 689 mFullScreenTransitionsState.exitFullScreen(); 690 } 691 692 private void setInternalAccessAdapter(InternalAccessDelegate internalAccessAdapter) { 693 mInternalAccessAdapter = internalAccessAdapter; 694 mContentViewCore.setContainerViewInternals(mInternalAccessAdapter); 695 } 696 697 private void setContainerView(ViewGroup newContainerView) { 698 mContainerView = newContainerView; 699 mContentViewCore.setContainerView(mContainerView); 700 if (mAwPdfExporter != null) { 701 mAwPdfExporter.setContainerView(mContainerView); 702 } 703 mWebContentsDelegate.setContainerView(mContainerView); 704 705 onContainerViewChanged(); 706 } 707 708 /** 709 * Reconciles the state of this AwContents object with the state of the new container view. 710 */ 711 private void onContainerViewChanged() { 712 // NOTE: mAwViewMethods is used by the old container view, the WebView, so it might refer 713 // to a NullAwViewMethods when in fullscreen. To ensure that the state is reconciled with 714 // the new container view correctly, we bypass mAwViewMethods and use the real 715 // implementation directly. 716 AwViewMethods awViewMethodsImpl = mFullScreenTransitionsState.getInitialAwViewMethods(); 717 awViewMethodsImpl.onVisibilityChanged(mContainerView, mContainerView.getVisibility()); 718 awViewMethodsImpl.onWindowVisibilityChanged(mContainerView.getWindowVisibility()); 719 720 // We should stop running WebView tests in JellyBean devices, see crbug/161864. 721 // Until then we skip calling isAttachedToWindow() as it has only been introduced in K. 722 if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT 723 || mContainerView.isAttachedToWindow()) { 724 awViewMethodsImpl.onAttachedToWindow(); 725 } else { 726 awViewMethodsImpl.onDetachedFromWindow(); 727 } 728 awViewMethodsImpl.onSizeChanged( 729 mContainerView.getWidth(), mContainerView.getHeight(), 0, 0); 730 awViewMethodsImpl.onWindowFocusChanged(mContainerView.hasWindowFocus()); 731 awViewMethodsImpl.onFocusChanged(mContainerView.hasFocus(), 0, null); 732 mContainerView.requestLayout(); 733 } 734 735 /* Common initialization routine for adopting a native AwContents instance into this 736 * java instance. 737 * 738 * TAKE CARE! This method can get called multiple times per java instance. Code accordingly. 739 * ^^^^^^^^^ See the native class declaration for more details on relative object lifetimes. 740 */ 741 private void setNewAwContents(long newAwContentsPtr) { 742 if (mNativeAwContents != 0) { 743 destroy(); 744 mContentViewCore = null; 745 } 746 747 assert mNativeAwContents == 0 && mCleanupReference == null && mContentViewCore == null; 748 749 mNativeAwContents = newAwContentsPtr; 750 // TODO(joth): when the native and java counterparts of AwBrowserContext are hooked up to 751 // each other, we should update |mBrowserContext| according to the newly received native 752 // WebContent's browser context. 753 754 // The native side object has been bound to this java instance, so now is the time to 755 // bind all the native->java relationships. 756 mCleanupReference = new CleanupReference(this, new DestroyRunnable(mNativeAwContents)); 757 758 long nativeWebContents = nativeGetWebContents(mNativeAwContents); 759 760 mWindowAndroid = mContext instanceof Activity ? 761 new ActivityWindowAndroid((Activity) mContext) : 762 new WindowAndroid(mContext.getApplicationContext()); 763 mContentViewCore = createAndInitializeContentViewCore( 764 mContainerView, mContext, mInternalAccessAdapter, nativeWebContents, 765 new AwGestureStateListener(), mContentViewClient, mZoomControls, mWindowAndroid); 766 nativeSetJavaPeers(mNativeAwContents, this, mWebContentsDelegate, mContentsClientBridge, 767 mIoThreadClient, mInterceptNavigationDelegate); 768 installWebContentsObserver(); 769 mSettings.setWebContents(nativeWebContents); 770 nativeSetDipScale(mNativeAwContents, (float) mDIPScale); 771 772 // The only call to onShow. onHide should never be called. 773 mContentViewCore.onShow(); 774 } 775 776 private void installWebContentsObserver() { 777 if (mWebContentsObserver != null) { 778 mWebContentsObserver.detachFromWebContents(); 779 } 780 mWebContentsObserver = new AwWebContentsObserver(mContentViewCore.getWebContents(), 781 mContentsClient); 782 } 783 784 /** 785 * Called on the "source" AwContents that is opening the popup window to 786 * provide the AwContents to host the pop up content. 787 */ 788 public void supplyContentsForPopup(AwContents newContents) { 789 long popupNativeAwContents = nativeReleasePopupAwContents(mNativeAwContents); 790 if (popupNativeAwContents == 0) { 791 Log.w(TAG, "Popup WebView bind failed: no pending content."); 792 if (newContents != null) newContents.destroy(); 793 return; 794 } 795 if (newContents == null) { 796 nativeDestroy(popupNativeAwContents); 797 return; 798 } 799 800 newContents.receivePopupContents(popupNativeAwContents); 801 } 802 803 // Recap: supplyContentsForPopup() is called on the parent window's content, this method is 804 // called on the popup window's content. 805 private void receivePopupContents(long popupNativeAwContents) { 806 mDeferredShouldOverrideUrlLoadingIsPendingForPopup = true; 807 // Save existing view state. 808 final boolean wasAttached = mIsAttachedToWindow; 809 final boolean wasViewVisible = mIsViewVisible; 810 final boolean wasWindowVisible = mIsWindowVisible; 811 final boolean wasPaused = mIsPaused; 812 final boolean wasFocused = mContainerViewFocused; 813 final boolean wasWindowFocused = mWindowFocused; 814 815 // Properly clean up existing mContentViewCore and mNativeAwContents. 816 if (wasFocused) onFocusChanged(false, 0, null); 817 if (wasWindowFocused) onWindowFocusChanged(false); 818 if (wasViewVisible) setViewVisibilityInternal(false); 819 if (wasWindowVisible) setWindowVisibilityInternal(false); 820 if (wasAttached) onDetachedFromWindow(); 821 if (!wasPaused) onPause(); 822 823 // Save injected JavaScript interfaces. 824 Map<String, Pair<Object, Class>> javascriptInterfaces = 825 new HashMap<String, Pair<Object, Class>>(); 826 if (mContentViewCore != null) { 827 javascriptInterfaces.putAll(mContentViewCore.getJavascriptInterfaces()); 828 } 829 830 setNewAwContents(popupNativeAwContents); 831 832 // Finally refresh all view state for mContentViewCore and mNativeAwContents. 833 if (!wasPaused) onResume(); 834 if (wasAttached) { 835 onAttachedToWindow(); 836 postInvalidateOnAnimation(); 837 } 838 onSizeChanged(mContainerView.getWidth(), mContainerView.getHeight(), 0, 0); 839 if (wasWindowVisible) setWindowVisibilityInternal(true); 840 if (wasViewVisible) setViewVisibilityInternal(true); 841 if (wasWindowFocused) onWindowFocusChanged(wasWindowFocused); 842 if (wasFocused) onFocusChanged(true, 0, null); 843 844 // Restore injected JavaScript interfaces. 845 for (Map.Entry<String, Pair<Object, Class>> entry : javascriptInterfaces.entrySet()) { 846 @SuppressWarnings("unchecked") 847 Class<? extends Annotation> requiredAnnotation = (Class<? extends Annotation>) 848 entry.getValue().second; 849 mContentViewCore.addPossiblyUnsafeJavascriptInterface( 850 entry.getValue().first, 851 entry.getKey(), 852 requiredAnnotation); 853 } 854 } 855 856 /** 857 * Deletes the native counterpart of this object. 858 */ 859 public void destroy() { 860 if (mCleanupReference != null) { 861 assert mNativeAwContents != 0; 862 // If we are attached, we have to call native detach to clean up 863 // hardware resources. 864 if (mIsAttachedToWindow) { 865 nativeOnDetachedFromWindow(mNativeAwContents); 866 } 867 868 // We explicitly do not null out the mContentViewCore reference here 869 // because ContentViewCore already has code to deal with the case 870 // methods are called on it after it's been destroyed, and other 871 // code relies on AwContents.mContentViewCore to be non-null. 872 mContentViewCore.destroy(); 873 mNativeAwContents = 0; 874 875 mCleanupReference.cleanupNow(); 876 mCleanupReference = null; 877 } 878 879 assert !mContentViewCore.isAlive(); 880 assert mNativeAwContents == 0; 881 } 882 883 @VisibleForTesting 884 public ContentViewCore getContentViewCore() { 885 return mContentViewCore; 886 } 887 888 // Can be called from any thread. 889 public AwSettings getSettings() { 890 return mSettings; 891 } 892 893 public AwPdfExporter getPdfExporter() { 894 // mNativeAwContents can be null, due to destroy(). 895 if (mNativeAwContents == 0) { 896 return null; 897 } 898 if (mAwPdfExporter == null) { 899 mAwPdfExporter = new AwPdfExporter(mContainerView); 900 nativeCreatePdfExporter(mNativeAwContents, mAwPdfExporter); 901 } 902 return mAwPdfExporter; 903 } 904 905 public static void setAwDrawSWFunctionTable(long functionTablePointer) { 906 nativeSetAwDrawSWFunctionTable(functionTablePointer); 907 } 908 909 public static void setAwDrawGLFunctionTable(long functionTablePointer) { 910 nativeSetAwDrawGLFunctionTable(functionTablePointer); 911 } 912 913 public static long getAwDrawGLFunction() { 914 return nativeGetAwDrawGLFunction(); 915 } 916 917 public static void setShouldDownloadFavicons() { 918 nativeSetShouldDownloadFavicons(); 919 } 920 921 /** 922 * Disables contents of JS-to-Java bridge objects to be inspectable using 923 * Object.keys() method and "for .. in" loops. This is intended for applications 924 * targeting earlier Android releases where this was not possible, and we want 925 * to ensure backwards compatible behavior. 926 */ 927 public void disableJavascriptInterfacesInspection() { 928 mContentViewCore.setAllowJavascriptInterfacesInspection(false); 929 } 930 931 /** 932 * Intended for test code. 933 * @return the number of native instances of this class. 934 */ 935 @VisibleForTesting 936 public static int getNativeInstanceCount() { 937 return nativeGetNativeInstanceCount(); 938 } 939 940 public long getAwDrawGLViewContext() { 941 // Only called during early construction, so client should not have had a chance to 942 // call destroy yet. 943 assert mNativeAwContents != 0; 944 945 // Using the native pointer as the returned viewContext. This is matched by the 946 // reinterpret_cast back to BrowserViewRenderer pointer in the native DrawGLFunction. 947 return nativeGetAwDrawGLViewContext(mNativeAwContents); 948 } 949 950 // This is only to avoid heap allocations inside getGlobalVisibleRect. It should treated 951 // as a local variable in the function and not used anywhere else. 952 private static final Rect sLocalGlobalVisibleRect = new Rect(); 953 954 private Rect getGlobalVisibleRect() { 955 if (!mContainerView.getGlobalVisibleRect(sLocalGlobalVisibleRect)) { 956 sLocalGlobalVisibleRect.setEmpty(); 957 } 958 return sLocalGlobalVisibleRect; 959 } 960 961 //-------------------------------------------------------------------------------------------- 962 // WebView[Provider] method implementations (where not provided by ContentViewCore) 963 //-------------------------------------------------------------------------------------------- 964 965 public void onDraw(Canvas canvas) { 966 mAwViewMethods.onDraw(canvas); 967 } 968 969 public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 970 mAwViewMethods.onMeasure(widthMeasureSpec, heightMeasureSpec); 971 } 972 973 public int getContentHeightCss() { 974 return (int) Math.ceil(mContentHeightDip); 975 } 976 977 public int getContentWidthCss() { 978 return (int) Math.ceil(mContentWidthDip); 979 } 980 981 public Picture capturePicture() { 982 if (mNativeAwContents == 0) return null; 983 return new AwPicture(nativeCapturePicture(mNativeAwContents, 984 mScrollOffsetManager.computeHorizontalScrollRange(), 985 mScrollOffsetManager.computeVerticalScrollRange())); 986 } 987 988 public void clearView() { 989 if (mNativeAwContents == 0) return; 990 nativeClearView(mNativeAwContents); 991 } 992 993 /** 994 * Enable the onNewPicture callback. 995 * @param enabled Flag to enable the callback. 996 * @param invalidationOnly Flag to call back only on invalidation without providing a picture. 997 */ 998 public void enableOnNewPicture(boolean enabled, boolean invalidationOnly) { 999 if (mNativeAwContents == 0) return; 1000 if (invalidationOnly) { 1001 mPictureListenerContentProvider = null; 1002 } else if (enabled && mPictureListenerContentProvider == null) { 1003 mPictureListenerContentProvider = new Callable<Picture>() { 1004 @Override 1005 public Picture call() { 1006 return capturePicture(); 1007 } 1008 }; 1009 } 1010 nativeEnableOnNewPicture(mNativeAwContents, enabled); 1011 } 1012 1013 public void findAllAsync(String searchString) { 1014 if (mNativeAwContents == 0) return; 1015 nativeFindAllAsync(mNativeAwContents, searchString); 1016 } 1017 1018 public void findNext(boolean forward) { 1019 if (mNativeAwContents == 0) return; 1020 nativeFindNext(mNativeAwContents, forward); 1021 } 1022 1023 public void clearMatches() { 1024 if (mNativeAwContents == 0) return; 1025 nativeClearMatches(mNativeAwContents); 1026 } 1027 1028 /** 1029 * @return load progress of the WebContents. 1030 */ 1031 public int getMostRecentProgress() { 1032 // WebContentsDelegateAndroid conveniently caches the most recent notified value for us. 1033 return mWebContentsDelegate.getMostRecentProgress(); 1034 } 1035 1036 public Bitmap getFavicon() { 1037 return mFavicon; 1038 } 1039 1040 private void requestVisitedHistoryFromClient() { 1041 ValueCallback<String[]> callback = new ValueCallback<String[]>() { 1042 @Override 1043 public void onReceiveValue(final String[] value) { 1044 ThreadUtils.runOnUiThread(new Runnable() { 1045 @Override 1046 public void run() { 1047 if (mNativeAwContents == 0) return; 1048 nativeAddVisitedLinks(mNativeAwContents, value); 1049 } 1050 }); 1051 } 1052 }; 1053 mContentsClient.getVisitedHistory(callback); 1054 } 1055 1056 /** 1057 * Load url without fixing up the url string. Consumers of ContentView are responsible for 1058 * ensuring the URL passed in is properly formatted (i.e. the scheme has been added if left 1059 * off during user input). 1060 * 1061 * @param params Parameters for this load. 1062 */ 1063 public void loadUrl(LoadUrlParams params) { 1064 if (mNativeAwContents == 0) return; 1065 1066 if (params.getLoadUrlType() == LoadUrlParams.LOAD_TYPE_DATA && 1067 !params.isBaseUrlDataScheme()) { 1068 // This allows data URLs with a non-data base URL access to file:///android_asset/ and 1069 // file:///android_res/ URLs. If AwSettings.getAllowFileAccess permits, it will also 1070 // allow access to file:// URLs (subject to OS level permission checks). 1071 params.setCanLoadLocalResources(true); 1072 } 1073 1074 // If we are reloading the same url, then set transition type as reload. 1075 if (params.getUrl() != null && 1076 params.getUrl().equals(mContentViewCore.getUrl()) && 1077 params.getTransitionType() == PageTransitionTypes.PAGE_TRANSITION_LINK) { 1078 params.setTransitionType(PageTransitionTypes.PAGE_TRANSITION_RELOAD); 1079 } 1080 params.setTransitionType( 1081 params.getTransitionType() | PageTransitionTypes.PAGE_TRANSITION_FROM_API); 1082 1083 // For WebView, always use the user agent override, which is set 1084 // every time the user agent in AwSettings is modified. 1085 params.setOverrideUserAgent(LoadUrlParams.UA_OVERRIDE_TRUE); 1086 1087 1088 // We don't pass extra headers to the content layer, as WebViewClassic 1089 // was adding them in a very narrow set of conditions. See http://crbug.com/306873 1090 // However, if the embedder is attempting to inject a Referer header for their 1091 // loadUrl call, then we set that separately and remove it from the extra headers map/ 1092 final String REFERER = "referer"; 1093 Map<String, String> extraHeaders = params.getExtraHeaders(); 1094 if (extraHeaders != null) { 1095 for (String header : extraHeaders.keySet()) { 1096 if (REFERER.equals(header.toLowerCase(Locale.US))) { 1097 params.setReferrer(new Referrer(extraHeaders.remove(header), 1)); 1098 params.setExtraHeaders(extraHeaders); 1099 break; 1100 } 1101 } 1102 } 1103 1104 nativeSetExtraHeadersForUrl( 1105 mNativeAwContents, params.getUrl(), params.getExtraHttpRequestHeadersString()); 1106 params.setExtraHeaders(new HashMap<String, String>()); 1107 1108 nativeSendCheckRenderThreadResponsiveness(mNativeAwContents); 1109 mContentViewCore.loadUrl(params); 1110 1111 // The behavior of WebViewClassic uses the populateVisitedLinks callback in WebKit. 1112 // Chromium does not use this use code path and the best emulation of this behavior to call 1113 // request visited links once on the first URL load of the WebView. 1114 if (!mHasRequestedVisitedHistoryFromClient) { 1115 mHasRequestedVisitedHistoryFromClient = true; 1116 requestVisitedHistoryFromClient(); 1117 } 1118 1119 if (params.getLoadUrlType() == LoadUrlParams.LOAD_TYPE_DATA && 1120 params.getBaseUrl() != null) { 1121 // Data loads with a base url will be resolved in Blink, and not cause an onPageStarted 1122 // event to be sent. Sending the callback directly from here. 1123 mContentsClient.getCallbackHelper().postOnPageStarted(params.getBaseUrl()); 1124 } 1125 } 1126 1127 /** 1128 * Get the URL of the current page. 1129 * 1130 * @return The URL of the current page or null if it's empty. 1131 */ 1132 public String getUrl() { 1133 String url = mContentViewCore.getUrl(); 1134 if (url == null || url.trim().isEmpty()) return null; 1135 return url; 1136 } 1137 1138 public void requestFocus() { 1139 mAwViewMethods.requestFocus(); 1140 } 1141 1142 public void setBackgroundColor(int color) { 1143 mBaseBackgroundColor = color; 1144 if (mNativeAwContents != 0) nativeSetBackgroundColor(mNativeAwContents, color); 1145 } 1146 1147 /** 1148 * @see android.view.View#setLayerType() 1149 */ 1150 public void setLayerType(int layerType, Paint paint) { 1151 mAwViewMethods.setLayerType(layerType, paint); 1152 } 1153 1154 int getEffectiveBackgroundColor() { 1155 // Do not ask the ContentViewCore for the background color, as it will always 1156 // report white prior to initial navigation or post destruction, whereas we want 1157 // to use the client supplied base value in those cases. 1158 if (mNativeAwContents == 0 || !mContentsClient.isCachedRendererBackgroundColorValid()) { 1159 return mBaseBackgroundColor; 1160 } 1161 return mContentsClient.getCachedRendererBackgroundColor(); 1162 } 1163 1164 public boolean isMultiTouchZoomSupported() { 1165 return mSettings.supportsMultiTouchZoom(); 1166 } 1167 1168 public View getZoomControlsForTest() { 1169 return mZoomControls.getZoomControlsViewForTest(); 1170 } 1171 1172 /** 1173 * @see ContentViewCore#getContentSettings() 1174 */ 1175 public ContentSettings getContentSettings() { 1176 return mContentViewCore.getContentSettings(); 1177 } 1178 1179 /** 1180 * @see View#setOverScrollMode(int) 1181 */ 1182 public void setOverScrollMode(int mode) { 1183 if (mode != View.OVER_SCROLL_NEVER) { 1184 mOverScrollGlow = new OverScrollGlow(mContext, mContainerView); 1185 } else { 1186 mOverScrollGlow = null; 1187 } 1188 } 1189 1190 // TODO(mkosiba): In WebViewClassic these appear in some of the scroll extent calculation 1191 // methods but toggling them has no visiual effect on the content (in other words the scrolling 1192 // code behaves as if the scrollbar-related padding is in place but the onDraw code doesn't 1193 // take that into consideration). 1194 // http://crbug.com/269032 1195 private boolean mOverlayHorizontalScrollbar = true; 1196 private boolean mOverlayVerticalScrollbar = false; 1197 1198 /** 1199 * @see View#setScrollBarStyle(int) 1200 */ 1201 public void setScrollBarStyle(int style) { 1202 if (style == View.SCROLLBARS_INSIDE_OVERLAY 1203 || style == View.SCROLLBARS_OUTSIDE_OVERLAY) { 1204 mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = true; 1205 } else { 1206 mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = false; 1207 } 1208 } 1209 1210 /** 1211 * @see View#setHorizontalScrollbarOverlay(boolean) 1212 */ 1213 public void setHorizontalScrollbarOverlay(boolean overlay) { 1214 mOverlayHorizontalScrollbar = overlay; 1215 } 1216 1217 /** 1218 * @see View#setVerticalScrollbarOverlay(boolean) 1219 */ 1220 public void setVerticalScrollbarOverlay(boolean overlay) { 1221 mOverlayVerticalScrollbar = overlay; 1222 } 1223 1224 /** 1225 * @see View#overlayHorizontalScrollbar() 1226 */ 1227 public boolean overlayHorizontalScrollbar() { 1228 return mOverlayHorizontalScrollbar; 1229 } 1230 1231 /** 1232 * @see View#overlayVerticalScrollbar() 1233 */ 1234 public boolean overlayVerticalScrollbar() { 1235 return mOverlayVerticalScrollbar; 1236 } 1237 1238 /** 1239 * Called by the embedder when the scroll offset of the containing view has changed. 1240 * @see View#onScrollChanged(int,int) 1241 */ 1242 public void onContainerViewScrollChanged(int l, int t, int oldl, int oldt) { 1243 // A side-effect of View.onScrollChanged is that the scroll accessibility event being sent 1244 // by the base class implementation. This is completely hidden from the base classes and 1245 // cannot be prevented, which is why we need the code below. 1246 mScrollAccessibilityHelper.removePostedViewScrolledAccessibilityEventCallback(); 1247 mScrollOffsetManager.onContainerViewScrollChanged(l, t); 1248 } 1249 1250 /** 1251 * Called by the embedder when the containing view is to be scrolled or overscrolled. 1252 * @see View#onOverScrolled(int,int,int,int) 1253 */ 1254 public void onContainerViewOverScrolled(int scrollX, int scrollY, boolean clampedX, 1255 boolean clampedY) { 1256 int oldX = mContainerView.getScrollX(); 1257 int oldY = mContainerView.getScrollY(); 1258 1259 mScrollOffsetManager.onContainerViewOverScrolled(scrollX, scrollY, clampedX, clampedY); 1260 1261 if (mOverScrollGlow != null) { 1262 mOverScrollGlow.pullGlow(mContainerView.getScrollX(), mContainerView.getScrollY(), 1263 oldX, oldY, 1264 mScrollOffsetManager.computeMaximumHorizontalScrollOffset(), 1265 mScrollOffsetManager.computeMaximumVerticalScrollOffset()); 1266 } 1267 } 1268 1269 /** 1270 * @see android.webkit.WebView#requestChildRectangleOnScreen(View, Rect, boolean) 1271 */ 1272 public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) { 1273 return mScrollOffsetManager.requestChildRectangleOnScreen( 1274 child.getLeft() - child.getScrollX(), child.getTop() - child.getScrollY(), 1275 rect, immediate); 1276 } 1277 1278 /** 1279 * @see View.computeScroll() 1280 */ 1281 public void computeScroll() { 1282 mScrollOffsetManager.computeScrollAndAbsorbGlow(mOverScrollGlow); 1283 } 1284 1285 /** 1286 * @see View#computeHorizontalScrollRange() 1287 */ 1288 public int computeHorizontalScrollRange() { 1289 return mScrollOffsetManager.computeHorizontalScrollRange(); 1290 } 1291 1292 /** 1293 * @see View#computeHorizontalScrollOffset() 1294 */ 1295 public int computeHorizontalScrollOffset() { 1296 return mScrollOffsetManager.computeHorizontalScrollOffset(); 1297 } 1298 1299 /** 1300 * @see View#computeVerticalScrollRange() 1301 */ 1302 public int computeVerticalScrollRange() { 1303 return mScrollOffsetManager.computeVerticalScrollRange(); 1304 } 1305 1306 /** 1307 * @see View#computeVerticalScrollOffset() 1308 */ 1309 public int computeVerticalScrollOffset() { 1310 return mScrollOffsetManager.computeVerticalScrollOffset(); 1311 } 1312 1313 /** 1314 * @see View#computeVerticalScrollExtent() 1315 */ 1316 public int computeVerticalScrollExtent() { 1317 return mScrollOffsetManager.computeVerticalScrollExtent(); 1318 } 1319 1320 /** 1321 * @see android.webkit.WebView#stopLoading() 1322 */ 1323 public void stopLoading() { 1324 mContentViewCore.stopLoading(); 1325 } 1326 1327 /** 1328 * @see android.webkit.WebView#reload() 1329 */ 1330 public void reload() { 1331 mContentViewCore.reload(true); 1332 } 1333 1334 /** 1335 * @see android.webkit.WebView#canGoBack() 1336 */ 1337 public boolean canGoBack() { 1338 return mContentViewCore.canGoBack(); 1339 } 1340 1341 /** 1342 * @see android.webkit.WebView#goBack() 1343 */ 1344 public void goBack() { 1345 mContentViewCore.goBack(); 1346 } 1347 1348 /** 1349 * @see android.webkit.WebView#canGoForward() 1350 */ 1351 public boolean canGoForward() { 1352 return mContentViewCore.canGoForward(); 1353 } 1354 1355 /** 1356 * @see android.webkit.WebView#goForward() 1357 */ 1358 public void goForward() { 1359 mContentViewCore.goForward(); 1360 } 1361 1362 /** 1363 * @see android.webkit.WebView#canGoBackOrForward(int) 1364 */ 1365 public boolean canGoBackOrForward(int steps) { 1366 return mContentViewCore.canGoToOffset(steps); 1367 } 1368 1369 /** 1370 * @see android.webkit.WebView#goBackOrForward(int) 1371 */ 1372 public void goBackOrForward(int steps) { 1373 mContentViewCore.goToOffset(steps); 1374 } 1375 1376 /** 1377 * @see android.webkit.WebView#pauseTimers() 1378 */ 1379 public void pauseTimers() { 1380 ContentViewStatics.setWebKitSharedTimersSuspended(true); 1381 } 1382 1383 /** 1384 * @see android.webkit.WebView#resumeTimers() 1385 */ 1386 public void resumeTimers() { 1387 ContentViewStatics.setWebKitSharedTimersSuspended(false); 1388 } 1389 1390 /** 1391 * @see android.webkit.WebView#onPause() 1392 */ 1393 public void onPause() { 1394 if (mIsPaused || mNativeAwContents == 0) return; 1395 mIsPaused = true; 1396 nativeSetIsPaused(mNativeAwContents, mIsPaused); 1397 } 1398 1399 /** 1400 * @see android.webkit.WebView#onResume() 1401 */ 1402 public void onResume() { 1403 if (!mIsPaused || mNativeAwContents == 0) return; 1404 mIsPaused = false; 1405 nativeSetIsPaused(mNativeAwContents, mIsPaused); 1406 } 1407 1408 /** 1409 * @see android.webkit.WebView#isPaused() 1410 */ 1411 public boolean isPaused() { 1412 return mIsPaused; 1413 } 1414 1415 /** 1416 * @see android.webkit.WebView#onCreateInputConnection(EditorInfo) 1417 */ 1418 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 1419 return mAwViewMethods.onCreateInputConnection(outAttrs); 1420 } 1421 1422 /** 1423 * @see android.webkit.WebView#onKeyUp(int, KeyEvent) 1424 */ 1425 public boolean onKeyUp(int keyCode, KeyEvent event) { 1426 return mAwViewMethods.onKeyUp(keyCode, event); 1427 } 1428 1429 /** 1430 * @see android.webkit.WebView#dispatchKeyEvent(KeyEvent) 1431 */ 1432 public boolean dispatchKeyEvent(KeyEvent event) { 1433 return mAwViewMethods.dispatchKeyEvent(event); 1434 } 1435 1436 /** 1437 * Clears the resource cache. Note that the cache is per-application, so this will clear the 1438 * cache for all WebViews used. 1439 * 1440 * @param includeDiskFiles if false, only the RAM cache is cleared 1441 */ 1442 public void clearCache(boolean includeDiskFiles) { 1443 if (mNativeAwContents == 0) return; 1444 nativeClearCache(mNativeAwContents, includeDiskFiles); 1445 } 1446 1447 public void documentHasImages(Message message) { 1448 if (mNativeAwContents == 0) return; 1449 nativeDocumentHasImages(mNativeAwContents, message); 1450 } 1451 1452 public void saveWebArchive( 1453 final String basename, boolean autoname, final ValueCallback<String> callback) { 1454 if (!autoname) { 1455 saveWebArchiveInternal(basename, callback); 1456 return; 1457 } 1458 // If auto-generating the file name, handle the name generation on a background thread 1459 // as it will require I/O access for checking whether previous files existed. 1460 new AsyncTask<Void, Void, String>() { 1461 @Override 1462 protected String doInBackground(Void... params) { 1463 return generateArchiveAutoNamePath(getOriginalUrl(), basename); 1464 } 1465 1466 @Override 1467 protected void onPostExecute(String result) { 1468 saveWebArchiveInternal(result, callback); 1469 } 1470 }.execute(); 1471 } 1472 1473 public String getOriginalUrl() { 1474 NavigationHistory history = mContentViewCore.getNavigationHistory(); 1475 int currentIndex = history.getCurrentEntryIndex(); 1476 if (currentIndex >= 0 && currentIndex < history.getEntryCount()) { 1477 return history.getEntryAtIndex(currentIndex).getOriginalUrl(); 1478 } 1479 return null; 1480 } 1481 1482 /** 1483 * @see ContentViewCore#getNavigationHistory() 1484 */ 1485 public NavigationHistory getNavigationHistory() { 1486 return mContentViewCore.getNavigationHistory(); 1487 } 1488 1489 /** 1490 * @see android.webkit.WebView#getTitle() 1491 */ 1492 public String getTitle() { 1493 return mContentViewCore.getTitle(); 1494 } 1495 1496 /** 1497 * @see android.webkit.WebView#clearHistory() 1498 */ 1499 public void clearHistory() { 1500 mContentViewCore.clearHistory(); 1501 } 1502 1503 public String[] getHttpAuthUsernamePassword(String host, String realm) { 1504 return mBrowserContext.getHttpAuthDatabase(mContext) 1505 .getHttpAuthUsernamePassword(host, realm); 1506 } 1507 1508 public void setHttpAuthUsernamePassword(String host, String realm, String username, 1509 String password) { 1510 mBrowserContext.getHttpAuthDatabase(mContext) 1511 .setHttpAuthUsernamePassword(host, realm, username, password); 1512 } 1513 1514 /** 1515 * @see android.webkit.WebView#getCertificate() 1516 */ 1517 public SslCertificate getCertificate() { 1518 if (mNativeAwContents == 0) return null; 1519 return SslUtil.getCertificateFromDerBytes(nativeGetCertificate(mNativeAwContents)); 1520 } 1521 1522 /** 1523 * @see android.webkit.WebView#clearSslPreferences() 1524 */ 1525 public void clearSslPreferences() { 1526 mContentViewCore.clearSslPreferences(); 1527 } 1528 1529 // TODO(sgurun) remove after this rolls in. To keep internal tree happy. 1530 public void clearClientCertPreferences() { } 1531 1532 /** 1533 * Method to return all hit test values relevant to public WebView API. 1534 * Note that this expose more data than needed for WebView.getHitTestResult. 1535 * Unsafely returning reference to mutable internal object to avoid excessive 1536 * garbage allocation on repeated calls. 1537 */ 1538 public HitTestData getLastHitTestResult() { 1539 if (mNativeAwContents == 0) return null; 1540 nativeUpdateLastHitTestData(mNativeAwContents); 1541 return mPossiblyStaleHitTestData; 1542 } 1543 1544 /** 1545 * @see android.webkit.WebView#requestFocusNodeHref() 1546 */ 1547 public void requestFocusNodeHref(Message msg) { 1548 if (msg == null || mNativeAwContents == 0) return; 1549 1550 nativeUpdateLastHitTestData(mNativeAwContents); 1551 Bundle data = msg.getData(); 1552 1553 // In order to maintain compatibility with the old WebView's implementation, 1554 // the absolute (full) url is passed in the |url| field, not only the href attribute. 1555 // Note: HitTestData could be cleaned up at this point. See http://crbug.com/290992. 1556 data.putString("url", mPossiblyStaleHitTestData.href); 1557 data.putString("title", mPossiblyStaleHitTestData.anchorText); 1558 data.putString("src", mPossiblyStaleHitTestData.imgSrc); 1559 msg.setData(data); 1560 msg.sendToTarget(); 1561 } 1562 1563 /** 1564 * @see android.webkit.WebView#requestImageRef() 1565 */ 1566 public void requestImageRef(Message msg) { 1567 if (msg == null || mNativeAwContents == 0) return; 1568 1569 nativeUpdateLastHitTestData(mNativeAwContents); 1570 Bundle data = msg.getData(); 1571 data.putString("url", mPossiblyStaleHitTestData.imgSrc); 1572 msg.setData(data); 1573 msg.sendToTarget(); 1574 } 1575 1576 @VisibleForTesting 1577 public float getPageScaleFactor() { 1578 return mPageScaleFactor; 1579 } 1580 1581 /** 1582 * @see android.webkit.WebView#getScale() 1583 * 1584 * Please note that the scale returned is the page scale multiplied by 1585 * the screen density factor. See CTS WebViewTest.testSetInitialScale. 1586 */ 1587 public float getScale() { 1588 return (float)(mPageScaleFactor * mDIPScale); 1589 } 1590 1591 /** 1592 * @see android.webkit.WebView#flingScroll(int, int) 1593 */ 1594 public void flingScroll(int velocityX, int velocityY) { 1595 mScrollOffsetManager.flingScroll(velocityX, velocityY); 1596 } 1597 1598 /** 1599 * @see android.webkit.WebView#pageUp(boolean) 1600 */ 1601 public boolean pageUp(boolean top) { 1602 return mScrollOffsetManager.pageUp(top); 1603 } 1604 1605 /** 1606 * @see android.webkit.WebView#pageDown(boolean) 1607 */ 1608 public boolean pageDown(boolean bottom) { 1609 return mScrollOffsetManager.pageDown(bottom); 1610 } 1611 1612 /** 1613 * @see android.webkit.WebView#canZoomIn() 1614 */ 1615 // This method uses the term 'zoom' for legacy reasons, but relates 1616 // to what chrome calls the 'page scale factor'. 1617 public boolean canZoomIn() { 1618 final float zoomInExtent = mMaxPageScaleFactor - mPageScaleFactor; 1619 return zoomInExtent > ZOOM_CONTROLS_EPSILON; 1620 } 1621 1622 /** 1623 * @see android.webkit.WebView#canZoomOut() 1624 */ 1625 // This method uses the term 'zoom' for legacy reasons, but relates 1626 // to what chrome calls the 'page scale factor'. 1627 public boolean canZoomOut() { 1628 final float zoomOutExtent = mPageScaleFactor - mMinPageScaleFactor; 1629 return zoomOutExtent > ZOOM_CONTROLS_EPSILON; 1630 } 1631 1632 /** 1633 * @see android.webkit.WebView#zoomIn() 1634 */ 1635 // This method uses the term 'zoom' for legacy reasons, but relates 1636 // to what chrome calls the 'page scale factor'. 1637 public boolean zoomIn() { 1638 if (!canZoomIn()) { 1639 return false; 1640 } 1641 return zoomBy(1.25f); 1642 } 1643 1644 /** 1645 * @see android.webkit.WebView#zoomOut() 1646 */ 1647 // This method uses the term 'zoom' for legacy reasons, but relates 1648 // to what chrome calls the 'page scale factor'. 1649 public boolean zoomOut() { 1650 if (!canZoomOut()) { 1651 return false; 1652 } 1653 return zoomBy(0.8f); 1654 } 1655 1656 /** 1657 * @see android.webkit.WebView#zoomBy() 1658 */ 1659 // This method uses the term 'zoom' for legacy reasons, but relates 1660 // to what chrome calls the 'page scale factor'. 1661 public boolean zoomBy(float delta) { 1662 if (delta < 0.01f || delta > 100.0f) { 1663 throw new IllegalStateException("zoom delta value outside [0.01, 100] range."); 1664 } 1665 return mContentViewCore.pinchByDelta(delta); 1666 } 1667 1668 /** 1669 * @see android.webkit.WebView#invokeZoomPicker() 1670 */ 1671 public void invokeZoomPicker() { 1672 mContentViewCore.invokeZoomPicker(); 1673 } 1674 1675 /** 1676 * @see android.webkit.WebView#preauthorizePermission(Uri, long) 1677 */ 1678 public void preauthorizePermission(Uri origin, long resources) { 1679 if (mNativeAwContents == 0) return; 1680 nativePreauthorizePermission(mNativeAwContents, origin.toString(), resources); 1681 } 1682 1683 /** 1684 * @see ContentViewCore.evaluateJavaScript(String, JavaScriptCallback) 1685 */ 1686 public void evaluateJavaScript(String script, final ValueCallback<String> callback) { 1687 JavaScriptCallback jsCallback = null; 1688 if (callback != null) { 1689 jsCallback = new JavaScriptCallback() { 1690 @Override 1691 public void handleJavaScriptResult(String jsonResult) { 1692 callback.onReceiveValue(jsonResult); 1693 } 1694 }; 1695 } 1696 1697 mContentViewCore.evaluateJavaScript(script, jsCallback); 1698 } 1699 1700 /** 1701 * @see ContentViewCore.evaluateJavaScriptEvenIfNotYetNavigated(String) 1702 */ 1703 public void evaluateJavaScriptEvenIfNotYetNavigated(String script) { 1704 mContentViewCore.evaluateJavaScriptEvenIfNotYetNavigated(script); 1705 } 1706 1707 //-------------------------------------------------------------------------------------------- 1708 // View and ViewGroup method implementations 1709 //-------------------------------------------------------------------------------------------- 1710 1711 /** 1712 * @see android.webkit.View#onTouchEvent() 1713 */ 1714 public boolean onTouchEvent(MotionEvent event) { 1715 return mAwViewMethods.onTouchEvent(event); 1716 } 1717 1718 /** 1719 * @see android.view.View#onHoverEvent() 1720 */ 1721 public boolean onHoverEvent(MotionEvent event) { 1722 return mAwViewMethods.onHoverEvent(event); 1723 } 1724 1725 /** 1726 * @see android.view.View#onGenericMotionEvent() 1727 */ 1728 public boolean onGenericMotionEvent(MotionEvent event) { 1729 return mContentViewCore.onGenericMotionEvent(event); 1730 } 1731 1732 /** 1733 * @see android.view.View#onConfigurationChanged() 1734 */ 1735 public void onConfigurationChanged(Configuration newConfig) { 1736 mAwViewMethods.onConfigurationChanged(newConfig); 1737 } 1738 1739 /** 1740 * @see android.view.View#onAttachedToWindow() 1741 */ 1742 public void onAttachedToWindow() { 1743 mTemporarilyDetached = false; 1744 mAwViewMethods.onAttachedToWindow(); 1745 } 1746 1747 /** 1748 * @see android.view.View#onDetachedFromWindow() 1749 */ 1750 @SuppressLint("MissingSuperCall") 1751 public void onDetachedFromWindow() { 1752 mAwViewMethods.onDetachedFromWindow(); 1753 } 1754 1755 /** 1756 * @see android.view.View#onWindowFocusChanged() 1757 */ 1758 public void onWindowFocusChanged(boolean hasWindowFocus) { 1759 mAwViewMethods.onWindowFocusChanged(hasWindowFocus); 1760 } 1761 1762 /** 1763 * @see android.view.View#onFocusChanged() 1764 */ 1765 public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { 1766 if (!mTemporarilyDetached) { 1767 mAwViewMethods.onFocusChanged(focused, direction, previouslyFocusedRect); 1768 } 1769 } 1770 1771 /** 1772 * @see android.view.View#onStartTemporaryDetach() 1773 */ 1774 public void onStartTemporaryDetach() { 1775 mTemporarilyDetached = true; 1776 } 1777 1778 /** 1779 * @see android.view.View#onFinishTemporaryDetach() 1780 */ 1781 public void onFinishTemporaryDetach() { 1782 mTemporarilyDetached = false; 1783 } 1784 1785 /** 1786 * @see android.view.View#onSizeChanged() 1787 */ 1788 public void onSizeChanged(int w, int h, int ow, int oh) { 1789 mAwViewMethods.onSizeChanged(w, h, ow, oh); 1790 } 1791 1792 /** 1793 * @see android.view.View#onVisibilityChanged() 1794 */ 1795 public void onVisibilityChanged(View changedView, int visibility) { 1796 mAwViewMethods.onVisibilityChanged(changedView, visibility); 1797 } 1798 1799 /** 1800 * @see android.view.View#onWindowVisibilityChanged() 1801 */ 1802 public void onWindowVisibilityChanged(int visibility) { 1803 mAwViewMethods.onWindowVisibilityChanged(visibility); 1804 } 1805 1806 private void setViewVisibilityInternal(boolean visible) { 1807 mIsViewVisible = visible; 1808 if (mNativeAwContents == 0) return; 1809 nativeSetViewVisibility(mNativeAwContents, mIsViewVisible); 1810 } 1811 1812 private void setWindowVisibilityInternal(boolean visible) { 1813 mIsWindowVisible = visible; 1814 if (mNativeAwContents == 0) return; 1815 nativeSetWindowVisibility(mNativeAwContents, mIsWindowVisible); 1816 } 1817 1818 /** 1819 * Key for opaque state in bundle. Note this is only public for tests. 1820 */ 1821 public static final String SAVE_RESTORE_STATE_KEY = "WEBVIEW_CHROMIUM_STATE"; 1822 1823 /** 1824 * Save the state of this AwContents into provided Bundle. 1825 * @return False if saving state failed. 1826 */ 1827 public boolean saveState(Bundle outState) { 1828 if (mNativeAwContents == 0 || outState == null) return false; 1829 1830 byte[] state = nativeGetOpaqueState(mNativeAwContents); 1831 if (state == null) return false; 1832 1833 outState.putByteArray(SAVE_RESTORE_STATE_KEY, state); 1834 return true; 1835 } 1836 1837 /** 1838 * Restore the state of this AwContents into provided Bundle. 1839 * @param inState Must be a bundle returned by saveState. 1840 * @return False if restoring state failed. 1841 */ 1842 public boolean restoreState(Bundle inState) { 1843 if (mNativeAwContents == 0 || inState == null) return false; 1844 1845 byte[] state = inState.getByteArray(SAVE_RESTORE_STATE_KEY); 1846 if (state == null) return false; 1847 1848 boolean result = nativeRestoreFromOpaqueState(mNativeAwContents, state); 1849 1850 // The onUpdateTitle callback normally happens when a page is loaded, 1851 // but is optimized out in the restoreState case because the title is 1852 // already restored. See WebContentsImpl::UpdateTitleForEntry. So we 1853 // call the callback explicitly here. 1854 if (result) mContentsClient.onReceivedTitle(mContentViewCore.getTitle()); 1855 1856 return result; 1857 } 1858 1859 /** 1860 * @see ContentViewCore#addPossiblyUnsafeJavascriptInterface(Object, String, Class) 1861 */ 1862 public void addPossiblyUnsafeJavascriptInterface(Object object, String name, 1863 Class<? extends Annotation> requiredAnnotation) { 1864 mContentViewCore.addPossiblyUnsafeJavascriptInterface(object, name, requiredAnnotation); 1865 } 1866 1867 /** 1868 * @see android.webkit.WebView#removeJavascriptInterface(String) 1869 */ 1870 public void removeJavascriptInterface(String interfaceName) { 1871 mContentViewCore.removeJavascriptInterface(interfaceName); 1872 } 1873 1874 /** 1875 * If native accessibility (not script injection) is enabled, and if this is 1876 * running on JellyBean or later, returns an AccessibilityNodeProvider that 1877 * implements native accessibility for this view. Returns null otherwise. 1878 * @return The AccessibilityNodeProvider, if available, or null otherwise. 1879 */ 1880 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 1881 return mContentViewCore.getAccessibilityNodeProvider(); 1882 } 1883 1884 /** 1885 * @see android.webkit.WebView#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 1886 */ 1887 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 1888 mContentViewCore.onInitializeAccessibilityNodeInfo(info); 1889 } 1890 1891 /** 1892 * @see android.webkit.WebView#onInitializeAccessibilityEvent(AccessibilityEvent) 1893 */ 1894 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 1895 mContentViewCore.onInitializeAccessibilityEvent(event); 1896 } 1897 1898 public boolean supportsAccessibilityAction(int action) { 1899 return mContentViewCore.supportsAccessibilityAction(action); 1900 } 1901 1902 /** 1903 * @see android.webkit.WebView#performAccessibilityAction(int, Bundle) 1904 */ 1905 public boolean performAccessibilityAction(int action, Bundle arguments) { 1906 return mContentViewCore.performAccessibilityAction(action, arguments); 1907 } 1908 1909 /** 1910 * @see android.webkit.WebView#clearFormData() 1911 */ 1912 public void hideAutofillPopup() { 1913 if (mAwAutofillClient != null) { 1914 mAwAutofillClient.hideAutofillPopup(); 1915 } 1916 } 1917 1918 public void setNetworkAvailable(boolean networkUp) { 1919 if (mNativeAwContents == 0) return; 1920 nativeSetJsOnlineProperty(mNativeAwContents, networkUp); 1921 } 1922 1923 //-------------------------------------------------------------------------------------------- 1924 // Methods called from native via JNI 1925 //-------------------------------------------------------------------------------------------- 1926 1927 @CalledByNative 1928 private static void onDocumentHasImagesResponse(boolean result, Message message) { 1929 message.arg1 = result ? 1 : 0; 1930 message.sendToTarget(); 1931 } 1932 1933 @CalledByNative 1934 private void onReceivedTouchIconUrl(String url, boolean precomposed) { 1935 mContentsClient.onReceivedTouchIconUrl(url, precomposed); 1936 } 1937 1938 @CalledByNative 1939 private void onReceivedIcon(Bitmap bitmap) { 1940 mContentsClient.onReceivedIcon(bitmap); 1941 mFavicon = bitmap; 1942 } 1943 1944 /** Callback for generateMHTML. */ 1945 @CalledByNative 1946 private static void generateMHTMLCallback( 1947 String path, long size, ValueCallback<String> callback) { 1948 if (callback == null) return; 1949 callback.onReceiveValue(size < 0 ? null : path); 1950 } 1951 1952 @CalledByNative 1953 private void onReceivedHttpAuthRequest(AwHttpAuthHandler handler, String host, String realm) { 1954 mContentsClient.onReceivedHttpAuthRequest(handler, host, realm); 1955 } 1956 1957 private class AwGeolocationCallback implements GeolocationPermissions.Callback { 1958 1959 @Override 1960 public void invoke(final String origin, final boolean allow, final boolean retain) { 1961 ThreadUtils.runOnUiThread(new Runnable() { 1962 @Override 1963 public void run() { 1964 if (retain) { 1965 if (allow) { 1966 mBrowserContext.getGeolocationPermissions().allow(origin); 1967 } else { 1968 mBrowserContext.getGeolocationPermissions().deny(origin); 1969 } 1970 } 1971 if (mNativeAwContents == 0) return; 1972 nativeInvokeGeolocationCallback(mNativeAwContents, allow, origin); 1973 } 1974 }); 1975 } 1976 } 1977 1978 @CalledByNative 1979 private void onGeolocationPermissionsShowPrompt(String origin) { 1980 if (mNativeAwContents == 0) return; 1981 AwGeolocationPermissions permissions = mBrowserContext.getGeolocationPermissions(); 1982 // Reject if geoloaction is disabled, or the origin has a retained deny 1983 if (!mSettings.getGeolocationEnabled()) { 1984 nativeInvokeGeolocationCallback(mNativeAwContents, false, origin); 1985 return; 1986 } 1987 // Allow if the origin has a retained allow 1988 if (permissions.hasOrigin(origin)) { 1989 nativeInvokeGeolocationCallback(mNativeAwContents, permissions.isOriginAllowed(origin), 1990 origin); 1991 return; 1992 } 1993 mContentsClient.onGeolocationPermissionsShowPrompt( 1994 origin, new AwGeolocationCallback()); 1995 } 1996 1997 @CalledByNative 1998 private void onGeolocationPermissionsHidePrompt() { 1999 mContentsClient.onGeolocationPermissionsHidePrompt(); 2000 } 2001 2002 @CalledByNative 2003 private void onPermissionRequest(AwPermissionRequest awPermissionRequest) { 2004 mContentsClient.onPermissionRequest(awPermissionRequest); 2005 } 2006 2007 @CalledByNative 2008 private void onPermissionRequestCanceled(AwPermissionRequest awPermissionRequest) { 2009 mContentsClient.onPermissionRequestCanceled(awPermissionRequest); 2010 } 2011 2012 @CalledByNative 2013 public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, 2014 boolean isDoneCounting) { 2015 mContentsClient.onFindResultReceived(activeMatchOrdinal, numberOfMatches, isDoneCounting); 2016 } 2017 2018 @CalledByNative 2019 public void onNewPicture() { 2020 // Don't call capturePicture() here but instead defer it until the posted task runs within 2021 // the callback helper, to avoid doubling back into the renderer compositor in the middle 2022 // of the notification it is sending up to here. 2023 mContentsClient.getCallbackHelper().postOnNewPicture(mPictureListenerContentProvider); 2024 } 2025 2026 // Called as a result of nativeUpdateLastHitTestData. 2027 @CalledByNative 2028 private void updateHitTestData( 2029 int type, String extra, String href, String anchorText, String imgSrc) { 2030 mPossiblyStaleHitTestData.hitTestResultType = type; 2031 mPossiblyStaleHitTestData.hitTestResultExtraData = extra; 2032 mPossiblyStaleHitTestData.href = href; 2033 mPossiblyStaleHitTestData.anchorText = anchorText; 2034 mPossiblyStaleHitTestData.imgSrc = imgSrc; 2035 } 2036 2037 @CalledByNative 2038 private boolean requestDrawGL(Canvas canvas, boolean waitForCompletion) { 2039 return mNativeGLDelegate.requestDrawGL(canvas, waitForCompletion, mContainerView); 2040 } 2041 2042 private static final boolean SUPPORTS_ON_ANIMATION = 2043 Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; 2044 2045 @CalledByNative 2046 private void postInvalidateOnAnimation() { 2047 if (SUPPORTS_ON_ANIMATION && !mWindowAndroid.isInsideVSync()) { 2048 mContainerView.postInvalidateOnAnimation(); 2049 } else { 2050 mContainerView.invalidate(); 2051 } 2052 } 2053 2054 @CalledByNative 2055 private int[] getLocationOnScreen() { 2056 int[] result = new int[2]; 2057 mContainerView.getLocationOnScreen(result); 2058 return result; 2059 } 2060 2061 @CalledByNative 2062 private void onWebLayoutPageScaleFactorChanged(float webLayoutPageScaleFactor) { 2063 // This change notification comes from the renderer thread, not from the cc/ impl thread. 2064 mLayoutSizer.onPageScaleChanged(webLayoutPageScaleFactor); 2065 } 2066 2067 @CalledByNative 2068 private void onWebLayoutContentsSizeChanged(int widthCss, int heightCss) { 2069 // This change notification comes from the renderer thread, not from the cc/ impl thread. 2070 mLayoutSizer.onContentSizeChanged(widthCss, heightCss); 2071 } 2072 2073 @CalledByNative 2074 private void scrollContainerViewTo(int x, int y) { 2075 mScrollOffsetManager.scrollContainerViewTo(x, y); 2076 } 2077 2078 @CalledByNative 2079 private boolean isFlingActive() { 2080 return mScrollOffsetManager.isFlingActive(); 2081 } 2082 2083 @CalledByNative 2084 private void updateScrollState(int maxContainerViewScrollOffsetX, 2085 int maxContainerViewScrollOffsetY, int contentWidthDip, int contentHeightDip, 2086 float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor) { 2087 mContentWidthDip = contentWidthDip; 2088 mContentHeightDip = contentHeightDip; 2089 mScrollOffsetManager.setMaxScrollOffset(maxContainerViewScrollOffsetX, 2090 maxContainerViewScrollOffsetY); 2091 setPageScaleFactorAndLimits(pageScaleFactor, minPageScaleFactor, maxPageScaleFactor); 2092 } 2093 2094 @CalledByNative 2095 private void setAwAutofillClient(AwAutofillClient client) { 2096 mAwAutofillClient = client; 2097 client.init(mContentViewCore); 2098 } 2099 2100 @CalledByNative 2101 private void didOverscroll(int deltaX, int deltaY) { 2102 if (mOverScrollGlow != null) { 2103 mOverScrollGlow.setOverScrollDeltas(deltaX, deltaY); 2104 } 2105 2106 mScrollOffsetManager.overScrollBy(deltaX, deltaY); 2107 2108 if (mOverScrollGlow != null && mOverScrollGlow.isAnimating()) { 2109 mContainerView.invalidate(); 2110 } 2111 } 2112 2113 // ------------------------------------------------------------------------------------------- 2114 // Helper methods 2115 // ------------------------------------------------------------------------------------------- 2116 2117 private void setPageScaleFactorAndLimits( 2118 float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor) { 2119 if (mPageScaleFactor == pageScaleFactor && 2120 mMinPageScaleFactor == minPageScaleFactor && 2121 mMaxPageScaleFactor == maxPageScaleFactor) { 2122 return; 2123 } 2124 mMinPageScaleFactor = minPageScaleFactor; 2125 mMaxPageScaleFactor = maxPageScaleFactor; 2126 if (mPageScaleFactor != pageScaleFactor) { 2127 float oldPageScaleFactor = mPageScaleFactor; 2128 mPageScaleFactor = pageScaleFactor; 2129 mContentsClient.getCallbackHelper().postOnScaleChangedScaled( 2130 (float)(oldPageScaleFactor * mDIPScale), 2131 (float)(mPageScaleFactor * mDIPScale)); 2132 } 2133 } 2134 2135 private void saveWebArchiveInternal(String path, final ValueCallback<String> callback) { 2136 if (path == null || mNativeAwContents == 0) { 2137 ThreadUtils.runOnUiThread(new Runnable() { 2138 @Override 2139 public void run() { 2140 callback.onReceiveValue(null); 2141 } 2142 }); 2143 } else { 2144 nativeGenerateMHTML(mNativeAwContents, path, callback); 2145 } 2146 } 2147 2148 /** 2149 * Try to generate a pathname for saving an MHTML archive. This roughly follows WebView's 2150 * autoname logic. 2151 */ 2152 private static String generateArchiveAutoNamePath(String originalUrl, String baseName) { 2153 String name = null; 2154 if (originalUrl != null && !originalUrl.isEmpty()) { 2155 try { 2156 String path = new URL(originalUrl).getPath(); 2157 int lastSlash = path.lastIndexOf('/'); 2158 if (lastSlash > 0) { 2159 name = path.substring(lastSlash + 1); 2160 } else { 2161 name = path; 2162 } 2163 } catch (MalformedURLException e) { 2164 // If it fails parsing the URL, we'll just rely on the default name below. 2165 } 2166 } 2167 2168 if (TextUtils.isEmpty(name)) name = "index"; 2169 2170 String testName = baseName + name + WEB_ARCHIVE_EXTENSION; 2171 if (!new File(testName).exists()) return testName; 2172 2173 for (int i = 1; i < 100; i++) { 2174 testName = baseName + name + "-" + i + WEB_ARCHIVE_EXTENSION; 2175 if (!new File(testName).exists()) return testName; 2176 } 2177 2178 Log.e(TAG, "Unable to auto generate archive name for path: " + baseName); 2179 return null; 2180 } 2181 2182 public void extractSmartClipData(int x, int y, int width, int height) { 2183 mContentViewCore.extractSmartClipData(x, y, width, height); 2184 } 2185 2186 public void setSmartClipDataListener(ContentViewCore.SmartClipDataListener listener) { 2187 mContentViewCore.setSmartClipDataListener(listener); 2188 } 2189 2190 // -------------------------------------------------------------------------------------------- 2191 // This is the AwViewMethods implementation that does real work. The AwViewMethodsImpl is 2192 // hooked up to the WebView in embedded mode and to the FullScreenView in fullscreen mode, 2193 // but not to both at the same time. 2194 private class AwViewMethodsImpl implements AwViewMethods { 2195 private int mLayerType = View.LAYER_TYPE_NONE; 2196 private ComponentCallbacks2 mComponentCallbacks; 2197 2198 // Only valid within software onDraw(). 2199 private final Rect mClipBoundsTemporary = new Rect(); 2200 2201 @Override 2202 public void onDraw(Canvas canvas) { 2203 if (mNativeAwContents == 0) { 2204 canvas.drawColor(getEffectiveBackgroundColor()); 2205 return; 2206 } 2207 2208 // For hardware draws, the clip at onDraw time could be different 2209 // from the clip during DrawGL. 2210 if (!canvas.isHardwareAccelerated() && !canvas.getClipBounds(mClipBoundsTemporary)) { 2211 return; 2212 } 2213 2214 mScrollOffsetManager.syncScrollOffsetFromOnDraw(); 2215 Rect globalVisibleRect = getGlobalVisibleRect(); 2216 if (!nativeOnDraw(mNativeAwContents, canvas, canvas.isHardwareAccelerated(), 2217 mContainerView.getScrollX(), mContainerView.getScrollY(), 2218 globalVisibleRect.left, globalVisibleRect.top, 2219 globalVisibleRect.right, globalVisibleRect.bottom)) { 2220 // Can happen during initialization when compositor is not set 2221 // up. Or when clearView 2222 // is in effect. Just draw background color instead. 2223 canvas.drawColor(getEffectiveBackgroundColor()); 2224 } 2225 2226 if (mOverScrollGlow != null && mOverScrollGlow.drawEdgeGlows(canvas, 2227 mScrollOffsetManager.computeMaximumHorizontalScrollOffset(), 2228 mScrollOffsetManager.computeMaximumVerticalScrollOffset())) { 2229 mContainerView.invalidate(); 2230 } 2231 } 2232 2233 @Override 2234 public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 2235 mLayoutSizer.onMeasure(widthMeasureSpec, heightMeasureSpec); 2236 } 2237 2238 @Override 2239 public void requestFocus() { 2240 if (mNativeAwContents == 0) return; 2241 if (!mContainerView.isInTouchMode() && mSettings.shouldFocusFirstNode()) { 2242 nativeFocusFirstNode(mNativeAwContents); 2243 } 2244 } 2245 2246 @Override 2247 public void setLayerType(int layerType, Paint paint) { 2248 mLayerType = layerType; 2249 updateHardwareAcceleratedFeaturesToggle(); 2250 } 2251 2252 private void updateHardwareAcceleratedFeaturesToggle() { 2253 mSettings.setEnableSupportedHardwareAcceleratedFeatures( 2254 mIsAttachedToWindow && mContainerView.isHardwareAccelerated() && 2255 (mLayerType == View.LAYER_TYPE_NONE 2256 || mLayerType == View.LAYER_TYPE_HARDWARE)); 2257 } 2258 2259 @Override 2260 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 2261 return mContentViewCore.onCreateInputConnection(outAttrs); 2262 } 2263 2264 @Override 2265 public boolean onKeyUp(int keyCode, KeyEvent event) { 2266 return mContentViewCore.onKeyUp(keyCode, event); 2267 } 2268 2269 @Override 2270 public boolean dispatchKeyEvent(KeyEvent event) { 2271 if (isDpadEvent(event)) { 2272 mSettings.setSpatialNavigationEnabled(true); 2273 } 2274 return mContentViewCore.dispatchKeyEvent(event); 2275 } 2276 2277 private boolean isDpadEvent(KeyEvent event) { 2278 if (event.getAction() == KeyEvent.ACTION_DOWN) { 2279 switch (event.getKeyCode()) { 2280 case KeyEvent.KEYCODE_DPAD_CENTER: 2281 case KeyEvent.KEYCODE_DPAD_DOWN: 2282 case KeyEvent.KEYCODE_DPAD_UP: 2283 case KeyEvent.KEYCODE_DPAD_LEFT: 2284 case KeyEvent.KEYCODE_DPAD_RIGHT: 2285 return true; 2286 } 2287 } 2288 return false; 2289 } 2290 2291 @Override 2292 public boolean onTouchEvent(MotionEvent event) { 2293 if (mNativeAwContents == 0) return false; 2294 2295 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { 2296 mSettings.setSpatialNavigationEnabled(false); 2297 } 2298 2299 mScrollOffsetManager.setProcessingTouchEvent(true); 2300 boolean rv = mContentViewCore.onTouchEvent(event); 2301 mScrollOffsetManager.setProcessingTouchEvent(false); 2302 2303 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { 2304 int actionIndex = event.getActionIndex(); 2305 2306 // Note this will trigger IPC back to browser even if nothing is 2307 // hit. 2308 nativeRequestNewHitTestDataAt(mNativeAwContents, 2309 (int) Math.round(event.getX(actionIndex) / mDIPScale), 2310 (int) Math.round(event.getY(actionIndex) / mDIPScale)); 2311 } 2312 2313 if (mOverScrollGlow != null) { 2314 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { 2315 mOverScrollGlow.setShouldPull(true); 2316 } else if (event.getActionMasked() == MotionEvent.ACTION_UP || 2317 event.getActionMasked() == MotionEvent.ACTION_CANCEL) { 2318 mOverScrollGlow.setShouldPull(false); 2319 mOverScrollGlow.releaseAll(); 2320 } 2321 } 2322 2323 return rv; 2324 } 2325 2326 @Override 2327 public boolean onHoverEvent(MotionEvent event) { 2328 return mContentViewCore.onHoverEvent(event); 2329 } 2330 2331 @Override 2332 public boolean onGenericMotionEvent(MotionEvent event) { 2333 return mContentViewCore.onGenericMotionEvent(event); 2334 } 2335 2336 @Override 2337 public void onConfigurationChanged(Configuration newConfig) { 2338 mContentViewCore.onConfigurationChanged(newConfig); 2339 } 2340 2341 @Override 2342 public void onAttachedToWindow() { 2343 if (mNativeAwContents == 0) return; 2344 if (mIsAttachedToWindow) { 2345 Log.w(TAG, "onAttachedToWindow called when already attached. Ignoring"); 2346 return; 2347 } 2348 mIsAttachedToWindow = true; 2349 2350 mContentViewCore.onAttachedToWindow(); 2351 nativeOnAttachedToWindow(mNativeAwContents, mContainerView.getWidth(), 2352 mContainerView.getHeight()); 2353 updateHardwareAcceleratedFeaturesToggle(); 2354 2355 if (mComponentCallbacks != null) return; 2356 mComponentCallbacks = new AwComponentCallbacks(); 2357 mContext.registerComponentCallbacks(mComponentCallbacks); 2358 } 2359 2360 @Override 2361 public void onDetachedFromWindow() { 2362 if (!mIsAttachedToWindow) { 2363 Log.w(TAG, "onDetachedFromWindow called when already detached. Ignoring"); 2364 return; 2365 } 2366 mIsAttachedToWindow = false; 2367 hideAutofillPopup(); 2368 if (mNativeAwContents != 0) { 2369 nativeOnDetachedFromWindow(mNativeAwContents); 2370 } 2371 2372 mContentViewCore.onDetachedFromWindow(); 2373 updateHardwareAcceleratedFeaturesToggle(); 2374 2375 if (mComponentCallbacks != null) { 2376 mContext.unregisterComponentCallbacks(mComponentCallbacks); 2377 mComponentCallbacks = null; 2378 } 2379 2380 mScrollAccessibilityHelper.removePostedCallbacks(); 2381 mNativeGLDelegate.detachGLFunctor(); 2382 } 2383 2384 @Override 2385 public void onWindowFocusChanged(boolean hasWindowFocus) { 2386 mWindowFocused = hasWindowFocus; 2387 mContentViewCore.onWindowFocusChanged(hasWindowFocus); 2388 } 2389 2390 @Override 2391 public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { 2392 mContainerViewFocused = focused; 2393 mContentViewCore.onFocusChanged(focused); 2394 } 2395 2396 @Override 2397 public void onSizeChanged(int w, int h, int ow, int oh) { 2398 if (mNativeAwContents == 0) return; 2399 mScrollOffsetManager.setContainerViewSize(w, h); 2400 // The AwLayoutSizer needs to go first so that if we're in 2401 // fixedLayoutSize mode the update 2402 // to enter fixedLayoutSize mode is sent before the first resize 2403 // update. 2404 mLayoutSizer.onSizeChanged(w, h, ow, oh); 2405 mContentViewCore.onPhysicalBackingSizeChanged(w, h); 2406 mContentViewCore.onSizeChanged(w, h, ow, oh); 2407 nativeOnSizeChanged(mNativeAwContents, w, h, ow, oh); 2408 } 2409 2410 @Override 2411 public void onVisibilityChanged(View changedView, int visibility) { 2412 boolean viewVisible = mContainerView.getVisibility() == View.VISIBLE; 2413 if (mIsViewVisible == viewVisible) return; 2414 setViewVisibilityInternal(viewVisible); 2415 } 2416 2417 @Override 2418 public void onWindowVisibilityChanged(int visibility) { 2419 boolean windowVisible = visibility == View.VISIBLE; 2420 if (mIsWindowVisible == windowVisible) return; 2421 setWindowVisibilityInternal(windowVisible); 2422 } 2423 } 2424 2425 // Return true if the GeolocationPermissionAPI should be used. 2426 @CalledByNative 2427 private boolean useLegacyGeolocationPermissionAPI() { 2428 // Always return true since we are not ready to swap the geolocation yet. 2429 // TODO: If we decide not to migrate the geolocation, there are some unreachable 2430 // code need to remove. http://crbug.com/396184. 2431 return true; 2432 } 2433 2434 //-------------------------------------------------------------------------------------------- 2435 // Native methods 2436 //-------------------------------------------------------------------------------------------- 2437 2438 private static native long nativeInit(AwBrowserContext browserContext); 2439 private static native void nativeDestroy(long nativeAwContents); 2440 private static native void nativeSetAwDrawSWFunctionTable(long functionTablePointer); 2441 private static native void nativeSetAwDrawGLFunctionTable(long functionTablePointer); 2442 private static native long nativeGetAwDrawGLFunction(); 2443 private static native int nativeGetNativeInstanceCount(); 2444 private static native void nativeSetShouldDownloadFavicons(); 2445 2446 private native void nativeSetJavaPeers(long nativeAwContents, AwContents awContents, 2447 AwWebContentsDelegate webViewWebContentsDelegate, 2448 AwContentsClientBridge contentsClientBridge, 2449 AwContentsIoThreadClient ioThreadClient, 2450 InterceptNavigationDelegate navigationInterceptionDelegate); 2451 private native long nativeGetWebContents(long nativeAwContents); 2452 2453 private native void nativeDocumentHasImages(long nativeAwContents, Message message); 2454 private native void nativeGenerateMHTML( 2455 long nativeAwContents, String path, ValueCallback<String> callback); 2456 2457 private native void nativeAddVisitedLinks(long nativeAwContents, String[] visitedLinks); 2458 private native boolean nativeOnDraw(long nativeAwContents, Canvas canvas, 2459 boolean isHardwareAccelerated, int scrollX, int scrollY, 2460 int visibleLeft, int visibleTop, int visibleRight, int visibleBottom); 2461 private native void nativeFindAllAsync(long nativeAwContents, String searchString); 2462 private native void nativeFindNext(long nativeAwContents, boolean forward); 2463 private native void nativeClearMatches(long nativeAwContents); 2464 private native void nativeClearCache(long nativeAwContents, boolean includeDiskFiles); 2465 private native byte[] nativeGetCertificate(long nativeAwContents); 2466 2467 // Coordinates in desity independent pixels. 2468 private native void nativeRequestNewHitTestDataAt(long nativeAwContents, int x, int y); 2469 private native void nativeUpdateLastHitTestData(long nativeAwContents); 2470 2471 private native void nativeOnSizeChanged(long nativeAwContents, int w, int h, int ow, int oh); 2472 private native void nativeScrollTo(long nativeAwContents, int x, int y); 2473 private native void nativeSetViewVisibility(long nativeAwContents, boolean visible); 2474 private native void nativeSetWindowVisibility(long nativeAwContents, boolean visible); 2475 private native void nativeSetIsPaused(long nativeAwContents, boolean paused); 2476 private native void nativeOnAttachedToWindow(long nativeAwContents, int w, int h); 2477 private static native void nativeOnDetachedFromWindow(long nativeAwContents); 2478 private native void nativeSetDipScale(long nativeAwContents, float dipScale); 2479 2480 // Returns null if save state fails. 2481 private native byte[] nativeGetOpaqueState(long nativeAwContents); 2482 2483 // Returns false if restore state fails. 2484 private native boolean nativeRestoreFromOpaqueState(long nativeAwContents, byte[] state); 2485 2486 private native long nativeReleasePopupAwContents(long nativeAwContents); 2487 private native void nativeFocusFirstNode(long nativeAwContents); 2488 private native void nativeSetBackgroundColor(long nativeAwContents, int color); 2489 2490 private native long nativeGetAwDrawGLViewContext(long nativeAwContents); 2491 private native long nativeCapturePicture(long nativeAwContents, int width, int height); 2492 private native void nativeEnableOnNewPicture(long nativeAwContents, boolean enabled); 2493 private native void nativeClearView(long nativeAwContents); 2494 private native void nativeSetExtraHeadersForUrl(long nativeAwContents, 2495 String url, String extraHeaders); 2496 private native void nativeSendCheckRenderThreadResponsiveness(long nativeAwContents); 2497 2498 private native void nativeInvokeGeolocationCallback( 2499 long nativeAwContents, boolean value, String requestingFrame); 2500 2501 private native void nativeSetJsOnlineProperty(long nativeAwContents, boolean networkUp); 2502 2503 private native void nativeTrimMemory(long nativeAwContents, int level, boolean visible); 2504 2505 private native void nativeCreatePdfExporter(long nativeAwContents, AwPdfExporter awPdfExporter); 2506 2507 private native void nativePreauthorizePermission(long nativeAwContents, String origin, 2508 long resources); 2509} 2510