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.
5 package org.chromium.android_webview;
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.view.KeyEvent;
27 import android.view.MotionEvent;
28 import android.view.View;
29 import android.view.ViewGroup;
30 import android.view.accessibility.AccessibilityEvent;
31 import android.view.accessibility.AccessibilityNodeInfo;
32 import android.view.accessibility.AccessibilityNodeProvider;
33 import android.view.inputmethod.EditorInfo;
34 import android.view.inputmethod.InputConnection;
35 import android.webkit.GeolocationPermissions;
36 import android.webkit.ValueCallback;
37 import android.widget.OverScroller;
39 import com.google.common.annotations.VisibleForTesting;
41 import org.chromium.android_webview.permission.AwPermissionRequest;
42 import org.chromium.base.CalledByNative;
43 import org.chromium.base.JNINamespace;
44 import org.chromium.base.ThreadUtils;
45 import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
46 import org.chromium.components.navigation_interception.NavigationParams;
47 import org.chromium.content.browser.ContentSettings;
48 import org.chromium.content.browser.ContentViewClient;
49 import org.chromium.content.browser.ContentViewCore;
50 import org.chromium.content.browser.ContentViewStatics;
51 import org.chromium.content.browser.LoadUrlParams;
52 import org.chromium.content.browser.NavigationHistory;
53 import org.chromium.content.browser.PageTransitionTypes;
54 import org.chromium.content.common.CleanupReference;
55 import org.chromium.content_public.Referrer;
56 import org.chromium.content_public.browser.GestureStateListener;
57 import org.chromium.ui.base.ActivityWindowAndroid;
58 import org.chromium.ui.base.WindowAndroid;
59 import org.chromium.ui.gfx.DeviceDisplayInfo;
62 import java.lang.annotation.Annotation;
63 import java.net.MalformedURLException;
65 import java.util.HashMap;
66 import java.util.Locale;
68 import java.util.concurrent.Callable;
71 * Exposes the native AwContents class, and together these classes wrap the ContentViewCore
72 * and Browser components that are required to implement Android WebView API. This is the
73 * primary entry point for the WebViewProvider implementation; it holds a 1:1 object
74 * relationship with application WebView instances.
75 * (We define this class independent of the hidden WebViewProvider interfaces, to allow
76 * continuous build & test in the open source SDK-based tree).
78 @JNINamespace("android_webview")
79 public class AwContents {
80 private static final String TAG = "AwContents";
82 private static final String WEB_ARCHIVE_EXTENSION = ".mht";
84 // Used to avoid enabling zooming in / out if resulting zooming will
85 // produce little visible difference.
86 private static final float ZOOM_CONTROLS_EPSILON = 0.007f;
89 * WebKit hit test related data strcutre. These are used to implement
90 * getHitTestResult, requestFocusNodeHref, requestImageRef methods in WebView.
91 * All values should be updated together. The native counterpart is
94 public static class HitTestData {
95 // Used in getHitTestResult.
96 public int hitTestResultType;
97 public String hitTestResultExtraData;
99 // Used in requestFocusNodeHref (all three) and requestImageRef (only imgSrc).
101 public String anchorText;
102 public String imgSrc;
106 * Interface that consumers of {@link AwContents} must implement to allow the proper
107 * dispatching of view methods through the containing view.
109 public interface InternalAccessDelegate extends ContentViewCore.InternalAccessDelegate {
112 * @see View#overScrollBy(int, int, int, int, int, int, int, int, boolean);
114 void overScrollBy(int deltaX, int deltaY,
115 int scrollX, int scrollY,
116 int scrollRangeX, int scrollRangeY,
117 int maxOverScrollX, int maxOverScrollY,
118 boolean isTouchEvent);
121 * @see View#scrollTo(int, int)
123 void super_scrollTo(int scrollX, int scrollY);
126 * @see View#setMeasuredDimension(int, int)
128 void setMeasuredDimension(int measuredWidth, int measuredHeight);
131 * @see View#getScrollBarStyle()
133 int super_getScrollBarStyle();
137 * Interface that consumers of {@link AwContents} must implement to support
138 * native GL rendering.
140 public interface NativeGLDelegate {
142 * Requests a callback on the native DrawGL method (see getAwDrawGLFunction)
143 * if called from within onDraw, |canvas| will be non-null and hardware accelerated.
144 * Otherwise, |canvas| will be null, and the container view itself will be hardware
145 * accelerated. If |waitForCompletion| is true, this method will not return until
146 * functor has returned.
147 * Should avoid setting |waitForCompletion| when |canvas| is not null.
148 * |containerView| is the view where the AwContents should be drawn.
150 * @return false indicates the GL draw request was not accepted, and the caller
151 * should fallback to the SW path.
153 boolean requestDrawGL(Canvas canvas, boolean waitForCompletion, View containerView);
156 * Detaches the GLFunctor from the view tree.
158 void detachGLFunctor();
162 * Class to facilitate dependency injection. Subclasses by test code to provide mock versions of
163 * certain AwContents dependencies.
165 public static class DependencyFactory {
166 public AwLayoutSizer createLayoutSizer() {
167 return new AwLayoutSizer();
170 public AwScrollOffsetManager createScrollOffsetManager(
171 AwScrollOffsetManager.Delegate delegate, OverScroller overScroller) {
172 return new AwScrollOffsetManager(delegate, overScroller);
176 private long mNativeAwContents;
177 private final AwBrowserContext mBrowserContext;
178 private ViewGroup mContainerView;
179 private final AwLayoutChangeListener mLayoutChangeListener;
180 private final Context mContext;
181 private ContentViewCore mContentViewCore;
182 private final AwContentsClient mContentsClient;
183 private final AwContentViewClient mContentViewClient;
184 private final AwContentsClientBridge mContentsClientBridge;
185 private final AwWebContentsDelegateAdapter mWebContentsDelegate;
186 private final AwContentsIoThreadClient mIoThreadClient;
187 private final InterceptNavigationDelegateImpl mInterceptNavigationDelegate;
188 private InternalAccessDelegate mInternalAccessAdapter;
189 private final NativeGLDelegate mNativeGLDelegate;
190 private final AwLayoutSizer mLayoutSizer;
191 private final AwZoomControls mZoomControls;
192 private final AwScrollOffsetManager mScrollOffsetManager;
193 private OverScrollGlow mOverScrollGlow;
194 // This can be accessed on any thread after construction. See AwContentsIoThreadClient.
195 private final AwSettings mSettings;
196 private final ScrollAccessibilityHelper mScrollAccessibilityHelper;
198 private boolean mIsPaused;
199 private boolean mIsViewVisible;
200 private boolean mIsWindowVisible;
201 private boolean mIsAttachedToWindow;
202 private Bitmap mFavicon;
203 private boolean mHasRequestedVisitedHistoryFromClient;
204 // TODO(boliu): This should be in a global context, not per webview.
205 private final double mDIPScale;
207 // The base background color, i.e. not accounting for any CSS body from the current page.
208 private int mBaseBackgroundColor = Color.WHITE;
210 // Must call nativeUpdateLastHitTestData first to update this before use.
211 private final HitTestData mPossiblyStaleHitTestData = new HitTestData();
213 private final DefaultVideoPosterRequestHandler mDefaultVideoPosterRequestHandler;
215 // Bound method for suppling Picture instances to the AwContentsClient. Will be null if the
216 // picture listener API has not yet been enabled, or if it is using invalidation-only mode.
217 private Callable<Picture> mPictureListenerContentProvider;
219 private boolean mContainerViewFocused;
220 private boolean mWindowFocused;
222 // These come from the compositor and are updated synchronously (in contrast to the values in
223 // ContentViewCore, which are updated at end of every frame).
224 private float mPageScaleFactor = 1.0f;
225 private float mMinPageScaleFactor = 1.0f;
226 private float mMaxPageScaleFactor = 1.0f;
227 private float mContentWidthDip;
228 private float mContentHeightDip;
230 private AwAutofillClient mAwAutofillClient;
232 private AwPdfExporter mAwPdfExporter;
234 private AwViewMethods mAwViewMethods;
235 private final FullScreenTransitionsState mFullScreenTransitionsState;
237 // This flag indicates that ShouldOverrideUrlNavigation should be posted
238 // through the resourcethrottle. This is only used for popup windows.
239 private boolean mDeferredShouldOverrideUrlLoadingIsPendingForPopup;
241 // The framework may temporarily detach our container view, for example during layout if
242 // we are a child of a ListView. This may cause many toggles of View focus, which we suppress
243 // when in this state.
244 private boolean mTemporarilyDetached;
246 private static final class DestroyRunnable implements Runnable {
247 private final long mNativeAwContents;
248 private DestroyRunnable(long nativeAwContents) {
249 mNativeAwContents = nativeAwContents;
253 nativeDestroy(mNativeAwContents);
258 * A class that stores the state needed to enter and exit fullscreen.
260 private static class FullScreenTransitionsState {
261 private final ViewGroup mInitialContainerView;
262 private final InternalAccessDelegate mInitialInternalAccessAdapter;
263 private final AwViewMethods mInitialAwViewMethods;
264 private FullScreenView mFullScreenView;
266 private FullScreenTransitionsState(ViewGroup initialContainerView,
267 InternalAccessDelegate initialInternalAccessAdapter,
268 AwViewMethods initialAwViewMethods) {
269 mInitialContainerView = initialContainerView;
270 mInitialInternalAccessAdapter = initialInternalAccessAdapter;
271 mInitialAwViewMethods = initialAwViewMethods;
274 private void enterFullScreen(FullScreenView fullScreenView) {
275 mFullScreenView = fullScreenView;
278 private void exitFullScreen() {
279 mFullScreenView = null;
282 private boolean isFullScreen() {
283 return mFullScreenView != null;
286 private ViewGroup getInitialContainerView() {
287 return mInitialContainerView;
290 private InternalAccessDelegate getInitialInternalAccessDelegate() {
291 return mInitialInternalAccessAdapter;
294 private AwViewMethods getInitialAwViewMethods() {
295 return mInitialAwViewMethods;
298 private FullScreenView getFullScreenView() {
299 return mFullScreenView;
303 // Reference to the active mNativeAwContents pointer while it is active use
304 // (ie before it is destroyed).
305 private CleanupReference mCleanupReference;
307 //--------------------------------------------------------------------------------------------
308 private class IoThreadClientImpl extends AwContentsIoThreadClient {
309 // All methods are called on the IO thread.
312 public int getCacheMode() {
313 return mSettings.getCacheMode();
317 public AwWebResourceResponse shouldInterceptRequest(
318 AwContentsClient.ShouldInterceptRequestParams params) {
319 String url = params.url;
320 AwWebResourceResponse awWebResourceResponse;
321 // Return the response directly if the url is default video poster url.
322 awWebResourceResponse = mDefaultVideoPosterRequestHandler.shouldInterceptRequest(url);
323 if (awWebResourceResponse != null) return awWebResourceResponse;
325 awWebResourceResponse = mContentsClient.shouldInterceptRequest(params);
327 if (awWebResourceResponse == null) {
328 mContentsClient.getCallbackHelper().postOnLoadResource(url);
331 if (params.isMainFrame && awWebResourceResponse != null &&
332 awWebResourceResponse.getData() == null) {
333 // In this case the intercepted URLRequest job will simulate an empty response
334 // which doesn't trigger the onReceivedError callback. For WebViewClassic
335 // compatibility we synthesize that callback. http://crbug.com/180950
336 mContentsClient.getCallbackHelper().postOnReceivedError(
337 ErrorCodeConversionHelper.ERROR_UNKNOWN,
338 null /* filled in by the glue layer */, url);
340 return awWebResourceResponse;
344 public boolean shouldBlockContentUrls() {
345 return !mSettings.getAllowContentAccess();
349 public boolean shouldBlockFileUrls() {
350 return !mSettings.getAllowFileAccess();
354 public boolean shouldBlockNetworkLoads() {
355 return mSettings.getBlockNetworkLoads();
359 public boolean shouldAcceptThirdPartyCookies() {
360 return mSettings.getAcceptThirdPartyCookies();
364 public void onDownloadStart(String url, String userAgent,
365 String contentDisposition, String mimeType, long contentLength) {
366 mContentsClient.getCallbackHelper().postOnDownloadStart(url, userAgent,
367 contentDisposition, mimeType, contentLength);
371 public void newLoginRequest(String realm, String account, String args) {
372 mContentsClient.getCallbackHelper().postOnReceivedLoginRequest(realm, account, args);
376 //--------------------------------------------------------------------------------------------
377 // When the navigation is for a newly created WebView (i.e. a popup), intercept the navigation
378 // here for implementing shouldOverrideUrlLoading. This is to send the shouldOverrideUrlLoading
379 // callback to the correct WebViewClient that is associated with the WebView.
380 // Otherwise, use this delegate only to post onPageStarted messages.
382 // We are not using WebContentsObserver.didStartLoading because of stale URLs, out of order
383 // onPageStarted's and double onPageStarted's.
385 private class InterceptNavigationDelegateImpl implements InterceptNavigationDelegate {
387 public boolean shouldIgnoreNavigation(NavigationParams navigationParams) {
388 final String url = navigationParams.url;
389 boolean ignoreNavigation = false;
390 if (mDeferredShouldOverrideUrlLoadingIsPendingForPopup) {
391 mDeferredShouldOverrideUrlLoadingIsPendingForPopup = false;
392 // If this is used for all navigations in future, cases for application initiated
393 // load, redirect and backforward should also be filtered out.
394 if (!navigationParams.isPost) {
395 ignoreNavigation = mContentsClient.shouldOverrideUrlLoading(url);
398 // The shouldOverrideUrlLoading call might have resulted in posting messages to the
399 // UI thread. Using sendMessage here (instead of calling onPageStarted directly)
400 // will allow those to run in order.
401 if (!ignoreNavigation) {
402 mContentsClient.getCallbackHelper().postOnPageStarted(url);
404 return ignoreNavigation;
408 //--------------------------------------------------------------------------------------------
409 private class AwLayoutSizerDelegate implements AwLayoutSizer.Delegate {
411 public void requestLayout() {
412 mContainerView.requestLayout();
416 public void setMeasuredDimension(int measuredWidth, int measuredHeight) {
417 mInternalAccessAdapter.setMeasuredDimension(measuredWidth, measuredHeight);
421 public void setFixedLayoutSize(int widthDip, int heightDip) {
422 if (mNativeAwContents == 0) return;
423 nativeSetFixedLayoutSize(mNativeAwContents, widthDip, heightDip);
427 public boolean isLayoutParamsHeightWrapContent() {
428 return mContainerView.getLayoutParams() != null &&
429 mContainerView.getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT;
433 //--------------------------------------------------------------------------------------------
434 private class AwScrollOffsetManagerDelegate implements AwScrollOffsetManager.Delegate {
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);
443 public void scrollContainerViewTo(int x, int y) {
444 mInternalAccessAdapter.super_scrollTo(x, y);
448 public void scrollNativeTo(int x, int y) {
449 if (mNativeAwContents == 0) return;
450 nativeScrollTo(mNativeAwContents, x, y);
454 public int getContainerViewScrollX() {
455 return mContainerView.getScrollX();
459 public int getContainerViewScrollY() {
460 return mContainerView.getScrollY();
464 public void invalidate() {
465 mContainerView.invalidate();
469 //--------------------------------------------------------------------------------------------
470 private class AwGestureStateListener extends GestureStateListener {
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();
483 public void onPinchEnded() {
484 mLayoutSizer.unfreezeLayoutRequests();
488 public void onFlingCancelGesture() {
489 mScrollOffsetManager.onFlingCancelGesture();
493 public void onUnhandledFlingStartEvent(int velocityX, int velocityY) {
494 mScrollOffsetManager.onUnhandledFlingStartEvent(velocityX, velocityY);
498 public void onScrollUpdateGestureConsumed() {
499 mScrollAccessibilityHelper.postViewScrolledAccessibilityEventCallback();
503 //--------------------------------------------------------------------------------------------
504 private class AwComponentCallbacks implements ComponentCallbacks2 {
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);
514 public void onLowMemory() {}
517 public void onConfigurationChanged(Configuration configuration) {}
520 //--------------------------------------------------------------------------------------------
521 private class AwLayoutChangeListener implements View.OnLayoutChangeListener {
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();
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.
539 * This constructor uses the default view sizing policy.
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());
549 * @param dependencyFactory an instance of the DependencyFactory used to provide instances of
550 * classes that this class depends on.
552 * This version of the constructor is used in test code to inject test versions of the above
553 * documented classes.
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;
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(contentsClient, mContainerView);
575 mContentsClientBridge = new AwContentsClientBridge(contentsClient,
576 mBrowserContext.getKeyStore(), AwContentsStatics.getClientCertLookupTable());
577 mZoomControls = new AwZoomControls(this);
578 mIoThreadClient = new IoThreadClientImpl();
579 mInterceptNavigationDelegate = new InterceptNavigationDelegateImpl();
581 AwSettings.ZoomSupportChangeListener zoomListener =
582 new AwSettings.ZoomSupportChangeListener() {
584 public void onGestureZoomSupportChanged(
585 boolean supportsDoubleTapZoom, boolean supportsMultiTouchZoom) {
586 mContentViewCore.updateDoubleTapSupport(supportsDoubleTapZoom);
587 mContentViewCore.updateMultiTouchZoomSupport(supportsMultiTouchZoom);
591 mSettings.setZoomListener(zoomListener);
592 mDefaultVideoPosterRequestHandler = new DefaultVideoPosterRequestHandler(mContentsClient);
593 mSettings.setDefaultVideoPosterURL(
594 mDefaultVideoPosterRequestHandler.getDefaultVideoPosterURL());
595 mSettings.setDIPScale(mDIPScale);
596 mScrollOffsetManager = dependencyFactory.createScrollOffsetManager(
597 new AwScrollOffsetManagerDelegate(), new OverScroller(mContext));
598 mScrollAccessibilityHelper = new ScrollAccessibilityHelper(mContainerView);
600 setOverScrollMode(mContainerView.getOverScrollMode());
601 setScrollBarStyle(mInternalAccessAdapter.super_getScrollBarStyle());
602 mLayoutChangeListener = new AwLayoutChangeListener();
603 mContainerView.addOnLayoutChangeListener(mLayoutChangeListener);
605 setNewAwContents(nativeInit(mBrowserContext));
607 onContainerViewChanged();
610 private static ContentViewCore createAndInitializeContentViewCore(ViewGroup containerView,
611 Context context, InternalAccessDelegate internalDispatcher, long nativeWebContents,
612 GestureStateListener gestureStateListener,
613 ContentViewClient contentViewClient,
614 ContentViewCore.ZoomControlsDelegate zoomControlsDelegate) {
615 ContentViewCore contentViewCore = new ContentViewCore(context);
616 contentViewCore.initialize(containerView, internalDispatcher, nativeWebContents,
617 context instanceof Activity ?
618 new ActivityWindowAndroid((Activity) context) :
619 new WindowAndroid(context.getApplicationContext()));
620 contentViewCore.addGestureStateListener(gestureStateListener);
621 contentViewCore.setContentViewClient(contentViewClient);
622 contentViewCore.setZoomControlsDelegate(zoomControlsDelegate);
623 return contentViewCore;
626 boolean isFullScreen() {
627 return mFullScreenTransitionsState.isFullScreen();
631 * Transitions this {@link AwContents} to fullscreen mode and returns the
632 * {@link View} where the contents will be drawn while in fullscreen.
634 View enterFullScreen() {
635 assert !isFullScreen();
637 // Detach to tear down the GL functor if this is still associated with the old
638 // container view. It will be recreated during the next call to onDraw attached to
639 // the new container view.
640 onDetachedFromWindow();
642 // In fullscreen mode FullScreenView owns the AwViewMethodsImpl and AwContents
643 // a NullAwViewMethods.
644 FullScreenView fullScreenView = new FullScreenView(mContext, mAwViewMethods);
645 mFullScreenTransitionsState.enterFullScreen(fullScreenView);
646 mAwViewMethods = new NullAwViewMethods(this, mInternalAccessAdapter, mContainerView);
647 mContainerView.removeOnLayoutChangeListener(mLayoutChangeListener);
648 fullScreenView.addOnLayoutChangeListener(mLayoutChangeListener);
650 // Associate this AwContents with the FullScreenView.
651 setInternalAccessAdapter(fullScreenView.getInternalAccessAdapter());
652 setContainerView(fullScreenView);
654 return fullScreenView;
658 * Returns this {@link AwContents} to embedded mode, where the {@link AwContents} are drawn
661 void exitFullScreen() {
662 assert isFullScreen();
664 // Detach to tear down the GL functor if this is still associated with the old
665 // container view. It will be recreated during the next call to onDraw attached to
666 // the new container view.
667 // NOTE: we cannot use mAwViewMethods here because its type is NullAwViewMethods.
668 AwViewMethods awViewMethodsImpl = mFullScreenTransitionsState.getInitialAwViewMethods();
669 awViewMethodsImpl.onDetachedFromWindow();
671 // Swap the view delegates. In embedded mode the FullScreenView owns a
672 // NullAwViewMethods and AwContents the AwViewMethodsImpl.
673 FullScreenView fullscreenView = mFullScreenTransitionsState.getFullScreenView();
674 fullscreenView.setAwViewMethods(new NullAwViewMethods(
675 this, fullscreenView.getInternalAccessAdapter(), fullscreenView));
676 mAwViewMethods = awViewMethodsImpl;
677 ViewGroup initialContainerView = mFullScreenTransitionsState.getInitialContainerView();
678 initialContainerView.addOnLayoutChangeListener(mLayoutChangeListener);
679 fullscreenView.removeOnLayoutChangeListener(mLayoutChangeListener);
681 // Re-associate this AwContents with the WebView.
682 setInternalAccessAdapter(mFullScreenTransitionsState.getInitialInternalAccessDelegate());
683 setContainerView(initialContainerView);
685 mFullScreenTransitionsState.exitFullScreen();
688 private void setInternalAccessAdapter(InternalAccessDelegate internalAccessAdapter) {
689 mInternalAccessAdapter = internalAccessAdapter;
690 mContentViewCore.setContainerViewInternals(mInternalAccessAdapter);
693 private void setContainerView(ViewGroup newContainerView) {
694 mContainerView = newContainerView;
695 mContentViewCore.setContainerView(mContainerView);
696 if (mAwPdfExporter != null) {
697 mAwPdfExporter.setContainerView(mContainerView);
699 mWebContentsDelegate.setContainerView(mContainerView);
701 onContainerViewChanged();
705 * Reconciles the state of this AwContents object with the state of the new container view.
707 private void onContainerViewChanged() {
708 // NOTE: mAwViewMethods is used by the old container view, the WebView, so it might refer
709 // to a NullAwViewMethods when in fullscreen. To ensure that the state is reconciled with
710 // the new container view correctly, we bypass mAwViewMethods and use the real
711 // implementation directly.
712 AwViewMethods awViewMethodsImpl = mFullScreenTransitionsState.getInitialAwViewMethods();
713 awViewMethodsImpl.onVisibilityChanged(mContainerView, mContainerView.getVisibility());
714 awViewMethodsImpl.onWindowVisibilityChanged(mContainerView.getWindowVisibility());
715 if (mContainerView.isAttachedToWindow()) {
716 awViewMethodsImpl.onAttachedToWindow();
718 awViewMethodsImpl.onDetachedFromWindow();
720 awViewMethodsImpl.onSizeChanged(
721 mContainerView.getWidth(), mContainerView.getHeight(), 0, 0);
722 awViewMethodsImpl.onWindowFocusChanged(mContainerView.hasWindowFocus());
723 awViewMethodsImpl.onFocusChanged(mContainerView.hasFocus(), 0, null);
724 mContainerView.requestLayout();
727 /* Common initialization routine for adopting a native AwContents instance into this
730 * TAKE CARE! This method can get called multiple times per java instance. Code accordingly.
731 * ^^^^^^^^^ See the native class declaration for more details on relative object lifetimes.
733 private void setNewAwContents(long newAwContentsPtr) {
734 if (mNativeAwContents != 0) {
736 mContentViewCore = null;
739 assert mNativeAwContents == 0 && mCleanupReference == null && mContentViewCore == null;
741 mNativeAwContents = newAwContentsPtr;
742 // TODO(joth): when the native and java counterparts of AwBrowserContext are hooked up to
743 // each other, we should update |mBrowserContext| according to the newly received native
744 // WebContent's browser context.
746 // The native side object has been bound to this java instance, so now is the time to
747 // bind all the native->java relationships.
748 mCleanupReference = new CleanupReference(this, new DestroyRunnable(mNativeAwContents));
750 long nativeWebContents = nativeGetWebContents(mNativeAwContents);
751 mContentViewCore = createAndInitializeContentViewCore(
752 mContainerView, mContext, mInternalAccessAdapter, nativeWebContents,
753 new AwGestureStateListener(), mContentViewClient, mZoomControls);
754 nativeSetJavaPeers(mNativeAwContents, this, mWebContentsDelegate, mContentsClientBridge,
755 mIoThreadClient, mInterceptNavigationDelegate);
756 mContentsClient.installWebContentsObserver(mContentViewCore);
757 mSettings.setWebContents(nativeWebContents);
758 nativeSetDipScale(mNativeAwContents, (float) mDIPScale);
760 // The only call to onShow. onHide should never be called.
761 mContentViewCore.onShow();
765 * Called on the "source" AwContents that is opening the popup window to
766 * provide the AwContents to host the pop up content.
768 public void supplyContentsForPopup(AwContents newContents) {
769 long popupNativeAwContents = nativeReleasePopupAwContents(mNativeAwContents);
770 if (popupNativeAwContents == 0) {
771 Log.w(TAG, "Popup WebView bind failed: no pending content.");
772 if (newContents != null) newContents.destroy();
775 if (newContents == null) {
776 nativeDestroy(popupNativeAwContents);
780 newContents.receivePopupContents(popupNativeAwContents);
783 // Recap: supplyContentsForPopup() is called on the parent window's content, this method is
784 // called on the popup window's content.
785 private void receivePopupContents(long popupNativeAwContents) {
786 mDeferredShouldOverrideUrlLoadingIsPendingForPopup = true;
787 // Save existing view state.
788 final boolean wasAttached = mIsAttachedToWindow;
789 final boolean wasViewVisible = mIsViewVisible;
790 final boolean wasWindowVisible = mIsWindowVisible;
791 final boolean wasPaused = mIsPaused;
792 final boolean wasFocused = mContainerViewFocused;
793 final boolean wasWindowFocused = mWindowFocused;
795 // Properly clean up existing mContentViewCore and mNativeAwContents.
796 if (wasFocused) onFocusChanged(false, 0, null);
797 if (wasWindowFocused) onWindowFocusChanged(false);
798 if (wasViewVisible) setViewVisibilityInternal(false);
799 if (wasWindowVisible) setWindowVisibilityInternal(false);
800 if (wasAttached) onDetachedFromWindow();
801 if (!wasPaused) onPause();
803 setNewAwContents(popupNativeAwContents);
805 // Finally refresh all view state for mContentViewCore and mNativeAwContents.
806 if (!wasPaused) onResume();
808 onAttachedToWindow();
809 postInvalidateOnAnimation();
811 onSizeChanged(mContainerView.getWidth(), mContainerView.getHeight(), 0, 0);
812 if (wasWindowVisible) setWindowVisibilityInternal(true);
813 if (wasViewVisible) setViewVisibilityInternal(true);
814 if (wasWindowFocused) onWindowFocusChanged(wasWindowFocused);
815 if (wasFocused) onFocusChanged(true, 0, null);
819 * Deletes the native counterpart of this object.
821 public void destroy() {
822 if (mCleanupReference != null) {
823 assert mNativeAwContents != 0;
824 // If we are attached, we have to call native detach to clean up
825 // hardware resources.
826 if (mIsAttachedToWindow) {
827 nativeOnDetachedFromWindow(mNativeAwContents);
830 // We explicitly do not null out the mContentViewCore reference here
831 // because ContentViewCore already has code to deal with the case
832 // methods are called on it after it's been destroyed, and other
833 // code relies on AwContents.mContentViewCore to be non-null.
834 mContentViewCore.destroy();
835 mNativeAwContents = 0;
837 mCleanupReference.cleanupNow();
838 mCleanupReference = null;
841 assert !mContentViewCore.isAlive();
842 assert mNativeAwContents == 0;
846 public ContentViewCore getContentViewCore() {
847 return mContentViewCore;
850 // Can be called from any thread.
851 public AwSettings getSettings() {
855 public AwPdfExporter getPdfExporter() {
856 // mNativeAwContents can be null, due to destroy().
857 if (mNativeAwContents == 0) {
860 if (mAwPdfExporter == null) {
861 mAwPdfExporter = new AwPdfExporter(mContainerView);
862 nativeCreatePdfExporter(mNativeAwContents, mAwPdfExporter);
864 return mAwPdfExporter;
867 public static void setAwDrawSWFunctionTable(long functionTablePointer) {
868 nativeSetAwDrawSWFunctionTable(functionTablePointer);
871 public static void setAwDrawGLFunctionTable(long functionTablePointer) {
872 nativeSetAwDrawGLFunctionTable(functionTablePointer);
875 public static long getAwDrawGLFunction() {
876 return nativeGetAwDrawGLFunction();
879 public static void setShouldDownloadFavicons() {
880 nativeSetShouldDownloadFavicons();
884 * Disables contents of JS-to-Java bridge objects to be inspectable using
885 * Object.keys() method and "for .. in" loops. This is intended for applications
886 * targeting earlier Android releases where this was not possible, and we want
887 * to ensure backwards compatible behavior.
889 public void disableJavascriptInterfacesInspection() {
890 mContentViewCore.setAllowJavascriptInterfacesInspection(false);
894 * Intended for test code.
895 * @return the number of native instances of this class.
898 public static int getNativeInstanceCount() {
899 return nativeGetNativeInstanceCount();
902 public long getAwDrawGLViewContext() {
903 // Only called during early construction, so client should not have had a chance to
905 assert mNativeAwContents != 0;
907 // Using the native pointer as the returned viewContext. This is matched by the
908 // reinterpret_cast back to BrowserViewRenderer pointer in the native DrawGLFunction.
909 return nativeGetAwDrawGLViewContext(mNativeAwContents);
912 // This is only to avoid heap allocations inside getGlobalVisibleRect. It should treated
913 // as a local variable in the function and not used anywhere else.
914 private static final Rect sLocalGlobalVisibleRect = new Rect();
916 private Rect getGlobalVisibleRect() {
917 if (!mContainerView.getGlobalVisibleRect(sLocalGlobalVisibleRect)) {
918 sLocalGlobalVisibleRect.setEmpty();
920 return sLocalGlobalVisibleRect;
923 //--------------------------------------------------------------------------------------------
924 // WebView[Provider] method implementations (where not provided by ContentViewCore)
925 //--------------------------------------------------------------------------------------------
927 public void onDraw(Canvas canvas) {
928 mAwViewMethods.onDraw(canvas);
931 public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
932 mAwViewMethods.onMeasure(widthMeasureSpec, heightMeasureSpec);
935 public int getContentHeightCss() {
936 return (int) Math.ceil(mContentHeightDip);
939 public int getContentWidthCss() {
940 return (int) Math.ceil(mContentWidthDip);
943 public Picture capturePicture() {
944 if (mNativeAwContents == 0) return null;
945 return new AwPicture(nativeCapturePicture(mNativeAwContents,
946 mScrollOffsetManager.computeHorizontalScrollRange(),
947 mScrollOffsetManager.computeVerticalScrollRange()));
950 public void clearView() {
951 if (mNativeAwContents == 0) return;
952 nativeClearView(mNativeAwContents);
956 * Enable the onNewPicture callback.
957 * @param enabled Flag to enable the callback.
958 * @param invalidationOnly Flag to call back only on invalidation without providing a picture.
960 public void enableOnNewPicture(boolean enabled, boolean invalidationOnly) {
961 if (mNativeAwContents == 0) return;
962 if (invalidationOnly) {
963 mPictureListenerContentProvider = null;
964 } else if (enabled && mPictureListenerContentProvider == null) {
965 mPictureListenerContentProvider = new Callable<Picture>() {
967 public Picture call() {
968 return capturePicture();
972 nativeEnableOnNewPicture(mNativeAwContents, enabled);
975 public void findAllAsync(String searchString) {
976 if (mNativeAwContents == 0) return;
977 nativeFindAllAsync(mNativeAwContents, searchString);
980 public void findNext(boolean forward) {
981 if (mNativeAwContents == 0) return;
982 nativeFindNext(mNativeAwContents, forward);
985 public void clearMatches() {
986 if (mNativeAwContents == 0) return;
987 nativeClearMatches(mNativeAwContents);
991 * @return load progress of the WebContents.
993 public int getMostRecentProgress() {
994 // WebContentsDelegateAndroid conveniently caches the most recent notified value for us.
995 return mWebContentsDelegate.getMostRecentProgress();
998 public Bitmap getFavicon() {
1002 private void requestVisitedHistoryFromClient() {
1003 ValueCallback<String[]> callback = new ValueCallback<String[]>() {
1005 public void onReceiveValue(final String[] value) {
1006 ThreadUtils.runOnUiThread(new Runnable() {
1009 if (mNativeAwContents == 0) return;
1010 nativeAddVisitedLinks(mNativeAwContents, value);
1015 mContentsClient.getVisitedHistory(callback);
1019 * Load url without fixing up the url string. Consumers of ContentView are responsible for
1020 * ensuring the URL passed in is properly formatted (i.e. the scheme has been added if left
1021 * off during user input).
1023 * @param params Parameters for this load.
1025 public void loadUrl(LoadUrlParams params) {
1026 if (mNativeAwContents == 0) return;
1028 if (params.getLoadUrlType() == LoadUrlParams.LOAD_TYPE_DATA &&
1029 !params.isBaseUrlDataScheme()) {
1030 // This allows data URLs with a non-data base URL access to file:///android_asset/ and
1031 // file:///android_res/ URLs. If AwSettings.getAllowFileAccess permits, it will also
1032 // allow access to file:// URLs (subject to OS level permission checks).
1033 params.setCanLoadLocalResources(true);
1036 // If we are reloading the same url, then set transition type as reload.
1037 if (params.getUrl() != null &&
1038 params.getUrl().equals(mContentViewCore.getUrl()) &&
1039 params.getTransitionType() == PageTransitionTypes.PAGE_TRANSITION_LINK) {
1040 params.setTransitionType(PageTransitionTypes.PAGE_TRANSITION_RELOAD);
1042 params.setTransitionType(
1043 params.getTransitionType() | PageTransitionTypes.PAGE_TRANSITION_FROM_API);
1045 // For WebView, always use the user agent override, which is set
1046 // every time the user agent in AwSettings is modified.
1047 params.setOverrideUserAgent(LoadUrlParams.UA_OVERRIDE_TRUE);
1050 // We don't pass extra headers to the content layer, as WebViewClassic
1051 // was adding them in a very narrow set of conditions. See http://crbug.com/306873
1052 // However, if the embedder is attempting to inject a Referer header for their
1053 // loadUrl call, then we set that separately and remove it from the extra headers map/
1054 final String REFERER = "referer";
1055 Map<String, String> extraHeaders = params.getExtraHeaders();
1056 if (extraHeaders != null) {
1057 for (String header : extraHeaders.keySet()) {
1058 if (REFERER.equals(header.toLowerCase(Locale.US))) {
1059 params.setReferrer(new Referrer(extraHeaders.remove(header), 1));
1060 params.setExtraHeaders(extraHeaders);
1066 nativeSetExtraHeadersForUrl(
1067 mNativeAwContents, params.getUrl(), params.getExtraHttpRequestHeadersString());
1068 params.setExtraHeaders(new HashMap<String, String>());
1070 nativeSendCheckRenderThreadResponsiveness(mNativeAwContents);
1071 mContentViewCore.loadUrl(params);
1073 // The behavior of WebViewClassic uses the populateVisitedLinks callback in WebKit.
1074 // Chromium does not use this use code path and the best emulation of this behavior to call
1075 // request visited links once on the first URL load of the WebView.
1076 if (!mHasRequestedVisitedHistoryFromClient) {
1077 mHasRequestedVisitedHistoryFromClient = true;
1078 requestVisitedHistoryFromClient();
1081 if (params.getLoadUrlType() == LoadUrlParams.LOAD_TYPE_DATA &&
1082 params.getBaseUrl() != null) {
1083 // Data loads with a base url will be resolved in Blink, and not cause an onPageStarted
1084 // event to be sent. Sending the callback directly from here.
1085 mContentsClient.getCallbackHelper().postOnPageStarted(params.getBaseUrl());
1090 * Get the URL of the current page.
1092 * @return The URL of the current page or null if it's empty.
1094 public String getUrl() {
1095 String url = mContentViewCore.getUrl();
1096 if (url == null || url.trim().isEmpty()) return null;
1100 public void requestFocus() {
1101 mAwViewMethods.requestFocus();
1104 public void setBackgroundColor(int color) {
1105 mBaseBackgroundColor = color;
1106 if (mNativeAwContents != 0) nativeSetBackgroundColor(mNativeAwContents, color);
1110 * @see android.view.View#setLayerType()
1112 public void setLayerType(int layerType, Paint paint) {
1113 mAwViewMethods.setLayerType(layerType, paint);
1116 int getEffectiveBackgroundColor() {
1117 // Do not ask the ContentViewCore for the background color, as it will always
1118 // report white prior to initial navigation or post destruction, whereas we want
1119 // to use the client supplied base value in those cases.
1120 if (mNativeAwContents == 0 || !mContentsClient.isCachedRendererBackgroundColorValid()) {
1121 return mBaseBackgroundColor;
1123 return mContentsClient.getCachedRendererBackgroundColor();
1126 public boolean isMultiTouchZoomSupported() {
1127 return mSettings.supportsMultiTouchZoom();
1130 public View getZoomControlsForTest() {
1131 return mZoomControls.getZoomControlsViewForTest();
1135 * @see ContentViewCore#getContentSettings()
1137 public ContentSettings getContentSettings() {
1138 return mContentViewCore.getContentSettings();
1142 * @see View#setOverScrollMode(int)
1144 public void setOverScrollMode(int mode) {
1145 if (mode != View.OVER_SCROLL_NEVER) {
1146 mOverScrollGlow = new OverScrollGlow(mContext, mContainerView);
1148 mOverScrollGlow = null;
1152 // TODO(mkosiba): In WebViewClassic these appear in some of the scroll extent calculation
1153 // methods but toggling them has no visiual effect on the content (in other words the scrolling
1154 // code behaves as if the scrollbar-related padding is in place but the onDraw code doesn't
1155 // take that into consideration).
1156 // http://crbug.com/269032
1157 private boolean mOverlayHorizontalScrollbar = true;
1158 private boolean mOverlayVerticalScrollbar = false;
1161 * @see View#setScrollBarStyle(int)
1163 public void setScrollBarStyle(int style) {
1164 if (style == View.SCROLLBARS_INSIDE_OVERLAY
1165 || style == View.SCROLLBARS_OUTSIDE_OVERLAY) {
1166 mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = true;
1168 mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = false;
1173 * @see View#setHorizontalScrollbarOverlay(boolean)
1175 public void setHorizontalScrollbarOverlay(boolean overlay) {
1176 mOverlayHorizontalScrollbar = overlay;
1180 * @see View#setVerticalScrollbarOverlay(boolean)
1182 public void setVerticalScrollbarOverlay(boolean overlay) {
1183 mOverlayVerticalScrollbar = overlay;
1187 * @see View#overlayHorizontalScrollbar()
1189 public boolean overlayHorizontalScrollbar() {
1190 return mOverlayHorizontalScrollbar;
1194 * @see View#overlayVerticalScrollbar()
1196 public boolean overlayVerticalScrollbar() {
1197 return mOverlayVerticalScrollbar;
1201 * Called by the embedder when the scroll offset of the containing view has changed.
1202 * @see View#onScrollChanged(int,int)
1204 public void onContainerViewScrollChanged(int l, int t, int oldl, int oldt) {
1205 // A side-effect of View.onScrollChanged is that the scroll accessibility event being sent
1206 // by the base class implementation. This is completely hidden from the base classes and
1207 // cannot be prevented, which is why we need the code below.
1208 mScrollAccessibilityHelper.removePostedViewScrolledAccessibilityEventCallback();
1209 mScrollOffsetManager.onContainerViewScrollChanged(l, t);
1213 * Called by the embedder when the containing view is to be scrolled or overscrolled.
1214 * @see View#onOverScrolled(int,int,int,int)
1216 public void onContainerViewOverScrolled(int scrollX, int scrollY, boolean clampedX,
1218 int oldX = mContainerView.getScrollX();
1219 int oldY = mContainerView.getScrollY();
1221 mScrollOffsetManager.onContainerViewOverScrolled(scrollX, scrollY, clampedX, clampedY);
1223 if (mOverScrollGlow != null) {
1224 mOverScrollGlow.pullGlow(mContainerView.getScrollX(), mContainerView.getScrollY(),
1226 mScrollOffsetManager.computeMaximumHorizontalScrollOffset(),
1227 mScrollOffsetManager.computeMaximumVerticalScrollOffset());
1232 * @see android.webkit.WebView#requestChildRectangleOnScreen(View, Rect, boolean)
1234 public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) {
1235 return mScrollOffsetManager.requestChildRectangleOnScreen(
1236 child.getLeft() - child.getScrollX(), child.getTop() - child.getScrollY(),
1241 * @see View.computeScroll()
1243 public void computeScroll() {
1244 mScrollOffsetManager.computeScrollAndAbsorbGlow(mOverScrollGlow);
1248 * @see View#computeHorizontalScrollRange()
1250 public int computeHorizontalScrollRange() {
1251 return mScrollOffsetManager.computeHorizontalScrollRange();
1255 * @see View#computeHorizontalScrollOffset()
1257 public int computeHorizontalScrollOffset() {
1258 return mScrollOffsetManager.computeHorizontalScrollOffset();
1262 * @see View#computeVerticalScrollRange()
1264 public int computeVerticalScrollRange() {
1265 return mScrollOffsetManager.computeVerticalScrollRange();
1269 * @see View#computeVerticalScrollOffset()
1271 public int computeVerticalScrollOffset() {
1272 return mScrollOffsetManager.computeVerticalScrollOffset();
1276 * @see View#computeVerticalScrollExtent()
1278 public int computeVerticalScrollExtent() {
1279 return mScrollOffsetManager.computeVerticalScrollExtent();
1283 * @see android.webkit.WebView#stopLoading()
1285 public void stopLoading() {
1286 mContentViewCore.stopLoading();
1290 * @see android.webkit.WebView#reload()
1292 public void reload() {
1293 mContentViewCore.reload(true);
1297 * @see android.webkit.WebView#canGoBack()
1299 public boolean canGoBack() {
1300 return mContentViewCore.canGoBack();
1304 * @see android.webkit.WebView#goBack()
1306 public void goBack() {
1307 mContentViewCore.goBack();
1311 * @see android.webkit.WebView#canGoForward()
1313 public boolean canGoForward() {
1314 return mContentViewCore.canGoForward();
1318 * @see android.webkit.WebView#goForward()
1320 public void goForward() {
1321 mContentViewCore.goForward();
1325 * @see android.webkit.WebView#canGoBackOrForward(int)
1327 public boolean canGoBackOrForward(int steps) {
1328 return mContentViewCore.canGoToOffset(steps);
1332 * @see android.webkit.WebView#goBackOrForward(int)
1334 public void goBackOrForward(int steps) {
1335 mContentViewCore.goToOffset(steps);
1339 * @see android.webkit.WebView#pauseTimers()
1341 public void pauseTimers() {
1342 ContentViewStatics.setWebKitSharedTimersSuspended(true);
1346 * @see android.webkit.WebView#resumeTimers()
1348 public void resumeTimers() {
1349 ContentViewStatics.setWebKitSharedTimersSuspended(false);
1353 * @see android.webkit.WebView#onPause()
1355 public void onPause() {
1356 if (mIsPaused || mNativeAwContents == 0) return;
1358 nativeSetIsPaused(mNativeAwContents, mIsPaused);
1362 * @see android.webkit.WebView#onResume()
1364 public void onResume() {
1365 if (!mIsPaused || mNativeAwContents == 0) return;
1367 nativeSetIsPaused(mNativeAwContents, mIsPaused);
1371 * @see android.webkit.WebView#isPaused()
1373 public boolean isPaused() {
1378 * @see android.webkit.WebView#onCreateInputConnection(EditorInfo)
1380 public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
1381 return mAwViewMethods.onCreateInputConnection(outAttrs);
1385 * @see android.webkit.WebView#onKeyUp(int, KeyEvent)
1387 public boolean onKeyUp(int keyCode, KeyEvent event) {
1388 return mAwViewMethods.onKeyUp(keyCode, event);
1392 * @see android.webkit.WebView#dispatchKeyEvent(KeyEvent)
1394 public boolean dispatchKeyEvent(KeyEvent event) {
1395 return mAwViewMethods.dispatchKeyEvent(event);
1399 * Clears the resource cache. Note that the cache is per-application, so this will clear the
1400 * cache for all WebViews used.
1402 * @param includeDiskFiles if false, only the RAM cache is cleared
1404 public void clearCache(boolean includeDiskFiles) {
1405 if (mNativeAwContents == 0) return;
1406 nativeClearCache(mNativeAwContents, includeDiskFiles);
1409 public void documentHasImages(Message message) {
1410 if (mNativeAwContents == 0) return;
1411 nativeDocumentHasImages(mNativeAwContents, message);
1414 public void saveWebArchive(
1415 final String basename, boolean autoname, final ValueCallback<String> callback) {
1417 saveWebArchiveInternal(basename, callback);
1420 // If auto-generating the file name, handle the name generation on a background thread
1421 // as it will require I/O access for checking whether previous files existed.
1422 new AsyncTask<Void, Void, String>() {
1424 protected String doInBackground(Void... params) {
1425 return generateArchiveAutoNamePath(getOriginalUrl(), basename);
1429 protected void onPostExecute(String result) {
1430 saveWebArchiveInternal(result, callback);
1435 public String getOriginalUrl() {
1436 NavigationHistory history = mContentViewCore.getNavigationHistory();
1437 int currentIndex = history.getCurrentEntryIndex();
1438 if (currentIndex >= 0 && currentIndex < history.getEntryCount()) {
1439 return history.getEntryAtIndex(currentIndex).getOriginalUrl();
1445 * @see ContentViewCore#getNavigationHistory()
1447 public NavigationHistory getNavigationHistory() {
1448 return mContentViewCore.getNavigationHistory();
1452 * @see android.webkit.WebView#getTitle()
1454 public String getTitle() {
1455 return mContentViewCore.getTitle();
1459 * @see android.webkit.WebView#clearHistory()
1461 public void clearHistory() {
1462 mContentViewCore.clearHistory();
1465 public String[] getHttpAuthUsernamePassword(String host, String realm) {
1466 return mBrowserContext.getHttpAuthDatabase(mContext)
1467 .getHttpAuthUsernamePassword(host, realm);
1470 public void setHttpAuthUsernamePassword(String host, String realm, String username,
1472 mBrowserContext.getHttpAuthDatabase(mContext)
1473 .setHttpAuthUsernamePassword(host, realm, username, password);
1477 * @see android.webkit.WebView#getCertificate()
1479 public SslCertificate getCertificate() {
1480 if (mNativeAwContents == 0) return null;
1481 return SslUtil.getCertificateFromDerBytes(nativeGetCertificate(mNativeAwContents));
1485 * @see android.webkit.WebView#clearSslPreferences()
1487 public void clearSslPreferences() {
1488 mContentViewCore.clearSslPreferences();
1491 // TODO(sgurun) remove after this rolls in. To keep internal tree happy.
1492 public void clearClientCertPreferences() { }
1495 * Method to return all hit test values relevant to public WebView API.
1496 * Note that this expose more data than needed for WebView.getHitTestResult.
1497 * Unsafely returning reference to mutable internal object to avoid excessive
1498 * garbage allocation on repeated calls.
1500 public HitTestData getLastHitTestResult() {
1501 if (mNativeAwContents == 0) return null;
1502 nativeUpdateLastHitTestData(mNativeAwContents);
1503 return mPossiblyStaleHitTestData;
1507 * @see android.webkit.WebView#requestFocusNodeHref()
1509 public void requestFocusNodeHref(Message msg) {
1510 if (msg == null || mNativeAwContents == 0) return;
1512 nativeUpdateLastHitTestData(mNativeAwContents);
1513 Bundle data = msg.getData();
1515 // In order to maintain compatibility with the old WebView's implementation,
1516 // the absolute (full) url is passed in the |url| field, not only the href attribute.
1517 // Note: HitTestData could be cleaned up at this point. See http://crbug.com/290992.
1518 data.putString("url", mPossiblyStaleHitTestData.href);
1519 data.putString("title", mPossiblyStaleHitTestData.anchorText);
1520 data.putString("src", mPossiblyStaleHitTestData.imgSrc);
1526 * @see android.webkit.WebView#requestImageRef()
1528 public void requestImageRef(Message msg) {
1529 if (msg == null || mNativeAwContents == 0) return;
1531 nativeUpdateLastHitTestData(mNativeAwContents);
1532 Bundle data = msg.getData();
1533 data.putString("url", mPossiblyStaleHitTestData.imgSrc);
1539 public float getPageScaleFactor() {
1540 return mPageScaleFactor;
1544 * @see android.webkit.WebView#getScale()
1546 * Please note that the scale returned is the page scale multiplied by
1547 * the screen density factor. See CTS WebViewTest.testSetInitialScale.
1549 public float getScale() {
1550 return (float)(mPageScaleFactor * mDIPScale);
1554 * @see android.webkit.WebView#flingScroll(int, int)
1556 public void flingScroll(int velocityX, int velocityY) {
1557 mScrollOffsetManager.flingScroll(velocityX, velocityY);
1561 * @see android.webkit.WebView#pageUp(boolean)
1563 public boolean pageUp(boolean top) {
1564 return mScrollOffsetManager.pageUp(top);
1568 * @see android.webkit.WebView#pageDown(boolean)
1570 public boolean pageDown(boolean bottom) {
1571 return mScrollOffsetManager.pageDown(bottom);
1575 * @see android.webkit.WebView#canZoomIn()
1577 // This method uses the term 'zoom' for legacy reasons, but relates
1578 // to what chrome calls the 'page scale factor'.
1579 public boolean canZoomIn() {
1580 final float zoomInExtent = mMaxPageScaleFactor - mPageScaleFactor;
1581 return zoomInExtent > ZOOM_CONTROLS_EPSILON;
1585 * @see android.webkit.WebView#canZoomOut()
1587 // This method uses the term 'zoom' for legacy reasons, but relates
1588 // to what chrome calls the 'page scale factor'.
1589 public boolean canZoomOut() {
1590 final float zoomOutExtent = mPageScaleFactor - mMinPageScaleFactor;
1591 return zoomOutExtent > ZOOM_CONTROLS_EPSILON;
1595 * @see android.webkit.WebView#zoomIn()
1597 // This method uses the term 'zoom' for legacy reasons, but relates
1598 // to what chrome calls the 'page scale factor'.
1599 public boolean zoomIn() {
1603 return mContentViewCore.pinchByDelta(1.25f);
1607 * @see android.webkit.WebView#zoomOut()
1609 // This method uses the term 'zoom' for legacy reasons, but relates
1610 // to what chrome calls the 'page scale factor'.
1611 public boolean zoomOut() {
1612 if (!canZoomOut()) {
1615 return mContentViewCore.pinchByDelta(0.8f);
1619 * @see android.webkit.WebView#invokeZoomPicker()
1621 public void invokeZoomPicker() {
1622 mContentViewCore.invokeZoomPicker();
1626 * @see android.webkit.WebView#preauthorizePermission(Uri, long)
1628 public void preauthorizePermission(Uri origin, long resources) {
1629 if (mNativeAwContents == 0) return;
1630 nativePreauthorizePermission(mNativeAwContents, origin.toString(), resources);
1634 * @see ContentViewCore.evaluateJavaScript(String, ContentViewCore.JavaScriptCallback)
1636 public void evaluateJavaScript(String script, final ValueCallback<String> callback) {
1637 ContentViewCore.JavaScriptCallback jsCallback = null;
1638 if (callback != null) {
1639 jsCallback = new ContentViewCore.JavaScriptCallback() {
1641 public void handleJavaScriptResult(String jsonResult) {
1642 callback.onReceiveValue(jsonResult);
1647 mContentViewCore.evaluateJavaScript(script, jsCallback);
1651 * @see ContentViewCore.evaluateJavaScriptEvenIfNotYetNavigated(String)
1653 public void evaluateJavaScriptEvenIfNotYetNavigated(String script) {
1654 mContentViewCore.evaluateJavaScriptEvenIfNotYetNavigated(script);
1657 //--------------------------------------------------------------------------------------------
1658 // View and ViewGroup method implementations
1659 //--------------------------------------------------------------------------------------------
1662 * @see android.webkit.View#onTouchEvent()
1664 public boolean onTouchEvent(MotionEvent event) {
1665 return mAwViewMethods.onTouchEvent(event);
1669 * @see android.view.View#onHoverEvent()
1671 public boolean onHoverEvent(MotionEvent event) {
1672 return mAwViewMethods.onHoverEvent(event);
1676 * @see android.view.View#onGenericMotionEvent()
1678 public boolean onGenericMotionEvent(MotionEvent event) {
1679 return mContentViewCore.onGenericMotionEvent(event);
1683 * @see android.view.View#onConfigurationChanged()
1685 public void onConfigurationChanged(Configuration newConfig) {
1686 mAwViewMethods.onConfigurationChanged(newConfig);
1690 * @see android.view.View#onAttachedToWindow()
1692 public void onAttachedToWindow() {
1693 mTemporarilyDetached = false;
1694 mAwViewMethods.onAttachedToWindow();
1698 * @see android.view.View#onDetachedFromWindow()
1700 @SuppressLint("MissingSuperCall")
1701 public void onDetachedFromWindow() {
1702 mAwViewMethods.onDetachedFromWindow();
1706 * @see android.view.View#onWindowFocusChanged()
1708 public void onWindowFocusChanged(boolean hasWindowFocus) {
1709 mAwViewMethods.onWindowFocusChanged(hasWindowFocus);
1713 * @see android.view.View#onFocusChanged()
1715 public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
1716 if (!mTemporarilyDetached) {
1717 mAwViewMethods.onFocusChanged(focused, direction, previouslyFocusedRect);
1722 * @see android.view.View#onStartTemporaryDetach()
1724 public void onStartTemporaryDetach() {
1725 mTemporarilyDetached = true;
1729 * @see android.view.View#onFinishTemporaryDetach()
1731 public void onFinishTemporaryDetach() {
1732 mTemporarilyDetached = false;
1736 * @see android.view.View#onSizeChanged()
1738 public void onSizeChanged(int w, int h, int ow, int oh) {
1739 mAwViewMethods.onSizeChanged(w, h, ow, oh);
1743 * @see android.view.View#onVisibilityChanged()
1745 public void onVisibilityChanged(View changedView, int visibility) {
1746 mAwViewMethods.onVisibilityChanged(changedView, visibility);
1750 * @see android.view.View#onWindowVisibilityChanged()
1752 public void onWindowVisibilityChanged(int visibility) {
1753 mAwViewMethods.onWindowVisibilityChanged(visibility);
1756 private void setViewVisibilityInternal(boolean visible) {
1757 mIsViewVisible = visible;
1758 if (mNativeAwContents == 0) return;
1759 nativeSetViewVisibility(mNativeAwContents, mIsViewVisible);
1762 private void setWindowVisibilityInternal(boolean visible) {
1763 mIsWindowVisible = visible;
1764 if (mNativeAwContents == 0) return;
1765 nativeSetWindowVisibility(mNativeAwContents, mIsWindowVisible);
1769 * Key for opaque state in bundle. Note this is only public for tests.
1771 public static final String SAVE_RESTORE_STATE_KEY = "WEBVIEW_CHROMIUM_STATE";
1774 * Save the state of this AwContents into provided Bundle.
1775 * @return False if saving state failed.
1777 public boolean saveState(Bundle outState) {
1778 if (mNativeAwContents == 0 || outState == null) return false;
1780 byte[] state = nativeGetOpaqueState(mNativeAwContents);
1781 if (state == null) return false;
1783 outState.putByteArray(SAVE_RESTORE_STATE_KEY, state);
1788 * Restore the state of this AwContents into provided Bundle.
1789 * @param inState Must be a bundle returned by saveState.
1790 * @return False if restoring state failed.
1792 public boolean restoreState(Bundle inState) {
1793 if (mNativeAwContents == 0 || inState == null) return false;
1795 byte[] state = inState.getByteArray(SAVE_RESTORE_STATE_KEY);
1796 if (state == null) return false;
1798 boolean result = nativeRestoreFromOpaqueState(mNativeAwContents, state);
1800 // The onUpdateTitle callback normally happens when a page is loaded,
1801 // but is optimized out in the restoreState case because the title is
1802 // already restored. See WebContentsImpl::UpdateTitleForEntry. So we
1803 // call the callback explicitly here.
1804 if (result) mContentsClient.onReceivedTitle(mContentViewCore.getTitle());
1810 * @see ContentViewCore#addPossiblyUnsafeJavascriptInterface(Object, String, Class)
1812 public void addPossiblyUnsafeJavascriptInterface(Object object, String name,
1813 Class<? extends Annotation> requiredAnnotation) {
1814 mContentViewCore.addPossiblyUnsafeJavascriptInterface(object, name, requiredAnnotation);
1818 * @see android.webkit.WebView#removeJavascriptInterface(String)
1820 public void removeJavascriptInterface(String interfaceName) {
1821 mContentViewCore.removeJavascriptInterface(interfaceName);
1825 * If native accessibility (not script injection) is enabled, and if this is
1826 * running on JellyBean or later, returns an AccessibilityNodeProvider that
1827 * implements native accessibility for this view. Returns null otherwise.
1828 * @return The AccessibilityNodeProvider, if available, or null otherwise.
1830 public AccessibilityNodeProvider getAccessibilityNodeProvider() {
1831 return mContentViewCore.getAccessibilityNodeProvider();
1835 * @see android.webkit.WebView#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
1837 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
1838 mContentViewCore.onInitializeAccessibilityNodeInfo(info);
1842 * @see android.webkit.WebView#onInitializeAccessibilityEvent(AccessibilityEvent)
1844 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
1845 mContentViewCore.onInitializeAccessibilityEvent(event);
1848 public boolean supportsAccessibilityAction(int action) {
1849 return mContentViewCore.supportsAccessibilityAction(action);
1853 * @see android.webkit.WebView#performAccessibilityAction(int, Bundle)
1855 public boolean performAccessibilityAction(int action, Bundle arguments) {
1856 return mContentViewCore.performAccessibilityAction(action, arguments);
1860 * @see android.webkit.WebView#clearFormData()
1862 public void hideAutofillPopup() {
1863 if (mAwAutofillClient != null) {
1864 mAwAutofillClient.hideAutofillPopup();
1868 public void setNetworkAvailable(boolean networkUp) {
1869 if (mNativeAwContents == 0) return;
1870 nativeSetJsOnlineProperty(mNativeAwContents, networkUp);
1873 //--------------------------------------------------------------------------------------------
1874 // Methods called from native via JNI
1875 //--------------------------------------------------------------------------------------------
1878 private static void onDocumentHasImagesResponse(boolean result, Message message) {
1879 message.arg1 = result ? 1 : 0;
1880 message.sendToTarget();
1884 private void onReceivedTouchIconUrl(String url, boolean precomposed) {
1885 mContentsClient.onReceivedTouchIconUrl(url, precomposed);
1889 private void onReceivedIcon(Bitmap bitmap) {
1890 mContentsClient.onReceivedIcon(bitmap);
1894 /** Callback for generateMHTML. */
1896 private static void generateMHTMLCallback(
1897 String path, long size, ValueCallback<String> callback) {
1898 if (callback == null) return;
1899 callback.onReceiveValue(size < 0 ? null : path);
1903 private void onReceivedHttpAuthRequest(AwHttpAuthHandler handler, String host, String realm) {
1904 mContentsClient.onReceivedHttpAuthRequest(handler, host, realm);
1907 private class AwGeolocationCallback implements GeolocationPermissions.Callback {
1910 public void invoke(final String origin, final boolean allow, final boolean retain) {
1911 ThreadUtils.runOnUiThread(new Runnable() {
1916 mBrowserContext.getGeolocationPermissions().allow(origin);
1918 mBrowserContext.getGeolocationPermissions().deny(origin);
1921 if (mNativeAwContents == 0) return;
1922 nativeInvokeGeolocationCallback(mNativeAwContents, allow, origin);
1929 private void onGeolocationPermissionsShowPrompt(String origin) {
1930 if (mNativeAwContents == 0) return;
1931 AwGeolocationPermissions permissions = mBrowserContext.getGeolocationPermissions();
1932 // Reject if geoloaction is disabled, or the origin has a retained deny
1933 if (!mSettings.getGeolocationEnabled()) {
1934 nativeInvokeGeolocationCallback(mNativeAwContents, false, origin);
1937 // Allow if the origin has a retained allow
1938 if (permissions.hasOrigin(origin)) {
1939 nativeInvokeGeolocationCallback(mNativeAwContents, permissions.isOriginAllowed(origin),
1943 mContentsClient.onGeolocationPermissionsShowPrompt(
1944 origin, new AwGeolocationCallback());
1948 private void onGeolocationPermissionsHidePrompt() {
1949 mContentsClient.onGeolocationPermissionsHidePrompt();
1953 private void onPermissionRequest(AwPermissionRequest awPermissionRequest) {
1954 mContentsClient.onPermissionRequest(awPermissionRequest);
1958 private void onPermissionRequestCanceled(AwPermissionRequest awPermissionRequest) {
1959 mContentsClient.onPermissionRequestCanceled(awPermissionRequest);
1963 public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
1964 boolean isDoneCounting) {
1965 mContentsClient.onFindResultReceived(activeMatchOrdinal, numberOfMatches, isDoneCounting);
1969 public void onNewPicture() {
1970 // Don't call capturePicture() here but instead defer it until the posted task runs within
1971 // the callback helper, to avoid doubling back into the renderer compositor in the middle
1972 // of the notification it is sending up to here.
1973 mContentsClient.getCallbackHelper().postOnNewPicture(mPictureListenerContentProvider);
1976 // Called as a result of nativeUpdateLastHitTestData.
1978 private void updateHitTestData(
1979 int type, String extra, String href, String anchorText, String imgSrc) {
1980 mPossiblyStaleHitTestData.hitTestResultType = type;
1981 mPossiblyStaleHitTestData.hitTestResultExtraData = extra;
1982 mPossiblyStaleHitTestData.href = href;
1983 mPossiblyStaleHitTestData.anchorText = anchorText;
1984 mPossiblyStaleHitTestData.imgSrc = imgSrc;
1988 private boolean requestDrawGL(Canvas canvas, boolean waitForCompletion) {
1989 return mNativeGLDelegate.requestDrawGL(canvas, waitForCompletion, mContainerView);
1992 private static final boolean SUPPORTS_ON_ANIMATION =
1993 Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
1996 private void postInvalidateOnAnimation() {
1997 if (SUPPORTS_ON_ANIMATION) {
1998 mContainerView.postInvalidateOnAnimation();
2000 mContainerView.postInvalidate();
2005 private int[] getLocationOnScreen() {
2006 int[] result = new int[2];
2007 mContainerView.getLocationOnScreen(result);
2012 private void onWebLayoutPageScaleFactorChanged(float webLayoutPageScaleFactor) {
2013 // This change notification comes from the renderer thread, not from the cc/ impl thread.
2014 mLayoutSizer.onPageScaleChanged(webLayoutPageScaleFactor);
2018 private void onWebLayoutContentsSizeChanged(int widthCss, int heightCss) {
2019 // This change notification comes from the renderer thread, not from the cc/ impl thread.
2020 mLayoutSizer.onContentSizeChanged(widthCss, heightCss);
2024 private void scrollContainerViewTo(int x, int y) {
2025 mScrollOffsetManager.scrollContainerViewTo(x, y);
2029 private boolean isFlingActive() {
2030 return mScrollOffsetManager.isFlingActive();
2034 private void updateScrollState(int maxContainerViewScrollOffsetX,
2035 int maxContainerViewScrollOffsetY, int contentWidthDip, int contentHeightDip,
2036 float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor) {
2037 mContentWidthDip = contentWidthDip;
2038 mContentHeightDip = contentHeightDip;
2039 mScrollOffsetManager.setMaxScrollOffset(maxContainerViewScrollOffsetX,
2040 maxContainerViewScrollOffsetY);
2041 setPageScaleFactorAndLimits(pageScaleFactor, minPageScaleFactor, maxPageScaleFactor);
2045 private void setAwAutofillClient(AwAutofillClient client) {
2046 mAwAutofillClient = client;
2047 client.init(mContentViewCore);
2051 private void didOverscroll(int deltaX, int deltaY) {
2052 if (mOverScrollGlow != null) {
2053 mOverScrollGlow.setOverScrollDeltas(deltaX, deltaY);
2056 mScrollOffsetManager.overScrollBy(deltaX, deltaY);
2058 if (mOverScrollGlow != null && mOverScrollGlow.isAnimating()) {
2059 mContainerView.invalidate();
2063 // -------------------------------------------------------------------------------------------
2065 // -------------------------------------------------------------------------------------------
2067 private void setPageScaleFactorAndLimits(
2068 float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor) {
2069 if (mPageScaleFactor == pageScaleFactor &&
2070 mMinPageScaleFactor == minPageScaleFactor &&
2071 mMaxPageScaleFactor == maxPageScaleFactor) {
2074 mMinPageScaleFactor = minPageScaleFactor;
2075 mMaxPageScaleFactor = maxPageScaleFactor;
2076 if (mPageScaleFactor != pageScaleFactor) {
2077 float oldPageScaleFactor = mPageScaleFactor;
2078 mPageScaleFactor = pageScaleFactor;
2079 // NOTE: if this ever needs to become synchronous then we need to make sure the scroll
2080 // bounds are correctly updated before calling the method, otherwise embedder code that
2081 // attempts to scroll on scale change might cause weird results.
2082 mContentsClient.getCallbackHelper().postOnScaleChangedScaled(
2083 (float)(oldPageScaleFactor * mDIPScale),
2084 (float)(mPageScaleFactor * mDIPScale));
2088 private void saveWebArchiveInternal(String path, final ValueCallback<String> callback) {
2089 if (path == null || mNativeAwContents == 0) {
2090 ThreadUtils.runOnUiThread(new Runnable() {
2093 callback.onReceiveValue(null);
2097 nativeGenerateMHTML(mNativeAwContents, path, callback);
2102 * Try to generate a pathname for saving an MHTML archive. This roughly follows WebView's
2105 private static String generateArchiveAutoNamePath(String originalUrl, String baseName) {
2107 if (originalUrl != null && !originalUrl.isEmpty()) {
2109 String path = new URL(originalUrl).getPath();
2110 int lastSlash = path.lastIndexOf('/');
2111 if (lastSlash > 0) {
2112 name = path.substring(lastSlash + 1);
2116 } catch (MalformedURLException e) {
2117 // If it fails parsing the URL, we'll just rely on the default name below.
2121 if (TextUtils.isEmpty(name)) name = "index";
2123 String testName = baseName + name + WEB_ARCHIVE_EXTENSION;
2124 if (!new File(testName).exists()) return testName;
2126 for (int i = 1; i < 100; i++) {
2127 testName = baseName + name + "-" + i + WEB_ARCHIVE_EXTENSION;
2128 if (!new File(testName).exists()) return testName;
2131 Log.e(TAG, "Unable to auto generate archive name for path: " + baseName);
2135 public void extractSmartClipData(int x, int y, int width, int height) {
2136 mContentViewCore.extractSmartClipData(x, y, width, height);
2139 public void setSmartClipDataListener(ContentViewCore.SmartClipDataListener listener) {
2140 mContentViewCore.setSmartClipDataListener(listener);
2143 // --------------------------------------------------------------------------------------------
2144 // This is the AwViewMethods implementation that does real work. The AwViewMethodsImpl is
2145 // hooked up to the WebView in embedded mode and to the FullScreenView in fullscreen mode,
2146 // but not to both at the same time.
2147 private class AwViewMethodsImpl implements AwViewMethods {
2148 private int mLayerType = View.LAYER_TYPE_NONE;
2149 private ComponentCallbacks2 mComponentCallbacks;
2151 // Only valid within onDraw().
2152 private final Rect mClipBoundsTemporary = new Rect();
2155 public void onDraw(Canvas canvas) {
2156 if (mNativeAwContents == 0) {
2157 canvas.drawColor(getEffectiveBackgroundColor());
2161 mScrollOffsetManager.syncScrollOffsetFromOnDraw();
2162 canvas.getClipBounds(mClipBoundsTemporary);
2164 Rect globalVisibleRect = getGlobalVisibleRect();
2166 if (!nativeOnDraw(mNativeAwContents, canvas, canvas.isHardwareAccelerated(),
2167 mContainerView.getScrollX(), mContainerView.getScrollY(),
2168 globalVisibleRect.left, globalVisibleRect.top,
2169 globalVisibleRect.right, globalVisibleRect.bottom,
2170 mClipBoundsTemporary.left, mClipBoundsTemporary.top,
2171 mClipBoundsTemporary.right, mClipBoundsTemporary.bottom)) {
2172 // Can happen during initialization when compositor is not set
2173 // up. Or when clearView
2174 // is in effect. Just draw background color instead.
2175 canvas.drawColor(getEffectiveBackgroundColor());
2178 if (mOverScrollGlow != null && mOverScrollGlow.drawEdgeGlows(canvas,
2179 mScrollOffsetManager.computeMaximumHorizontalScrollOffset(),
2180 mScrollOffsetManager.computeMaximumVerticalScrollOffset())) {
2181 mContainerView.invalidate();
2186 public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
2187 mLayoutSizer.onMeasure(widthMeasureSpec, heightMeasureSpec);
2191 public void requestFocus() {
2192 if (mNativeAwContents == 0) return;
2193 if (!mContainerView.isInTouchMode() && mSettings.shouldFocusFirstNode()) {
2194 nativeFocusFirstNode(mNativeAwContents);
2199 public void setLayerType(int layerType, Paint paint) {
2200 mLayerType = layerType;
2201 updateHardwareAcceleratedFeaturesToggle();
2204 private void updateHardwareAcceleratedFeaturesToggle() {
2205 mSettings.setEnableSupportedHardwareAcceleratedFeatures(
2206 mIsAttachedToWindow && mContainerView.isHardwareAccelerated() &&
2207 (mLayerType == View.LAYER_TYPE_NONE
2208 || mLayerType == View.LAYER_TYPE_HARDWARE));
2212 public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
2213 return mContentViewCore.onCreateInputConnection(outAttrs);
2217 public boolean onKeyUp(int keyCode, KeyEvent event) {
2218 return mContentViewCore.onKeyUp(keyCode, event);
2222 public boolean dispatchKeyEvent(KeyEvent event) {
2223 if (isDpadEvent(event)) {
2224 mSettings.setSpatialNavigationEnabled(true);
2226 return mContentViewCore.dispatchKeyEvent(event);
2229 private boolean isDpadEvent(KeyEvent event) {
2230 if (event.getAction() == KeyEvent.ACTION_DOWN) {
2231 switch (event.getKeyCode()) {
2232 case KeyEvent.KEYCODE_DPAD_CENTER:
2233 case KeyEvent.KEYCODE_DPAD_DOWN:
2234 case KeyEvent.KEYCODE_DPAD_UP:
2235 case KeyEvent.KEYCODE_DPAD_LEFT:
2236 case KeyEvent.KEYCODE_DPAD_RIGHT:
2244 public boolean onTouchEvent(MotionEvent event) {
2245 if (mNativeAwContents == 0) return false;
2247 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
2248 mSettings.setSpatialNavigationEnabled(false);
2251 mScrollOffsetManager.setProcessingTouchEvent(true);
2252 boolean rv = mContentViewCore.onTouchEvent(event);
2253 mScrollOffsetManager.setProcessingTouchEvent(false);
2255 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
2256 int actionIndex = event.getActionIndex();
2258 // Note this will trigger IPC back to browser even if nothing is
2260 nativeRequestNewHitTestDataAt(mNativeAwContents,
2261 (int) Math.round(event.getX(actionIndex) / mDIPScale),
2262 (int) Math.round(event.getY(actionIndex) / mDIPScale));
2265 if (mOverScrollGlow != null) {
2266 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
2267 mOverScrollGlow.setShouldPull(true);
2268 } else if (event.getActionMasked() == MotionEvent.ACTION_UP ||
2269 event.getActionMasked() == MotionEvent.ACTION_CANCEL) {
2270 mOverScrollGlow.setShouldPull(false);
2271 mOverScrollGlow.releaseAll();
2279 public boolean onHoverEvent(MotionEvent event) {
2280 return mContentViewCore.onHoverEvent(event);
2284 public boolean onGenericMotionEvent(MotionEvent event) {
2285 return mContentViewCore.onGenericMotionEvent(event);
2289 public void onConfigurationChanged(Configuration newConfig) {
2290 mContentViewCore.onConfigurationChanged(newConfig);
2294 public void onAttachedToWindow() {
2295 if (mNativeAwContents == 0) return;
2296 if (mIsAttachedToWindow) {
2297 Log.w(TAG, "onAttachedToWindow called when already attached. Ignoring");
2300 mIsAttachedToWindow = true;
2302 mContentViewCore.onAttachedToWindow();
2303 nativeOnAttachedToWindow(mNativeAwContents, mContainerView.getWidth(),
2304 mContainerView.getHeight());
2305 updateHardwareAcceleratedFeaturesToggle();
2307 if (mComponentCallbacks != null) return;
2308 mComponentCallbacks = new AwComponentCallbacks();
2309 mContext.registerComponentCallbacks(mComponentCallbacks);
2313 public void onDetachedFromWindow() {
2314 if (!mIsAttachedToWindow) {
2315 Log.w(TAG, "onDetachedFromWindow called when already detached. Ignoring");
2318 mIsAttachedToWindow = false;
2319 hideAutofillPopup();
2320 if (mNativeAwContents != 0) {
2321 nativeOnDetachedFromWindow(mNativeAwContents);
2324 mContentViewCore.onDetachedFromWindow();
2325 updateHardwareAcceleratedFeaturesToggle();
2327 if (mComponentCallbacks != null) {
2328 mContext.unregisterComponentCallbacks(mComponentCallbacks);
2329 mComponentCallbacks = null;
2332 mScrollAccessibilityHelper.removePostedCallbacks();
2333 mNativeGLDelegate.detachGLFunctor();
2337 public void onWindowFocusChanged(boolean hasWindowFocus) {
2338 mWindowFocused = hasWindowFocus;
2339 mContentViewCore.onWindowFocusChanged(hasWindowFocus);
2343 public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
2344 mContainerViewFocused = focused;
2345 mContentViewCore.onFocusChanged(focused);
2349 public void onSizeChanged(int w, int h, int ow, int oh) {
2350 if (mNativeAwContents == 0) return;
2351 mScrollOffsetManager.setContainerViewSize(w, h);
2352 // The AwLayoutSizer needs to go first so that if we're in
2353 // fixedLayoutSize mode the update
2354 // to enter fixedLayoutSize mode is sent before the first resize
2356 mLayoutSizer.onSizeChanged(w, h, ow, oh);
2357 mContentViewCore.onPhysicalBackingSizeChanged(w, h);
2358 mContentViewCore.onSizeChanged(w, h, ow, oh);
2359 nativeOnSizeChanged(mNativeAwContents, w, h, ow, oh);
2363 public void onVisibilityChanged(View changedView, int visibility) {
2364 boolean viewVisible = mContainerView.getVisibility() == View.VISIBLE;
2365 if (mIsViewVisible == viewVisible) return;
2366 setViewVisibilityInternal(viewVisible);
2370 public void onWindowVisibilityChanged(int visibility) {
2371 boolean windowVisible = visibility == View.VISIBLE;
2372 if (mIsWindowVisible == windowVisible) return;
2373 setWindowVisibilityInternal(windowVisible);
2377 // Return true if the GeolocationPermissionAPI should be used.
2379 private boolean useLegacyGeolocationPermissionAPI() {
2380 // TODO (michaelbai): Need to verify whether this is correct when release.
2381 return mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.KITKAT;
2384 //--------------------------------------------------------------------------------------------
2386 //--------------------------------------------------------------------------------------------
2388 private static native long nativeInit(AwBrowserContext browserContext);
2389 private static native void nativeDestroy(long nativeAwContents);
2390 private static native void nativeSetAwDrawSWFunctionTable(long functionTablePointer);
2391 private static native void nativeSetAwDrawGLFunctionTable(long functionTablePointer);
2392 private static native long nativeGetAwDrawGLFunction();
2393 private static native int nativeGetNativeInstanceCount();
2394 private static native void nativeSetShouldDownloadFavicons();
2396 private native void nativeSetJavaPeers(long nativeAwContents, AwContents awContents,
2397 AwWebContentsDelegate webViewWebContentsDelegate,
2398 AwContentsClientBridge contentsClientBridge,
2399 AwContentsIoThreadClient ioThreadClient,
2400 InterceptNavigationDelegate navigationInterceptionDelegate);
2401 private native long nativeGetWebContents(long nativeAwContents);
2403 private native void nativeDocumentHasImages(long nativeAwContents, Message message);
2404 private native void nativeGenerateMHTML(
2405 long nativeAwContents, String path, ValueCallback<String> callback);
2407 private native void nativeAddVisitedLinks(long nativeAwContents, String[] visitedLinks);
2408 private native boolean nativeOnDraw(long nativeAwContents, Canvas canvas,
2409 boolean isHardwareAccelerated, int scrollX, int scrollY,
2410 int visibleLeft, int visibleTop, int visibleRight, int visibleBottom,
2411 int clipLeft, int clipTop, int clipRight, int clipBottom);
2412 private native void nativeFindAllAsync(long nativeAwContents, String searchString);
2413 private native void nativeFindNext(long nativeAwContents, boolean forward);
2414 private native void nativeClearMatches(long nativeAwContents);
2415 private native void nativeClearCache(long nativeAwContents, boolean includeDiskFiles);
2416 private native byte[] nativeGetCertificate(long nativeAwContents);
2418 // Coordinates in desity independent pixels.
2419 private native void nativeRequestNewHitTestDataAt(long nativeAwContents, int x, int y);
2420 private native void nativeUpdateLastHitTestData(long nativeAwContents);
2422 private native void nativeOnSizeChanged(long nativeAwContents, int w, int h, int ow, int oh);
2423 private native void nativeScrollTo(long nativeAwContents, int x, int y);
2424 private native void nativeSetViewVisibility(long nativeAwContents, boolean visible);
2425 private native void nativeSetWindowVisibility(long nativeAwContents, boolean visible);
2426 private native void nativeSetIsPaused(long nativeAwContents, boolean paused);
2427 private native void nativeOnAttachedToWindow(long nativeAwContents, int w, int h);
2428 private static native void nativeOnDetachedFromWindow(long nativeAwContents);
2429 private native void nativeSetDipScale(long nativeAwContents, float dipScale);
2430 private native void nativeSetFixedLayoutSize(long nativeAwContents,
2431 int widthDip, int heightDip);
2433 // Returns null if save state fails.
2434 private native byte[] nativeGetOpaqueState(long nativeAwContents);
2436 // Returns false if restore state fails.
2437 private native boolean nativeRestoreFromOpaqueState(long nativeAwContents, byte[] state);
2439 private native long nativeReleasePopupAwContents(long nativeAwContents);
2440 private native void nativeFocusFirstNode(long nativeAwContents);
2441 private native void nativeSetBackgroundColor(long nativeAwContents, int color);
2443 private native long nativeGetAwDrawGLViewContext(long nativeAwContents);
2444 private native long nativeCapturePicture(long nativeAwContents, int width, int height);
2445 private native void nativeEnableOnNewPicture(long nativeAwContents, boolean enabled);
2446 private native void nativeClearView(long nativeAwContents);
2447 private native void nativeSetExtraHeadersForUrl(long nativeAwContents,
2448 String url, String extraHeaders);
2449 private native void nativeSendCheckRenderThreadResponsiveness(long nativeAwContents);
2451 private native void nativeInvokeGeolocationCallback(
2452 long nativeAwContents, boolean value, String requestingFrame);
2454 private native void nativeSetJsOnlineProperty(long nativeAwContents, boolean networkUp);
2456 private native void nativeTrimMemory(long nativeAwContents, int level, boolean visible);
2458 private native void nativeCreatePdfExporter(long nativeAwContents, AwPdfExporter awPdfExporter);
2460 private native void nativePreauthorizePermission(long nativeAwContents, String origin,