Home | History | Annotate | Download | only in android_webview
      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