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