AwContents.java revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)package org.chromium.android_webview;
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.app.Activity;
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.content.ComponentCallbacks2;
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.content.Context;
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.content.res.Configuration;
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.graphics.Bitmap;
12effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport android.graphics.Canvas;
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.graphics.Color;
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.graphics.Picture;
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.graphics.Rect;
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.net.http.SslCertificate;
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.os.AsyncTask;
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.os.Build;
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.os.Bundle;
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.os.Message;
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.text.TextUtils;
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.util.Log;
234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import android.view.KeyEvent;
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.view.MotionEvent;
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.view.View;
264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import android.view.ViewGroup;
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.view.accessibility.AccessibilityEvent;
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.view.accessibility.AccessibilityNodeInfo;
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.view.accessibility.AccessibilityNodeProvider;
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.view.inputmethod.EditorInfo;
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.view.inputmethod.InputConnection;
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.webkit.GeolocationPermissions;
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.webkit.ValueCallback;
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.widget.OverScroller;
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import com.google.common.annotations.VisibleForTesting;
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.chromium.base.CalledByNative;
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.base.JNINamespace;
40effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport org.chromium.base.ThreadUtils;
41effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport org.chromium.components.navigation_interception.InterceptNavigationDelegate;
42effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport org.chromium.components.navigation_interception.NavigationParams;
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import org.chromium.content.browser.ContentSettings;
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import org.chromium.content.browser.ContentViewClient;
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import org.chromium.content.browser.ContentViewCore;
464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import org.chromium.content.browser.ContentViewStatics;
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import org.chromium.content.browser.LoadUrlParams;
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.chromium.content.browser.NavigationHistory;
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.chromium.content.browser.PageTransitionTypes;
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.content.common.CleanupReference;
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.chromium.content_public.browser.GestureStateListener;
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.ui.base.ActivityWindowAndroid;
5323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import org.chromium.ui.base.WindowAndroid;
54effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport org.chromium.ui.gfx.DeviceDisplayInfo;
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
56effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport java.io.File;
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import java.lang.annotation.Annotation;
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import java.net.MalformedURLException;
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import java.net.URL;
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import java.util.ArrayList;
6123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import java.util.HashMap;
62effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport java.util.List;
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import java.util.concurrent.Callable;
64effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Exposes the native AwContents class, and together these classes wrap the ContentViewCore
674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * and Browser components that are required to implement Android WebView API. This is the
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * primary entry point for the WebViewProvider implementation; it holds a 1:1 object
69effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * relationship with application WebView instances.
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * (We define this class independent of the hidden WebViewProvider interfaces, to allow
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * continuous build & test in the open source SDK-based tree).
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)@JNINamespace("android_webview")
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)public class AwContents {
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private static final String TAG = "AwContents";
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private static final String WEB_ARCHIVE_EXTENSION = ".mht";
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Used to avoid enabling zooming in / out if resulting zooming will
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // produce little visible difference.
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private static final float ZOOM_CONTROLS_EPSILON = 0.007f;
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * WebKit hit test related data strcutre. These are used to implement
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)     * getHitTestResult, requestFocusNodeHref, requestImageRef methods in WebView.
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)     * All values should be updated together. The native counterpart is
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * AwHitTestData.
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)     */
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    public static class HitTestData {
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // Used in getHitTestResult.
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        public int hitTestResultType;
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        public String hitTestResultExtraData;
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // Used in requestFocusNodeHref (all three) and requestImageRef (only imgSrc).
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        public String href;
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        public String anchorText;
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        public String imgSrc;
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)     * Interface that consumers of {@link AwContents} must implement to allow the proper
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)     * dispatching of view methods through the containing view.
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    public interface InternalAccessDelegate extends ContentViewCore.InternalAccessDelegate {
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        /**
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         * @see View#overScrollBy(int, int, int, int, int, int, int, int, boolean);
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         */
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        void overScrollBy(int deltaX, int deltaY,
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                int scrollX, int scrollY,
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                int scrollRangeX, int scrollRangeY,
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                int maxOverScrollX, int maxOverScrollY,
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                boolean isTouchEvent);
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        /**
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         * @see View#scrollTo(int, int)
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         */
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        void super_scrollTo(int scrollX, int scrollY);
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        /**
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         * @see View#setMeasuredDimension(int, int)
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         */
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        void setMeasuredDimension(int measuredWidth, int measuredHeight);
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        /**
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         * @see View#getScrollBarStyle()
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         */
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        int super_getScrollBarStyle();
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        /**
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         * Requests a callback on the native DrawGL method (see getAwDrawGLFunction)
132effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         * if called from within onDraw, |canvas| will be non-null and hardware accelerated.
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         * otherwise, |canvas| will be null, and the container view itself will be hardware
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         * accelerated.
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         *
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         * @return false indicates the GL draw request was not accepted, and the caller
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         *         should fallback to the SW path.
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         */
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        boolean requestDrawGL(Canvas canvas);
140effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
141effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
142effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private long mNativeAwContents;
143effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private final AwBrowserContext mBrowserContext;
144effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private final ViewGroup mContainerView;
145effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private ContentViewCore mContentViewCore;
146effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private final AwContentsClient mContentsClient;
147effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private final AwContentViewClient mContentViewClient;
148effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private final AwContentsClientBridge mContentsClientBridge;
149effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private final AwWebContentsDelegate mWebContentsDelegate;
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private final AwContentsIoThreadClient mIoThreadClient;
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private final InterceptNavigationDelegateImpl mInterceptNavigationDelegate;
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private final InternalAccessDelegate mInternalAccessAdapter;
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private final AwLayoutSizer mLayoutSizer;
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private final AwZoomControls mZoomControls;
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private final AwScrollOffsetManager mScrollOffsetManager;
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private OverScrollGlow mOverScrollGlow;
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // This can be accessed on any thread after construction. See AwContentsIoThreadClient.
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private final AwSettings mSettings;
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private final ScrollAccessibilityHelper mScrollAccessibilityHelper;
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private boolean mIsPaused;
162effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private boolean mIsViewVisible;
163effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private boolean mIsWindowVisible;
164effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private boolean mIsAttachedToWindow;
165effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private Bitmap mFavicon;
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private boolean mHasRequestedVisitedHistoryFromClient;
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(boliu): This should be in a global context, not per webview.
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private final double mDIPScale;
16923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The base background color, i.e. not accounting for any CSS body from the current page.
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private int mBaseBackgroundColor = Color.WHITE;
1724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Must call nativeUpdateLastHitTestData first to update this before use.
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private final HitTestData mPossiblyStaleHitTestData = new HitTestData();
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private final DefaultVideoPosterRequestHandler mDefaultVideoPosterRequestHandler;
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Bound method for suppling Picture instances to the AwContentsClient. Will be null if the
1794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // picture listener API has not yet been enabled, or if it is using invalidation-only mode.
1804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    private Callable<Picture> mPictureListenerContentProvider;
1814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private boolean mContainerViewFocused;
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private boolean mWindowFocused;
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
18523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    // These come from the compositor and are updated synchronously (in contrast to the values in
18623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    // ContentViewCore, which are updated at end of every frame).
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private float mPageScaleFactor = 1.0f;
188ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    private float mMinPageScaleFactor = 1.0f;
189ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    private float mMaxPageScaleFactor = 1.0f;
19023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    private float mContentWidthDip;
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private float mContentHeightDip;
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
193ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    private AwAutofillManagerDelegate mAwAutofillManagerDelegate;
194ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
195ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    private ComponentCallbacks2 mComponentCallbacks;
1964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    private AwPdfExporter mAwPdfExporter;
198ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
199ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // This flag indicates that ShouldOverrideUrlNavigation should be posted
200ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // through the resourcethrottle. This is only used for popup windows.
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private boolean mDeferredShouldOverrideUrlLoadingIsPendingForPopup;
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private static final class DestroyRunnable implements Runnable {
204effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        private final long mNativeAwContents;
205effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        private DestroyRunnable(long nativeAwContents) {
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            mNativeAwContents = nativeAwContents;
20723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        }
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        @Override
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        public void run() {
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // This is a no-op if not currently attached.
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            nativeOnDetachedFromWindow(mNativeAwContents);
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            nativeDestroy(mNativeAwContents);
213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Reference to the active mNativeAwContents pointer while it is active use
217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // (ie before it is destroyed).
218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private CleanupReference mCleanupReference;
219f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
220f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // A list of references to native pointers where the Java counterpart has been
221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // destroyed, but are held here because they are waiting for onDetachFromWindow
222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // to release GL resources. This is cleared inside onDetachFromWindow.
223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private List<CleanupReference> mPendingDetachCleanupReferences;
224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    //--------------------------------------------------------------------------------------------
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private class IoThreadClientImpl implements AwContentsIoThreadClient {
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // All methods are called on the IO thread.
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        @Override
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        public int getCacheMode() {
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            return mSettings.getCacheMode();
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        @Override
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        public InterceptedRequestData shouldInterceptRequest(final String url,
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                boolean isMainFrame) {
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            InterceptedRequestData interceptedRequestData;
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            // Return the response directly if the url is default video poster url.
23923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            interceptedRequestData = mDefaultVideoPosterRequestHandler.shouldInterceptRequest(url);
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (interceptedRequestData != null) return interceptedRequestData;
24123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            interceptedRequestData = mContentsClient.shouldInterceptRequest(url);
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (interceptedRequestData == null) {
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                mContentsClient.getCallbackHelper().postOnLoadResource(url);
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            }
247effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (isMainFrame && interceptedRequestData != null &&
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    interceptedRequestData.getData() == null) {
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                // In this case the intercepted URLRequest job will simulate an empty response
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                // which doesn't trigger the onReceivedError callback. For WebViewClassic
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                // compatibility we synthesize that callback. http://crbug.com/180950
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                mContentsClient.getCallbackHelper().postOnReceivedError(
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        ErrorCodeConversionHelper.ERROR_UNKNOWN,
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        null /* filled in by the glue layer */, url);
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            }
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            return interceptedRequestData;
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
25923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
26023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        @Override
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        public boolean shouldBlockContentUrls() {
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            return !mSettings.getAllowContentAccess();
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        @Override
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        public boolean shouldBlockFileUrls() {
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            return !mSettings.getAllowFileAccess();
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        @Override
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        public boolean shouldBlockNetworkLoads() {
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            return mSettings.getBlockNetworkLoads();
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        @Override
27623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        public void onDownloadStart(String url,
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    String userAgent,
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    String contentDisposition,
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    String mimeType,
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    long contentLength) {
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            mContentsClient.getCallbackHelper().postOnDownloadStart(url, userAgent,
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    contentDisposition, mimeType, contentLength);
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        @Override
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        public void newLoginRequest(String realm, String account, String args) {
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            mContentsClient.getCallbackHelper().postOnReceivedLoginRequest(realm, account, args);
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    //--------------------------------------------------------------------------------------------
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // When the navigation is for a newly created WebView (i.e. a popup), intercept the navigation
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // here for implementing shouldOverrideUrlLoading. This is to send the shouldOverrideUrlLoading
294effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // callback to the correct WebViewClient that is associated with the WebView.
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Otherwise, use this delegate only to post onPageStarted messages.
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    //
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We are not using WebContentsObserver.didStartLoading because of stale URLs, out of order
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // onPageStarted's and double onPageStarted's.
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    //
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private class InterceptNavigationDelegateImpl implements InterceptNavigationDelegate {
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        @Override
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        public boolean shouldIgnoreNavigation(NavigationParams navigationParams) {
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            final String url = navigationParams.url;
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            boolean ignoreNavigation = false;
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (mDeferredShouldOverrideUrlLoadingIsPendingForPopup) {
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                mDeferredShouldOverrideUrlLoadingIsPendingForPopup = false;
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                // If this is used for all navigations in future, cases for application initiated
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                // load, redirect and backforward should also be filtered out.
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                if (!navigationParams.isPost) {
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    ignoreNavigation = mContentsClient.shouldOverrideUrlLoading(url);
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                }
312a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            }
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // The shouldOverrideUrlLoading call might have resulted in posting messages to the
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            // UI thread. Using sendMessage here (instead of calling onPageStarted directly)
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            // will allow those to run in order.
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (!ignoreNavigation) {
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                mContentsClient.getCallbackHelper().postOnPageStarted(url);
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            }
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            return ignoreNavigation;
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    //--------------------------------------------------------------------------------------------
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private class AwLayoutSizerDelegate implements AwLayoutSizer.Delegate {
32523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        @Override
326effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        public void requestLayout() {
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            mContainerView.requestLayout();
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        @Override
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        public void setMeasuredDimension(int measuredWidth, int measuredHeight) {
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            mInternalAccessAdapter.setMeasuredDimension(measuredWidth, measuredHeight);
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        @Override
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        public void setFixedLayoutSize(int widthDip, int heightDip) {
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (mNativeAwContents == 0) return;
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            nativeSetFixedLayoutSize(mNativeAwContents, widthDip, heightDip);
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        @Override
34223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        public boolean isLayoutParamsHeightWrapContent() {
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            return mContainerView.getLayoutParams() != null &&
344868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                mContainerView.getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT;
345868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        }
346868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
347868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
348868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    //--------------------------------------------------------------------------------------------
349868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    private class AwScrollOffsetManagerDelegate implements AwScrollOffsetManager.Delegate {
350868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        @Override
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        public void overScrollContainerViewBy(int deltaX, int deltaY, int scrollX, int scrollY,
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                int scrollRangeX, int scrollRangeY, boolean isTouchEvent) {
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            mInternalAccessAdapter.overScrollBy(deltaX, deltaY, scrollX, scrollY,
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    scrollRangeX, scrollRangeY, 0, 0, isTouchEvent);
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        @Override
358effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        public void scrollContainerViewTo(int x, int y) {
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            mInternalAccessAdapter.super_scrollTo(x, y);
36023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        }
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
36223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        @Override
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        public void scrollNativeTo(int x, int y) {
36423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            if (mNativeAwContents == 0) return;
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            nativeScrollTo(mNativeAwContents, x, y);
36623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        }
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        @Override
3694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        public int getContainerViewScrollX() {
370            return mContainerView.getScrollX();
371        }
372
373        @Override
374        public int getContainerViewScrollY() {
375            return mContainerView.getScrollY();
376        }
377
378        @Override
379        public void invalidate() {
380            mContainerView.invalidate();
381        }
382    }
383
384    //--------------------------------------------------------------------------------------------
385    private class AwGestureStateListener extends GestureStateListener {
386        @Override
387        public void onPinchStarted() {
388            // While it's possible to re-layout the view during a pinch gesture, the effect is very
389            // janky (especially that the page scale update notification comes from the renderer
390            // main thread, not from the impl thread, so it's usually out of sync with what's on
391            // screen). It's also quite expensive to do a re-layout, so we simply postpone
392            // re-layout for the duration of the gesture. This is compatible with what
393            // WebViewClassic does.
394            mLayoutSizer.freezeLayoutRequests();
395        }
396
397        @Override
398        public void onPinchEnded() {
399            mLayoutSizer.unfreezeLayoutRequests();
400        }
401
402        @Override
403        public void onFlingCancelGesture() {
404            mScrollOffsetManager.onFlingCancelGesture();
405        }
406
407        @Override
408        public void onUnhandledFlingStartEvent(int velocityX, int velocityY) {
409            mScrollOffsetManager.onUnhandledFlingStartEvent(velocityX, velocityY);
410        }
411
412        @Override
413        public void onScrollUpdateGestureConsumed() {
414            mScrollAccessibilityHelper.postViewScrolledAccessibilityEventCallback();
415        }
416    }
417
418    //--------------------------------------------------------------------------------------------
419    private class AwComponentCallbacks implements ComponentCallbacks2 {
420        @Override
421        public void onTrimMemory(int level) {
422            if (mNativeAwContents == 0) return;
423            nativeTrimMemory(mNativeAwContents, level);
424        }
425
426        @Override
427        public void onLowMemory() {}
428
429        @Override
430        public void onConfigurationChanged(Configuration configuration) {}
431    };
432
433    //--------------------------------------------------------------------------------------------
434    private class AwLayoutChangeListener implements View.OnLayoutChangeListener {
435        @Override
436        public void onLayoutChange(View v, int left, int top, int right, int bottom,
437                int oldLeft, int oldTop, int oldRight, int oldBottom) {
438            assert v == mContainerView;
439            mLayoutSizer.onLayoutChange();
440        }
441    }
442
443    /**
444     * @param browserContext the browsing context to associate this view contents with.
445     * @param containerView the view-hierarchy item this object will be bound to.
446     * @param internalAccessAdapter to access private methods on containerView.
447     * @param contentsClient will receive API callbacks from this WebView Contents.
448     * @param awSettings AwSettings instance used to configure the AwContents.
449     *
450     * This constructor uses the default view sizing policy.
451     */
452    public AwContents(AwBrowserContext browserContext, ViewGroup containerView,
453            InternalAccessDelegate internalAccessAdapter, AwContentsClient contentsClient,
454            AwSettings awSettings) {
455        this(browserContext, containerView, internalAccessAdapter, contentsClient, awSettings,
456                new AwLayoutSizer());
457    }
458
459    /**
460     * @param layoutSizer the AwLayoutSizer instance implementing the sizing policy for the view.
461     *
462     * This version of the constructor is used in test code to inject test versions of the above
463     * documented classes.
464     */
465    public AwContents(AwBrowserContext browserContext, ViewGroup containerView,
466            InternalAccessDelegate internalAccessAdapter, AwContentsClient contentsClient,
467            AwSettings settings, AwLayoutSizer layoutSizer) {
468        mBrowserContext = browserContext;
469        mContainerView = containerView;
470        mInternalAccessAdapter = internalAccessAdapter;
471        mContentsClient = contentsClient;
472        mContentViewClient = new AwContentViewClient(contentsClient, settings);
473        mLayoutSizer = layoutSizer;
474        mSettings = settings;
475        mDIPScale = DeviceDisplayInfo.create(mContainerView.getContext()).getDIPScale();
476        mLayoutSizer.setDelegate(new AwLayoutSizerDelegate());
477        mLayoutSizer.setDIPScale(mDIPScale);
478        mWebContentsDelegate = new AwWebContentsDelegateAdapter(contentsClient, mContainerView);
479        mContentsClientBridge = new AwContentsClientBridge(contentsClient);
480        mZoomControls = new AwZoomControls(this);
481        mIoThreadClient = new IoThreadClientImpl();
482        mInterceptNavigationDelegate = new InterceptNavigationDelegateImpl();
483
484        AwSettings.ZoomSupportChangeListener zoomListener =
485                new AwSettings.ZoomSupportChangeListener() {
486                    @Override
487                    public void onGestureZoomSupportChanged(
488                            boolean supportsDoubleTapZoom, boolean supportsMultiTouchZoom) {
489                        mContentViewCore.updateDoubleTapSupport(supportsDoubleTapZoom);
490                        mContentViewCore.updateMultiTouchZoomSupport(supportsMultiTouchZoom);
491                    }
492
493                };
494        mSettings.setZoomListener(zoomListener);
495        mDefaultVideoPosterRequestHandler = new DefaultVideoPosterRequestHandler(mContentsClient);
496        mSettings.setDefaultVideoPosterURL(
497                mDefaultVideoPosterRequestHandler.getDefaultVideoPosterURL());
498        mSettings.setDIPScale(mDIPScale);
499        mScrollOffsetManager = new AwScrollOffsetManager(new AwScrollOffsetManagerDelegate(),
500                new OverScroller(mContainerView.getContext()));
501        mScrollAccessibilityHelper = new ScrollAccessibilityHelper(mContainerView);
502
503        setOverScrollMode(mContainerView.getOverScrollMode());
504        setScrollBarStyle(mInternalAccessAdapter.super_getScrollBarStyle());
505        mContainerView.addOnLayoutChangeListener(new AwLayoutChangeListener());
506
507        setNewAwContents(nativeInit(mBrowserContext));
508
509        onVisibilityChanged(mContainerView, mContainerView.getVisibility());
510        onWindowVisibilityChanged(mContainerView.getWindowVisibility());
511    }
512
513    private static ContentViewCore createAndInitializeContentViewCore(ViewGroup containerView,
514            InternalAccessDelegate internalDispatcher, int nativeWebContents,
515            GestureStateListener gestureStateListener,
516            ContentViewClient contentViewClient,
517            ContentViewCore.ZoomControlsDelegate zoomControlsDelegate) {
518        Context context = containerView.getContext();
519        ContentViewCore contentViewCore = new ContentViewCore(context);
520        contentViewCore.initialize(containerView, internalDispatcher, nativeWebContents,
521                context instanceof Activity ?
522                        new ActivityWindowAndroid((Activity) context) :
523                        new WindowAndroid(context.getApplicationContext()));
524        contentViewCore.addGestureStateListener(gestureStateListener);
525        contentViewCore.setContentViewClient(contentViewClient);
526        contentViewCore.setZoomControlsDelegate(zoomControlsDelegate);
527        return contentViewCore;
528    }
529
530    /**
531     * Common initialization routine for adopting a native AwContents instance into this
532     * java instance.
533     *
534     * TAKE CARE! This method can get called multiple times per java instance. Code accordingly.
535     * ^^^^^^^^^  See the native class declaration for more details on relative object lifetimes.
536     */
537    private void setNewAwContents(long newAwContentsPtr) {
538        if (mNativeAwContents != 0) {
539            destroy();
540            mContentViewCore = null;
541        }
542
543        assert mNativeAwContents == 0 && mCleanupReference == null && mContentViewCore == null;
544
545        mNativeAwContents = newAwContentsPtr;
546        // TODO(joth): when the native and java counterparts of AwBrowserContext are hooked up to
547        // each other, we should update |mBrowserContext| according to the newly received native
548        // WebContent's browser context.
549
550        // The native side object has been bound to this java instance, so now is the time to
551        // bind all the native->java relationships.
552        mCleanupReference = new CleanupReference(this, new DestroyRunnable(mNativeAwContents));
553
554        int nativeWebContents = nativeGetWebContents(mNativeAwContents);
555        mContentViewCore = createAndInitializeContentViewCore(
556                mContainerView, mInternalAccessAdapter, nativeWebContents,
557                new AwGestureStateListener(), mContentViewClient, mZoomControls);
558        nativeSetJavaPeers(mNativeAwContents, this, mWebContentsDelegate, mContentsClientBridge,
559                mIoThreadClient, mInterceptNavigationDelegate);
560        mContentsClient.installWebContentsObserver(mContentViewCore);
561        mSettings.setWebContents(nativeWebContents);
562        nativeSetDipScale(mNativeAwContents, (float) mDIPScale);
563        updateGlobalVisibleRect();
564
565        // The only call to onShow. onHide should never be called.
566        mContentViewCore.onShow();
567    }
568
569    /**
570     * Called on the "source" AwContents that is opening the popup window to
571     * provide the AwContents to host the pop up content.
572     */
573    public void supplyContentsForPopup(AwContents newContents) {
574        int popupNativeAwContents = nativeReleasePopupAwContents(mNativeAwContents);
575        if (popupNativeAwContents == 0) {
576            Log.w(TAG, "Popup WebView bind failed: no pending content.");
577            if (newContents != null) newContents.destroy();
578            return;
579        }
580        if (newContents == null) {
581            nativeDestroy(popupNativeAwContents);
582            return;
583        }
584
585        newContents.receivePopupContents(popupNativeAwContents);
586    }
587
588    // Recap: supplyContentsForPopup() is called on the parent window's content, this method is
589    // called on the popup window's content.
590    private void receivePopupContents(int popupNativeAwContents) {
591        mDeferredShouldOverrideUrlLoadingIsPendingForPopup = true;
592        // Save existing view state.
593        final boolean wasAttached = mIsAttachedToWindow;
594        final boolean wasViewVisible = mIsViewVisible;
595        final boolean wasWindowVisible = mIsWindowVisible;
596        final boolean wasPaused = mIsPaused;
597        final boolean wasFocused = mContainerViewFocused;
598        final boolean wasWindowFocused = mWindowFocused;
599
600        // Properly clean up existing mContentViewCore and mNativeAwContents.
601        if (wasFocused) onFocusChanged(false, 0, null);
602        if (wasWindowFocused) onWindowFocusChanged(false);
603        if (wasViewVisible) setViewVisibilityInternal(false);
604        if (wasWindowVisible) setWindowVisibilityInternal(false);
605        if (!wasPaused) onPause();
606        // Not calling onDetachedFromWindow here because native code requires GL context to release
607        // GL resources. This case is properly handled when destroy is called while still attached
608        // to window.
609
610        setNewAwContents(popupNativeAwContents);
611
612        // Finally refresh all view state for mContentViewCore and mNativeAwContents.
613        if (!wasPaused) onResume();
614        if (wasAttached) onAttachedToWindow();
615        onSizeChanged(mContainerView.getWidth(), mContainerView.getHeight(), 0, 0);
616        if (wasWindowVisible) setWindowVisibilityInternal(true);
617        if (wasViewVisible) setViewVisibilityInternal(true);
618        if (wasWindowFocused) onWindowFocusChanged(wasWindowFocused);
619        if (wasFocused) onFocusChanged(true, 0, null);
620    }
621
622    /**
623     * Deletes the native counterpart of this object. Normally happens immediately,
624     * but maybe deferred until the appropriate time for GL resource cleanup. Either way
625     * this is transparent to the caller: after this function returns the object is
626     * effectively dead and methods are no-ops.
627     */
628    public void destroy() {
629        if (mCleanupReference != null) {
630            // We explicitly do not null out the mContentViewCore reference here
631            // because ContentViewCore already has code to deal with the case
632            // methods are called on it after it's been destroyed, and other
633            // code relies on AwContents.mContentViewCore to be non-null.
634            mContentViewCore.destroy();
635            mNativeAwContents = 0;
636
637            // We cannot destroy immediately if we are still attached to the window.
638            // Instead if we make sure to null out the native pointer so there is no more native
639            // calls, and delay the actual destroy until onDetachedFromWindow.
640            if (mIsAttachedToWindow) {
641                if (mPendingDetachCleanupReferences == null) {
642                    mPendingDetachCleanupReferences = new ArrayList<CleanupReference>();
643                }
644                mPendingDetachCleanupReferences.add(mCleanupReference);
645            } else {
646                mCleanupReference.cleanupNow();
647            }
648            mCleanupReference = null;
649        }
650
651        assert !mContentViewCore.isAlive();
652        assert mNativeAwContents == 0;
653    }
654
655    @VisibleForTesting
656    public ContentViewCore getContentViewCore() {
657        return mContentViewCore;
658    }
659
660    // Can be called from any thread.
661    public AwSettings getSettings() {
662        return mSettings;
663    }
664
665    public AwPdfExporter getPdfExporter() {
666        // mNativeAwContents can be null, due to destroy().
667        if (mNativeAwContents == 0) {
668            return null;
669        }
670        if (mAwPdfExporter == null) {
671            mAwPdfExporter = new AwPdfExporter(mContainerView);
672            nativeCreatePdfExporter(mNativeAwContents, mAwPdfExporter);
673        }
674        return mAwPdfExporter;
675    }
676
677    public static void setAwDrawSWFunctionTable(int functionTablePointer) {
678        nativeSetAwDrawSWFunctionTable(functionTablePointer);
679    }
680
681    public static void setAwDrawGLFunctionTable(int functionTablePointer) {
682        nativeSetAwDrawGLFunctionTable(functionTablePointer);
683    }
684
685    public static int getAwDrawGLFunction() {
686        return nativeGetAwDrawGLFunction();
687    }
688
689    public static void setShouldDownloadFavicons() {
690        nativeSetShouldDownloadFavicons();
691    }
692
693    /**
694     * Intended for test code.
695     * @return the number of native instances of this class.
696     */
697    @VisibleForTesting
698    public static int getNativeInstanceCount() {
699        return nativeGetNativeInstanceCount();
700    }
701
702    public int getAwDrawGLViewContext() {
703        // Only called during early construction, so client should not have had a chance to
704        // call destroy yet.
705        assert mNativeAwContents != 0;
706
707        // Using the native pointer as the returned viewContext. This is matched by the
708        // reinterpret_cast back to BrowserViewRenderer pointer in the native DrawGLFunction.
709        return nativeGetAwDrawGLViewContext(mNativeAwContents);
710    }
711
712    // This is only to avoid heap allocations inside updateGLobalVisibleRect. It should treated
713    // as a local variable in the function and not used anywhere else.
714    private static final Rect sLocalGlobalVisibleRect = new Rect();
715
716    @CalledByNative
717    private void updateGlobalVisibleRect() {
718        if (mNativeAwContents == 0) return;
719        if (!mContainerView.getGlobalVisibleRect(sLocalGlobalVisibleRect)) {
720            sLocalGlobalVisibleRect.setEmpty();
721        }
722
723        nativeSetGlobalVisibleRect(mNativeAwContents, sLocalGlobalVisibleRect.left,
724                sLocalGlobalVisibleRect.top, sLocalGlobalVisibleRect.right,
725                sLocalGlobalVisibleRect.bottom);
726    }
727
728    //--------------------------------------------------------------------------------------------
729    //  WebView[Provider] method implementations (where not provided by ContentViewCore)
730    //--------------------------------------------------------------------------------------------
731
732    // Only valid within onDraw().
733    private final Rect mClipBoundsTemporary = new Rect();
734
735    public void onDraw(Canvas canvas) {
736        if (mNativeAwContents == 0) {
737            canvas.drawColor(getEffectiveBackgroundColor());
738            return;
739        }
740
741        mScrollOffsetManager.syncScrollOffsetFromOnDraw();
742        canvas.getClipBounds(mClipBoundsTemporary);
743
744        if (!nativeOnDraw(mNativeAwContents, canvas, canvas.isHardwareAccelerated(),
745                mContainerView.getScrollX(), mContainerView.getScrollY(),
746                mClipBoundsTemporary.left, mClipBoundsTemporary.top,
747                mClipBoundsTemporary.right, mClipBoundsTemporary.bottom)) {
748            // Can happen during initialization when compositor is not set up. Or when clearView
749            // is in effect. Just draw background color instead.
750            canvas.drawColor(getEffectiveBackgroundColor());
751        }
752
753        if (mOverScrollGlow != null && mOverScrollGlow.drawEdgeGlows(canvas,
754                    mScrollOffsetManager.computeMaximumHorizontalScrollOffset(),
755                    mScrollOffsetManager.computeMaximumVerticalScrollOffset())) {
756            mContainerView.invalidate();
757        }
758    }
759
760    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
761        mLayoutSizer.onMeasure(widthMeasureSpec, heightMeasureSpec);
762    }
763
764    public int getContentHeightCss() {
765        return (int) Math.ceil(mContentHeightDip);
766    }
767
768    public int getContentWidthCss() {
769        return (int) Math.ceil(mContentWidthDip);
770    }
771
772    public Picture capturePicture() {
773        if (mNativeAwContents == 0) return null;
774        return new AwPicture(nativeCapturePicture(mNativeAwContents,
775                    mScrollOffsetManager.computeHorizontalScrollRange(),
776                    mScrollOffsetManager.computeVerticalScrollRange()));
777    }
778
779    public void clearView() {
780        if (mNativeAwContents == 0) return;
781        nativeClearView(mNativeAwContents);
782    }
783
784    /**
785     * Enable the onNewPicture callback.
786     * @param enabled Flag to enable the callback.
787     * @param invalidationOnly Flag to call back only on invalidation without providing a picture.
788     */
789    public void enableOnNewPicture(boolean enabled, boolean invalidationOnly) {
790        if (mNativeAwContents == 0) return;
791        if (invalidationOnly) {
792            mPictureListenerContentProvider = null;
793        } else if (enabled && mPictureListenerContentProvider == null) {
794            mPictureListenerContentProvider = new Callable<Picture>() {
795                @Override
796                public Picture call() {
797                    return capturePicture();
798                }
799            };
800        }
801        nativeEnableOnNewPicture(mNativeAwContents, enabled);
802    }
803
804    public void findAllAsync(String searchString) {
805        if (mNativeAwContents == 0) return;
806        nativeFindAllAsync(mNativeAwContents, searchString);
807    }
808
809    public void findNext(boolean forward) {
810        if (mNativeAwContents == 0) return;
811        nativeFindNext(mNativeAwContents, forward);
812    }
813
814    public void clearMatches() {
815        if (mNativeAwContents == 0) return;
816        nativeClearMatches(mNativeAwContents);
817    }
818
819    /**
820     * @return load progress of the WebContents.
821     */
822    public int getMostRecentProgress() {
823        // WebContentsDelegateAndroid conveniently caches the most recent notified value for us.
824        return mWebContentsDelegate.getMostRecentProgress();
825    }
826
827    public Bitmap getFavicon() {
828        return mFavicon;
829    }
830
831    private void requestVisitedHistoryFromClient() {
832        ValueCallback<String[]> callback = new ValueCallback<String[]>() {
833            @Override
834            public void onReceiveValue(final String[] value) {
835                ThreadUtils.runOnUiThread(new Runnable() {
836                    @Override
837                    public void run() {
838                        if (mNativeAwContents == 0) return;
839                        nativeAddVisitedLinks(mNativeAwContents, value);
840                    }
841                });
842            }
843        };
844        mContentsClient.getVisitedHistory(callback);
845    }
846
847    /**
848     * Load url without fixing up the url string. Consumers of ContentView are responsible for
849     * ensuring the URL passed in is properly formatted (i.e. the scheme has been added if left
850     * off during user input).
851     *
852     * @param params Parameters for this load.
853     */
854    public void loadUrl(LoadUrlParams params) {
855        if (params.getLoadUrlType() == LoadUrlParams.LOAD_TYPE_DATA &&
856                !params.isBaseUrlDataScheme()) {
857            // This allows data URLs with a non-data base URL access to file:///android_asset/ and
858            // file:///android_res/ URLs. If AwSettings.getAllowFileAccess permits, it will also
859            // allow access to file:// URLs (subject to OS level permission checks).
860            params.setCanLoadLocalResources(true);
861        }
862
863        // If we are reloading the same url, then set transition type as reload.
864        if (params.getUrl() != null &&
865                params.getUrl().equals(mContentViewCore.getUrl()) &&
866                params.getTransitionType() == PageTransitionTypes.PAGE_TRANSITION_LINK) {
867                params.setTransitionType(PageTransitionTypes.PAGE_TRANSITION_RELOAD);
868        }
869        params.setTransitionType(
870                params.getTransitionType() | PageTransitionTypes.PAGE_TRANSITION_FROM_API);
871
872        // For WebView, always use the user agent override, which is set
873        // every time the user agent in AwSettings is modified.
874        params.setOverrideUserAgent(LoadUrlParams.UA_OVERRIDE_TRUE);
875
876        // We don't pass extra headers to the content layer, as WebViewClassic
877        // was adding them in a very narrow set of conditions. See http://crbug.com/306873
878        if (mNativeAwContents != 0) {
879            nativeSetExtraHeadersForUrl(
880                    mNativeAwContents, params.getUrl(), params.getExtraHttpRequestHeadersString());
881        }
882        params.setExtraHeaders(new HashMap<String, String>());
883
884        mContentViewCore.loadUrl(params);
885
886        // The behavior of WebViewClassic uses the populateVisitedLinks callback in WebKit.
887        // Chromium does not use this use code path and the best emulation of this behavior to call
888        // request visited links once on the first URL load of the WebView.
889        if (!mHasRequestedVisitedHistoryFromClient) {
890            mHasRequestedVisitedHistoryFromClient = true;
891            requestVisitedHistoryFromClient();
892        }
893
894        if (params.getLoadUrlType() == LoadUrlParams.LOAD_TYPE_DATA &&
895                params.getBaseUrl() != null) {
896            // Data loads with a base url will be resolved in Blink, and not cause an onPageStarted
897            // event to be sent. Sending the callback directly from here.
898            mContentsClient.getCallbackHelper().postOnPageStarted(params.getBaseUrl());
899        }
900    }
901
902    /**
903     * Get the URL of the current page.
904     *
905     * @return The URL of the current page or null if it's empty.
906     */
907    public String getUrl() {
908        String url =  mContentViewCore.getUrl();
909        if (url == null || url.trim().isEmpty()) return null;
910        return url;
911    }
912
913    public void requestFocus() {
914        if (mNativeAwContents == 0) return;
915        if (!mContainerView.isInTouchMode() && mSettings.shouldFocusFirstNode()) {
916            nativeFocusFirstNode(mNativeAwContents);
917        }
918    }
919
920    public void setBackgroundColor(int color) {
921        mBaseBackgroundColor = color;
922        if (mNativeAwContents != 0) nativeSetBackgroundColor(mNativeAwContents, color);
923    }
924
925    private int getEffectiveBackgroundColor() {
926        // Do not ask the ContentViewCore for the background color, as it will always
927        // report white prior to initial navigation or post destruction,  whereas we want
928        // to use the client supplied base value in those cases.
929        if (mNativeAwContents == 0 || !mContentsClient.isCachedRendererBackgroundColorValid()) {
930            return mBaseBackgroundColor;
931        }
932        return mContentsClient.getCachedRendererBackgroundColor();
933    }
934
935    public boolean isMultiTouchZoomSupported() {
936        return mSettings.supportsMultiTouchZoom();
937    }
938
939    public View getZoomControlsForTest() {
940        return mZoomControls.getZoomControlsViewForTest();
941    }
942
943    /**
944     * @see ContentViewCore#getContentSettings()
945     */
946    public ContentSettings getContentSettings() {
947        return mContentViewCore.getContentSettings();
948    }
949
950    /**
951     * @see View#setOverScrollMode(int)
952     */
953    public void setOverScrollMode(int mode) {
954        if (mode != View.OVER_SCROLL_NEVER) {
955            mOverScrollGlow = new OverScrollGlow(mContainerView);
956        } else {
957            mOverScrollGlow = null;
958        }
959    }
960
961    // TODO(mkosiba): In WebViewClassic these appear in some of the scroll extent calculation
962    // methods but toggling them has no visiual effect on the content (in other words the scrolling
963    // code behaves as if the scrollbar-related padding is in place but the onDraw code doesn't
964    // take that into consideration).
965    // http://crbug.com/269032
966    private boolean mOverlayHorizontalScrollbar = true;
967    private boolean mOverlayVerticalScrollbar = false;
968
969    /**
970     * @see View#setScrollBarStyle(int)
971     */
972    public void setScrollBarStyle(int style) {
973        if (style == View.SCROLLBARS_INSIDE_OVERLAY
974                || style == View.SCROLLBARS_OUTSIDE_OVERLAY) {
975            mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = true;
976        } else {
977            mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = false;
978        }
979    }
980
981    /**
982     * @see View#setHorizontalScrollbarOverlay(boolean)
983     */
984    public void setHorizontalScrollbarOverlay(boolean overlay) {
985        mOverlayHorizontalScrollbar = overlay;
986    }
987
988    /**
989     * @see View#setVerticalScrollbarOverlay(boolean)
990     */
991    public void setVerticalScrollbarOverlay(boolean overlay) {
992        mOverlayVerticalScrollbar = overlay;
993    }
994
995    /**
996     * @see View#overlayHorizontalScrollbar()
997     */
998    public boolean overlayHorizontalScrollbar() {
999        return mOverlayHorizontalScrollbar;
1000    }
1001
1002    /**
1003     * @see View#overlayVerticalScrollbar()
1004     */
1005    public boolean overlayVerticalScrollbar() {
1006        return mOverlayVerticalScrollbar;
1007    }
1008
1009    /**
1010     * Called by the embedder when the scroll offset of the containing view has changed.
1011     * @see View#onScrollChanged(int,int)
1012     */
1013    public void onContainerViewScrollChanged(int l, int t, int oldl, int oldt) {
1014        // A side-effect of View.onScrollChanged is that the scroll accessibility event being sent
1015        // by the base class implementation. This is completely hidden from the base classes and
1016        // cannot be prevented, which is why we need the code below.
1017        mScrollAccessibilityHelper.removePostedViewScrolledAccessibilityEventCallback();
1018        mScrollOffsetManager.onContainerViewScrollChanged(l, t);
1019    }
1020
1021    /**
1022     * Called by the embedder when the containing view is to be scrolled or overscrolled.
1023     * @see View#onOverScrolled(int,int,int,int)
1024     */
1025    public void onContainerViewOverScrolled(int scrollX, int scrollY, boolean clampedX,
1026            boolean clampedY) {
1027        int oldX = mContainerView.getScrollX();
1028        int oldY = mContainerView.getScrollY();
1029
1030        mScrollOffsetManager.onContainerViewOverScrolled(scrollX, scrollY, clampedX, clampedY);
1031
1032        if (mOverScrollGlow != null) {
1033            mOverScrollGlow.pullGlow(mContainerView.getScrollX(), mContainerView.getScrollY(),
1034                    oldX, oldY,
1035                    mScrollOffsetManager.computeMaximumHorizontalScrollOffset(),
1036                    mScrollOffsetManager.computeMaximumVerticalScrollOffset());
1037        }
1038    }
1039
1040    /**
1041     * @see android.webkit.WebView#requestChildRectangleOnScreen(View, Rect, boolean)
1042     */
1043    public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) {
1044        return mScrollOffsetManager.requestChildRectangleOnScreen(
1045                child.getLeft() - child.getScrollX(), child.getTop() - child.getScrollY(),
1046                rect, immediate);
1047    }
1048
1049    /**
1050     * @see View.computeScroll()
1051     */
1052    public void computeScroll() {
1053        mScrollOffsetManager.computeScrollAndAbsorbGlow(mOverScrollGlow);
1054    }
1055
1056    /**
1057     * @see View#computeHorizontalScrollRange()
1058     */
1059    public int computeHorizontalScrollRange() {
1060        return mScrollOffsetManager.computeHorizontalScrollRange();
1061    }
1062
1063    /**
1064     * @see View#computeHorizontalScrollOffset()
1065     */
1066    public int computeHorizontalScrollOffset() {
1067        return mScrollOffsetManager.computeHorizontalScrollOffset();
1068    }
1069
1070    /**
1071     * @see View#computeVerticalScrollRange()
1072     */
1073    public int computeVerticalScrollRange() {
1074        return mScrollOffsetManager.computeVerticalScrollRange();
1075    }
1076
1077    /**
1078     * @see View#computeVerticalScrollOffset()
1079     */
1080    public int computeVerticalScrollOffset() {
1081        return mScrollOffsetManager.computeVerticalScrollOffset();
1082    }
1083
1084    /**
1085     * @see View#computeVerticalScrollExtent()
1086     */
1087    public int computeVerticalScrollExtent() {
1088        return mScrollOffsetManager.computeVerticalScrollExtent();
1089    }
1090
1091    /**
1092     * @see android.webkit.WebView#stopLoading()
1093     */
1094    public void stopLoading() {
1095        mContentViewCore.stopLoading();
1096    }
1097
1098    /**
1099     * @see android.webkit.WebView#reload()
1100     */
1101    public void reload() {
1102        mContentViewCore.reload(true);
1103    }
1104
1105    /**
1106     * @see android.webkit.WebView#canGoBack()
1107     */
1108    public boolean canGoBack() {
1109        return mContentViewCore.canGoBack();
1110    }
1111
1112    /**
1113     * @see android.webkit.WebView#goBack()
1114     */
1115    public void goBack() {
1116        mContentViewCore.goBack();
1117    }
1118
1119    /**
1120     * @see android.webkit.WebView#canGoForward()
1121     */
1122    public boolean canGoForward() {
1123        return mContentViewCore.canGoForward();
1124    }
1125
1126    /**
1127     * @see android.webkit.WebView#goForward()
1128     */
1129    public void goForward() {
1130        mContentViewCore.goForward();
1131    }
1132
1133    /**
1134     * @see android.webkit.WebView#canGoBackOrForward(int)
1135     */
1136    public boolean canGoBackOrForward(int steps) {
1137        return mContentViewCore.canGoToOffset(steps);
1138    }
1139
1140    /**
1141     * @see android.webkit.WebView#goBackOrForward(int)
1142     */
1143    public void goBackOrForward(int steps) {
1144        mContentViewCore.goToOffset(steps);
1145    }
1146
1147    /**
1148     * @see android.webkit.WebView#pauseTimers()
1149     */
1150    public void pauseTimers() {
1151        ContentViewStatics.setWebKitSharedTimersSuspended(true);
1152    }
1153
1154    /**
1155     * @see android.webkit.WebView#resumeTimers()
1156     */
1157    public void resumeTimers() {
1158        ContentViewStatics.setWebKitSharedTimersSuspended(false);
1159    }
1160
1161    /**
1162     * @see android.webkit.WebView#onPause()
1163     */
1164    public void onPause() {
1165        if (mIsPaused || mNativeAwContents == 0) return;
1166        mIsPaused = true;
1167        nativeSetIsPaused(mNativeAwContents, mIsPaused);
1168    }
1169
1170    /**
1171     * @see android.webkit.WebView#onResume()
1172     */
1173    public void onResume() {
1174        if (!mIsPaused || mNativeAwContents == 0) return;
1175        mIsPaused = false;
1176        nativeSetIsPaused(mNativeAwContents, mIsPaused);
1177    }
1178
1179    /**
1180     * @see android.webkit.WebView#isPaused()
1181     */
1182    public boolean isPaused() {
1183        return mIsPaused;
1184    }
1185
1186    /**
1187     * @see android.webkit.WebView#onCreateInputConnection(EditorInfo)
1188     */
1189    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
1190        return mContentViewCore.onCreateInputConnection(outAttrs);
1191    }
1192
1193    /**
1194     * @see android.webkit.WebView#onKeyUp(int, KeyEvent)
1195     */
1196    public boolean onKeyUp(int keyCode, KeyEvent event) {
1197        return mContentViewCore.onKeyUp(keyCode, event);
1198    }
1199
1200    private boolean isDpadEvent(KeyEvent event) {
1201        if (event.getAction() == KeyEvent.ACTION_DOWN) {
1202            switch (event.getKeyCode()) {
1203                case KeyEvent.KEYCODE_DPAD_CENTER:
1204                case KeyEvent.KEYCODE_DPAD_DOWN:
1205                case KeyEvent.KEYCODE_DPAD_UP:
1206                case KeyEvent.KEYCODE_DPAD_LEFT:
1207                case KeyEvent.KEYCODE_DPAD_RIGHT:
1208                    return true;
1209            }
1210        }
1211        return false;
1212    }
1213
1214    /**
1215     * @see android.webkit.WebView#dispatchKeyEvent(KeyEvent)
1216     */
1217    public boolean dispatchKeyEvent(KeyEvent event) {
1218        if (isDpadEvent(event)) {
1219            mSettings.setSpatialNavigationEnabled(true);
1220        }
1221        return mContentViewCore.dispatchKeyEvent(event);
1222    }
1223
1224    /**
1225     * Clears the resource cache. Note that the cache is per-application, so this will clear the
1226     * cache for all WebViews used.
1227     *
1228     * @param includeDiskFiles if false, only the RAM cache is cleared
1229     */
1230    public void clearCache(boolean includeDiskFiles) {
1231        if (mNativeAwContents == 0) return;
1232        nativeClearCache(mNativeAwContents, includeDiskFiles);
1233    }
1234
1235    public void documentHasImages(Message message) {
1236        if (mNativeAwContents == 0) return;
1237        nativeDocumentHasImages(mNativeAwContents, message);
1238    }
1239
1240    public void saveWebArchive(
1241            final String basename, boolean autoname, final ValueCallback<String> callback) {
1242        if (!autoname) {
1243            saveWebArchiveInternal(basename, callback);
1244            return;
1245        }
1246        // If auto-generating the file name, handle the name generation on a background thread
1247        // as it will require I/O access for checking whether previous files existed.
1248        new AsyncTask<Void, Void, String>() {
1249            @Override
1250            protected String doInBackground(Void... params) {
1251                return generateArchiveAutoNamePath(getOriginalUrl(), basename);
1252            }
1253
1254            @Override
1255            protected void onPostExecute(String result) {
1256                saveWebArchiveInternal(result, callback);
1257            }
1258        }.execute();
1259    }
1260
1261    public String getOriginalUrl() {
1262        NavigationHistory history = mContentViewCore.getNavigationHistory();
1263        int currentIndex = history.getCurrentEntryIndex();
1264        if (currentIndex >= 0 && currentIndex < history.getEntryCount()) {
1265            return history.getEntryAtIndex(currentIndex).getOriginalUrl();
1266        }
1267        return null;
1268    }
1269
1270    /**
1271     * @see ContentViewCore#getNavigationHistory()
1272     */
1273    public NavigationHistory getNavigationHistory() {
1274        return mContentViewCore.getNavigationHistory();
1275    }
1276
1277    /**
1278     * @see android.webkit.WebView#getTitle()
1279     */
1280    public String getTitle() {
1281        return mContentViewCore.getTitle();
1282    }
1283
1284    /**
1285     * @see android.webkit.WebView#clearHistory()
1286     */
1287    public void clearHistory() {
1288        mContentViewCore.clearHistory();
1289    }
1290
1291    public String[] getHttpAuthUsernamePassword(String host, String realm) {
1292        return mBrowserContext.getHttpAuthDatabase(mContentViewCore.getContext())
1293                .getHttpAuthUsernamePassword(host, realm);
1294    }
1295
1296    public void setHttpAuthUsernamePassword(String host, String realm, String username,
1297            String password) {
1298        mBrowserContext.getHttpAuthDatabase(mContentViewCore.getContext())
1299                .setHttpAuthUsernamePassword(host, realm, username, password);
1300    }
1301
1302    /**
1303     * @see android.webkit.WebView#getCertificate()
1304     */
1305    public SslCertificate getCertificate() {
1306        if (mNativeAwContents == 0) return null;
1307        return SslUtil.getCertificateFromDerBytes(nativeGetCertificate(mNativeAwContents));
1308    }
1309
1310    /**
1311     * @see android.webkit.WebView#clearSslPreferences()
1312     */
1313    public void clearSslPreferences() {
1314        mContentViewCore.clearSslPreferences();
1315    }
1316
1317    /**
1318     * Method to return all hit test values relevant to public WebView API.
1319     * Note that this expose more data than needed for WebView.getHitTestResult.
1320     * Unsafely returning reference to mutable internal object to avoid excessive
1321     * garbage allocation on repeated calls.
1322     */
1323    public HitTestData getLastHitTestResult() {
1324        if (mNativeAwContents == 0) return null;
1325        nativeUpdateLastHitTestData(mNativeAwContents);
1326        return mPossiblyStaleHitTestData;
1327    }
1328
1329    /**
1330     * @see android.webkit.WebView#requestFocusNodeHref()
1331     */
1332    public void requestFocusNodeHref(Message msg) {
1333        if (msg == null || mNativeAwContents == 0) return;
1334
1335        nativeUpdateLastHitTestData(mNativeAwContents);
1336        Bundle data = msg.getData();
1337
1338        // In order to maintain compatibility with the old WebView's implementation,
1339        // the absolute (full) url is passed in the |url| field, not only the href attribute.
1340        // Note: HitTestData could be cleaned up at this point. See http://crbug.com/290992.
1341        data.putString("url", mPossiblyStaleHitTestData.href);
1342        data.putString("title", mPossiblyStaleHitTestData.anchorText);
1343        data.putString("src", mPossiblyStaleHitTestData.imgSrc);
1344        msg.setData(data);
1345        msg.sendToTarget();
1346    }
1347
1348    /**
1349     * @see android.webkit.WebView#requestImageRef()
1350     */
1351    public void requestImageRef(Message msg) {
1352        if (msg == null || mNativeAwContents == 0) return;
1353
1354        nativeUpdateLastHitTestData(mNativeAwContents);
1355        Bundle data = msg.getData();
1356        data.putString("url", mPossiblyStaleHitTestData.imgSrc);
1357        msg.setData(data);
1358        msg.sendToTarget();
1359    }
1360
1361    @VisibleForTesting
1362    public float getPageScaleFactor() {
1363        return mPageScaleFactor;
1364    }
1365
1366    /**
1367     * @see android.webkit.WebView#getScale()
1368     *
1369     * Please note that the scale returned is the page scale multiplied by
1370     * the screen density factor. See CTS WebViewTest.testSetInitialScale.
1371     */
1372    public float getScale() {
1373        return (float)(mPageScaleFactor * mDIPScale);
1374    }
1375
1376    /**
1377     * @see android.webkit.WebView#flingScroll(int, int)
1378     */
1379    public void flingScroll(int velocityX, int velocityY) {
1380        mScrollOffsetManager.flingScroll(velocityX, velocityY);
1381    }
1382
1383    /**
1384     * @see android.webkit.WebView#pageUp(boolean)
1385     */
1386    public boolean pageUp(boolean top) {
1387        return mScrollOffsetManager.pageUp(top);
1388    }
1389
1390    /**
1391     * @see android.webkit.WebView#pageDown(boolean)
1392     */
1393    public boolean pageDown(boolean bottom) {
1394        return mScrollOffsetManager.pageDown(bottom);
1395    }
1396
1397    /**
1398     * @see android.webkit.WebView#canZoomIn()
1399     */
1400    // This method uses the term 'zoom' for legacy reasons, but relates
1401    // to what chrome calls the 'page scale factor'.
1402    public boolean canZoomIn() {
1403        final float zoomInExtent = mMaxPageScaleFactor - mPageScaleFactor;
1404        return zoomInExtent > ZOOM_CONTROLS_EPSILON;
1405    }
1406
1407    /**
1408     * @see android.webkit.WebView#canZoomOut()
1409     */
1410    // This method uses the term 'zoom' for legacy reasons, but relates
1411    // to what chrome calls the 'page scale factor'.
1412    public boolean canZoomOut() {
1413        final float zoomOutExtent = mPageScaleFactor - mMinPageScaleFactor;
1414        return zoomOutExtent > ZOOM_CONTROLS_EPSILON;
1415    }
1416
1417    /**
1418     * @see android.webkit.WebView#zoomIn()
1419     */
1420    // This method uses the term 'zoom' for legacy reasons, but relates
1421    // to what chrome calls the 'page scale factor'.
1422    public boolean zoomIn() {
1423        if (!canZoomIn()) {
1424            return false;
1425        }
1426        return mContentViewCore.pinchByDelta(1.25f);
1427    }
1428
1429    /**
1430     * @see android.webkit.WebView#zoomOut()
1431     */
1432    // This method uses the term 'zoom' for legacy reasons, but relates
1433    // to what chrome calls the 'page scale factor'.
1434    public boolean zoomOut() {
1435        if (!canZoomOut()) {
1436            return false;
1437        }
1438        return mContentViewCore.pinchByDelta(0.8f);
1439    }
1440
1441    /**
1442     * @see android.webkit.WebView#invokeZoomPicker()
1443     */
1444    public void invokeZoomPicker() {
1445        mContentViewCore.invokeZoomPicker();
1446    }
1447
1448    /**
1449     * @see ContentViewCore.evaluateJavaScript(String, ContentViewCore.JavaScriptCallback)
1450     */
1451    public void evaluateJavaScript(String script, final ValueCallback<String> callback) {
1452        ContentViewCore.JavaScriptCallback jsCallback = null;
1453        if (callback != null) {
1454            jsCallback = new ContentViewCore.JavaScriptCallback() {
1455                @Override
1456                public void handleJavaScriptResult(String jsonResult) {
1457                    callback.onReceiveValue(jsonResult);
1458                }
1459            };
1460        }
1461
1462        mContentViewCore.evaluateJavaScript(script, jsCallback);
1463    }
1464
1465    /**
1466     * @see ContentViewCore.evaluateJavaScriptEvenIfNotYetNavigated(String)
1467     */
1468    public void evaluateJavaScriptEvenIfNotYetNavigated(String script) {
1469        mContentViewCore.evaluateJavaScriptEvenIfNotYetNavigated(script);
1470    }
1471
1472    //--------------------------------------------------------------------------------------------
1473    //  View and ViewGroup method implementations
1474    //--------------------------------------------------------------------------------------------
1475
1476    /**
1477     * @see android.webkit.View#onTouchEvent()
1478     */
1479    public boolean onTouchEvent(MotionEvent event) {
1480        if (mNativeAwContents == 0) return false;
1481
1482        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
1483            mSettings.setSpatialNavigationEnabled(false);
1484        }
1485
1486        mScrollOffsetManager.setProcessingTouchEvent(true);
1487        boolean rv = mContentViewCore.onTouchEvent(event);
1488        mScrollOffsetManager.setProcessingTouchEvent(false);
1489
1490        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
1491            int actionIndex = event.getActionIndex();
1492
1493            // Note this will trigger IPC back to browser even if nothing is hit.
1494            nativeRequestNewHitTestDataAt(mNativeAwContents,
1495                                          (int) Math.round(event.getX(actionIndex) / mDIPScale),
1496                                          (int) Math.round(event.getY(actionIndex) / mDIPScale));
1497        }
1498
1499        if (mOverScrollGlow != null && event.getActionMasked() == MotionEvent.ACTION_UP) {
1500            mOverScrollGlow.releaseAll();
1501        }
1502
1503        return rv;
1504    }
1505
1506    /**
1507     * @see android.view.View#onHoverEvent()
1508     */
1509    public boolean onHoverEvent(MotionEvent event) {
1510        return mContentViewCore.onHoverEvent(event);
1511    }
1512
1513    /**
1514     * @see android.view.View#onGenericMotionEvent()
1515     */
1516    public boolean onGenericMotionEvent(MotionEvent event) {
1517        return mContentViewCore.onGenericMotionEvent(event);
1518    }
1519
1520    /**
1521     * @see android.view.View#onConfigurationChanged()
1522     */
1523    public void onConfigurationChanged(Configuration newConfig) {
1524        mContentViewCore.onConfigurationChanged(newConfig);
1525    }
1526
1527    /**
1528     * @see android.view.View#onAttachedToWindow()
1529     *
1530     * Note that this is also called from receivePopupContents.
1531     */
1532    public void onAttachedToWindow() {
1533        if (mNativeAwContents == 0) return;
1534        mIsAttachedToWindow = true;
1535
1536        mContentViewCore.onAttachedToWindow();
1537        nativeOnAttachedToWindow(mNativeAwContents, mContainerView.getWidth(),
1538                mContainerView.getHeight());
1539        mSettings.setEnableSupportedHardwareAcceleratedFeatures(
1540            mContainerView.isHardwareAccelerated());
1541
1542        if (mComponentCallbacks != null) return;
1543        mComponentCallbacks = new AwComponentCallbacks();
1544        mContainerView.getContext().registerComponentCallbacks(mComponentCallbacks);
1545    }
1546
1547    /**
1548     * @see android.view.View#onDetachedFromWindow()
1549     */
1550    public void onDetachedFromWindow() {
1551        mIsAttachedToWindow = false;
1552        hideAutofillPopup();
1553        if (mNativeAwContents != 0) {
1554            nativeOnDetachedFromWindow(mNativeAwContents);
1555        }
1556
1557        mContentViewCore.onDetachedFromWindow();
1558
1559        mSettings.setEnableSupportedHardwareAcceleratedFeatures(false);
1560
1561        if (mComponentCallbacks != null) {
1562            mContainerView.getContext().unregisterComponentCallbacks(mComponentCallbacks);
1563            mComponentCallbacks = null;
1564        }
1565
1566        mScrollAccessibilityHelper.removePostedCallbacks();
1567
1568        if (mPendingDetachCleanupReferences != null) {
1569            for (int i = 0; i < mPendingDetachCleanupReferences.size(); ++i) {
1570                mPendingDetachCleanupReferences.get(i).cleanupNow();
1571            }
1572            mPendingDetachCleanupReferences = null;
1573        }
1574    }
1575
1576    /**
1577     * @see android.view.View#onWindowFocusChanged()
1578     */
1579    public void onWindowFocusChanged(boolean hasWindowFocus) {
1580        mWindowFocused = hasWindowFocus;
1581        mContentViewCore.onWindowFocusChanged(hasWindowFocus);
1582    }
1583
1584    /**
1585     * @see android.view.View#onFocusChanged()
1586     */
1587    public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
1588        mContainerViewFocused = focused;
1589        mContentViewCore.onFocusChanged(focused);
1590    }
1591
1592    /**
1593     * @see android.view.View#onSizeChanged()
1594     */
1595    public void onSizeChanged(int w, int h, int ow, int oh) {
1596        if (mNativeAwContents == 0) return;
1597        mScrollOffsetManager.setContainerViewSize(w, h);
1598        // The AwLayoutSizer needs to go first so that if we're in fixedLayoutSize mode the update
1599        // to enter fixedLayoutSize mode is sent before the first resize update.
1600        mLayoutSizer.onSizeChanged(w, h, ow, oh);
1601        mContentViewCore.onPhysicalBackingSizeChanged(w, h);
1602        mContentViewCore.onSizeChanged(w, h, ow, oh);
1603        nativeOnSizeChanged(mNativeAwContents, w, h, ow, oh);
1604    }
1605
1606    /**
1607     * @see android.view.View#onVisibilityChanged()
1608     */
1609    public void onVisibilityChanged(View changedView, int visibility) {
1610        boolean viewVisible = mContainerView.getVisibility() == View.VISIBLE;
1611        if (mIsViewVisible == viewVisible) return;
1612        setViewVisibilityInternal(viewVisible);
1613    }
1614
1615    /**
1616     * @see android.view.View#onWindowVisibilityChanged()
1617     */
1618    public void onWindowVisibilityChanged(int visibility) {
1619        boolean windowVisible = visibility == View.VISIBLE;
1620        if (mIsWindowVisible == windowVisible) return;
1621        setWindowVisibilityInternal(windowVisible);
1622    }
1623
1624    private void setViewVisibilityInternal(boolean visible) {
1625        mIsViewVisible = visible;
1626        if (mNativeAwContents == 0) return;
1627        nativeSetViewVisibility(mNativeAwContents, mIsViewVisible);
1628    }
1629
1630    private void setWindowVisibilityInternal(boolean visible) {
1631        mIsWindowVisible = visible;
1632        if (mNativeAwContents == 0) return;
1633        nativeSetWindowVisibility(mNativeAwContents, mIsWindowVisible);
1634    }
1635
1636    /**
1637     * Key for opaque state in bundle. Note this is only public for tests.
1638     */
1639    public static final String SAVE_RESTORE_STATE_KEY = "WEBVIEW_CHROMIUM_STATE";
1640
1641    /**
1642     * Save the state of this AwContents into provided Bundle.
1643     * @return False if saving state failed.
1644     */
1645    public boolean saveState(Bundle outState) {
1646        if (mNativeAwContents == 0 || outState == null) return false;
1647
1648        byte[] state = nativeGetOpaqueState(mNativeAwContents);
1649        if (state == null) return false;
1650
1651        outState.putByteArray(SAVE_RESTORE_STATE_KEY, state);
1652        return true;
1653    }
1654
1655    /**
1656     * Restore the state of this AwContents into provided Bundle.
1657     * @param inState Must be a bundle returned by saveState.
1658     * @return False if restoring state failed.
1659     */
1660    public boolean restoreState(Bundle inState) {
1661        if (mNativeAwContents == 0 || inState == null) return false;
1662
1663        byte[] state = inState.getByteArray(SAVE_RESTORE_STATE_KEY);
1664        if (state == null) return false;
1665
1666        boolean result = nativeRestoreFromOpaqueState(mNativeAwContents, state);
1667
1668        // The onUpdateTitle callback normally happens when a page is loaded,
1669        // but is optimized out in the restoreState case because the title is
1670        // already restored. See WebContentsImpl::UpdateTitleForEntry. So we
1671        // call the callback explicitly here.
1672        if (result) mContentsClient.onReceivedTitle(mContentViewCore.getTitle());
1673
1674        return result;
1675    }
1676
1677    /**
1678     * @see ContentViewCore#addPossiblyUnsafeJavascriptInterface(Object, String, Class)
1679     */
1680    public void addPossiblyUnsafeJavascriptInterface(Object object, String name,
1681            Class<? extends Annotation> requiredAnnotation) {
1682        mContentViewCore.addPossiblyUnsafeJavascriptInterface(object, name, requiredAnnotation);
1683    }
1684
1685    /**
1686     * @see android.webkit.WebView#removeJavascriptInterface(String)
1687     */
1688    public void removeJavascriptInterface(String interfaceName) {
1689        mContentViewCore.removeJavascriptInterface(interfaceName);
1690    }
1691
1692    /**
1693     * If native accessibility (not script injection) is enabled, and if this is
1694     * running on JellyBean or later, returns an AccessibilityNodeProvider that
1695     * implements native accessibility for this view. Returns null otherwise.
1696     * @return The AccessibilityNodeProvider, if available, or null otherwise.
1697     */
1698    public AccessibilityNodeProvider getAccessibilityNodeProvider() {
1699        return mContentViewCore.getAccessibilityNodeProvider();
1700    }
1701
1702    /**
1703     * @see android.webkit.WebView#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
1704     */
1705    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
1706        mContentViewCore.onInitializeAccessibilityNodeInfo(info);
1707    }
1708
1709    /**
1710     * @see android.webkit.WebView#onInitializeAccessibilityEvent(AccessibilityEvent)
1711     */
1712    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
1713        mContentViewCore.onInitializeAccessibilityEvent(event);
1714    }
1715
1716    public boolean supportsAccessibilityAction(int action) {
1717        return mContentViewCore.supportsAccessibilityAction(action);
1718    }
1719
1720    /**
1721     * @see android.webkit.WebView#performAccessibilityAction(int, Bundle)
1722     */
1723    public boolean performAccessibilityAction(int action, Bundle arguments) {
1724        return mContentViewCore.performAccessibilityAction(action, arguments);
1725    }
1726
1727    /**
1728     * @see android.webkit.WebView#clearFormData()
1729     */
1730    public void hideAutofillPopup() {
1731        if (mAwAutofillManagerDelegate != null)
1732            mAwAutofillManagerDelegate.hideAutofillPopup();
1733    }
1734
1735    public void setNetworkAvailable(boolean networkUp) {
1736        if (mNativeAwContents == 0) return;
1737        nativeSetJsOnlineProperty(mNativeAwContents, networkUp);
1738    }
1739
1740    //--------------------------------------------------------------------------------------------
1741    //  Methods called from native via JNI
1742    //--------------------------------------------------------------------------------------------
1743
1744    @CalledByNative
1745    private static void onDocumentHasImagesResponse(boolean result, Message message) {
1746        message.arg1 = result ? 1 : 0;
1747        message.sendToTarget();
1748    }
1749
1750    @CalledByNative
1751    private void onReceivedTouchIconUrl(String url, boolean precomposed) {
1752        mContentsClient.onReceivedTouchIconUrl(url, precomposed);
1753    }
1754
1755    @CalledByNative
1756    private void onReceivedIcon(Bitmap bitmap) {
1757        mContentsClient.onReceivedIcon(bitmap);
1758        mFavicon = bitmap;
1759    }
1760
1761    /** Callback for generateMHTML. */
1762    @CalledByNative
1763    private static void generateMHTMLCallback(
1764            String path, long size, ValueCallback<String> callback) {
1765        if (callback == null) return;
1766        callback.onReceiveValue(size < 0 ? null : path);
1767    }
1768
1769    @CalledByNative
1770    private void onReceivedHttpAuthRequest(AwHttpAuthHandler handler, String host, String realm) {
1771        mContentsClient.onReceivedHttpAuthRequest(handler, host, realm);
1772    }
1773
1774    private class AwGeolocationCallback implements GeolocationPermissions.Callback {
1775
1776        @Override
1777        public void invoke(final String origin, final boolean allow, final boolean retain) {
1778            ThreadUtils.runOnUiThread(new Runnable() {
1779                @Override
1780                public void run() {
1781                    if (retain) {
1782                        if (allow) {
1783                            mBrowserContext.getGeolocationPermissions().allow(origin);
1784                        } else {
1785                            mBrowserContext.getGeolocationPermissions().deny(origin);
1786                        }
1787                    }
1788                    if (mNativeAwContents == 0) return;
1789                    nativeInvokeGeolocationCallback(mNativeAwContents, allow, origin);
1790                }
1791            });
1792        }
1793    }
1794
1795    @CalledByNative
1796    private void onGeolocationPermissionsShowPrompt(String origin) {
1797        if (mNativeAwContents == 0) return;
1798        AwGeolocationPermissions permissions = mBrowserContext.getGeolocationPermissions();
1799        // Reject if geoloaction is disabled, or the origin has a retained deny
1800        if (!mSettings.getGeolocationEnabled()) {
1801            nativeInvokeGeolocationCallback(mNativeAwContents, false, origin);
1802            return;
1803        }
1804        // Allow if the origin has a retained allow
1805        if (permissions.hasOrigin(origin)) {
1806            nativeInvokeGeolocationCallback(mNativeAwContents, permissions.isOriginAllowed(origin),
1807                    origin);
1808            return;
1809        }
1810        mContentsClient.onGeolocationPermissionsShowPrompt(
1811                origin, new AwGeolocationCallback());
1812    }
1813
1814    @CalledByNative
1815    private void onGeolocationPermissionsHidePrompt() {
1816        mContentsClient.onGeolocationPermissionsHidePrompt();
1817    }
1818
1819    @CalledByNative
1820    public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
1821            boolean isDoneCounting) {
1822        mContentsClient.onFindResultReceived(activeMatchOrdinal, numberOfMatches, isDoneCounting);
1823    }
1824
1825    @CalledByNative
1826    public void onNewPicture() {
1827        // Don't call capturePicture() here but instead defer it until the posted task runs within
1828        // the callback helper, to avoid doubling back into the renderer compositor in the middle
1829        // of the notification it is sending up to here.
1830        mContentsClient.getCallbackHelper().postOnNewPicture(mPictureListenerContentProvider);
1831    }
1832
1833    // Called as a result of nativeUpdateLastHitTestData.
1834    @CalledByNative
1835    private void updateHitTestData(
1836            int type, String extra, String href, String anchorText, String imgSrc) {
1837        mPossiblyStaleHitTestData.hitTestResultType = type;
1838        mPossiblyStaleHitTestData.hitTestResultExtraData = extra;
1839        mPossiblyStaleHitTestData.href = href;
1840        mPossiblyStaleHitTestData.anchorText = anchorText;
1841        mPossiblyStaleHitTestData.imgSrc = imgSrc;
1842    }
1843
1844    @CalledByNative
1845    private boolean requestDrawGL(Canvas canvas) {
1846        return mInternalAccessAdapter.requestDrawGL(canvas);
1847    }
1848
1849    private static final boolean SUPPORTS_ON_ANIMATION =
1850            Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
1851
1852    @CalledByNative
1853    private void postInvalidateOnAnimation() {
1854        if (SUPPORTS_ON_ANIMATION) {
1855            mContainerView.postInvalidateOnAnimation();
1856        } else {
1857            mContainerView.postInvalidate();
1858        }
1859    }
1860
1861    @CalledByNative
1862    private int[] getLocationOnScreen() {
1863        int[] result = new int[2];
1864        mContainerView.getLocationOnScreen(result);
1865        return result;
1866    }
1867
1868    @CalledByNative
1869    private void onWebLayoutPageScaleFactorChanged(float webLayoutPageScaleFactor) {
1870        // This change notification comes from the renderer thread, not from the cc/ impl thread.
1871        mLayoutSizer.onPageScaleChanged(webLayoutPageScaleFactor);
1872    }
1873
1874    @CalledByNative
1875    private void onWebLayoutContentsSizeChanged(int widthCss, int heightCss) {
1876        // This change notification comes from the renderer thread, not from the cc/ impl thread.
1877        mLayoutSizer.onContentSizeChanged(widthCss, heightCss);
1878    }
1879
1880    @CalledByNative
1881    private void setMaxContainerViewScrollOffset(int maxX, int maxY) {
1882        mScrollOffsetManager.setMaxScrollOffset(maxX, maxY);
1883    }
1884
1885    @CalledByNative
1886    private void scrollContainerViewTo(int x, int y) {
1887        mScrollOffsetManager.scrollContainerViewTo(x, y);
1888    }
1889
1890    @CalledByNative
1891    private boolean isFlingActive() {
1892        return mScrollOffsetManager.isFlingActive();
1893    }
1894
1895    @CalledByNative
1896    private void setContentsSize(int widthDip, int heightDip) {
1897        mContentWidthDip = widthDip;
1898        mContentHeightDip = heightDip;
1899    }
1900
1901    @CalledByNative
1902    private void setPageScaleFactorAndLimits(
1903            float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor) {
1904        if (mPageScaleFactor == pageScaleFactor &&
1905            mMinPageScaleFactor == minPageScaleFactor &&
1906            mMaxPageScaleFactor == maxPageScaleFactor)
1907            return;
1908        mMinPageScaleFactor = minPageScaleFactor;
1909        mMaxPageScaleFactor = maxPageScaleFactor;
1910        if (mPageScaleFactor != pageScaleFactor) {
1911          float oldPageScaleFactor = mPageScaleFactor;
1912          mPageScaleFactor = pageScaleFactor;
1913          mContentsClient.getCallbackHelper().postOnScaleChangedScaled(
1914              (float)(oldPageScaleFactor * mDIPScale),
1915              (float)(mPageScaleFactor * mDIPScale));
1916        }
1917    }
1918
1919    @CalledByNative
1920    private void setAwAutofillManagerDelegate(AwAutofillManagerDelegate delegate) {
1921        mAwAutofillManagerDelegate = delegate;
1922        delegate.init(mContentViewCore);
1923    }
1924
1925    @CalledByNative
1926    private void didOverscroll(int deltaX, int deltaY) {
1927        if (mOverScrollGlow != null) {
1928            mOverScrollGlow.setOverScrollDeltas(deltaX, deltaY);
1929        }
1930
1931        mScrollOffsetManager.overScrollBy(deltaX, deltaY);
1932
1933        if (mOverScrollGlow != null && mOverScrollGlow.isAnimating()) {
1934            mContainerView.invalidate();
1935        }
1936    }
1937
1938    // -------------------------------------------------------------------------------------------
1939    // Helper methods
1940    // -------------------------------------------------------------------------------------------
1941
1942    private void saveWebArchiveInternal(String path, final ValueCallback<String> callback) {
1943        if (path == null || mNativeAwContents == 0) {
1944            ThreadUtils.runOnUiThread(new Runnable() {
1945                @Override
1946                public void run() {
1947                    callback.onReceiveValue(null);
1948                }
1949            });
1950        } else {
1951            nativeGenerateMHTML(mNativeAwContents, path, callback);
1952        }
1953    }
1954
1955    /**
1956     * Try to generate a pathname for saving an MHTML archive. This roughly follows WebView's
1957     * autoname logic.
1958     */
1959    private static String generateArchiveAutoNamePath(String originalUrl, String baseName) {
1960        String name = null;
1961        if (originalUrl != null && !originalUrl.isEmpty()) {
1962            try {
1963                String path = new URL(originalUrl).getPath();
1964                int lastSlash = path.lastIndexOf('/');
1965                if (lastSlash > 0) {
1966                    name = path.substring(lastSlash + 1);
1967                } else {
1968                    name = path;
1969                }
1970            } catch (MalformedURLException e) {
1971                // If it fails parsing the URL, we'll just rely on the default name below.
1972            }
1973        }
1974
1975        if (TextUtils.isEmpty(name)) name = "index";
1976
1977        String testName = baseName + name + WEB_ARCHIVE_EXTENSION;
1978        if (!new File(testName).exists()) return testName;
1979
1980        for (int i = 1; i < 100; i++) {
1981            testName = baseName + name + "-" + i + WEB_ARCHIVE_EXTENSION;
1982            if (!new File(testName).exists()) return testName;
1983        }
1984
1985        Log.e(TAG, "Unable to auto generate archive name for path: " + baseName);
1986        return null;
1987    }
1988
1989    public void extractSmartClipData(int x, int y, int width, int height) {
1990        mContentViewCore.extractSmartClipData(x, y, width, height);
1991    }
1992
1993    public void setSmartClipDataListener(ContentViewCore.SmartClipDataListener listener) {
1994        mContentViewCore.setSmartClipDataListener(listener);
1995    }
1996
1997    //--------------------------------------------------------------------------------------------
1998    //  Native methods
1999    //--------------------------------------------------------------------------------------------
2000
2001    private static native long nativeInit(AwBrowserContext browserContext);
2002    private static native void nativeDestroy(long nativeAwContents);
2003    private static native void nativeSetAwDrawSWFunctionTable(int functionTablePointer);
2004    private static native void nativeSetAwDrawGLFunctionTable(int functionTablePointer);
2005    private static native int nativeGetAwDrawGLFunction();
2006    private static native int nativeGetNativeInstanceCount();
2007    private static native void nativeSetShouldDownloadFavicons();
2008    private native void nativeSetJavaPeers(long nativeAwContents, AwContents awContents,
2009            AwWebContentsDelegate webViewWebContentsDelegate,
2010            AwContentsClientBridge contentsClientBridge,
2011            AwContentsIoThreadClient ioThreadClient,
2012            InterceptNavigationDelegate navigationInterceptionDelegate);
2013    private native int nativeGetWebContents(long nativeAwContents);
2014
2015    private native void nativeDocumentHasImages(long nativeAwContents, Message message);
2016    private native void nativeGenerateMHTML(
2017            long nativeAwContents, String path, ValueCallback<String> callback);
2018
2019    private native void nativeAddVisitedLinks(long nativeAwContents, String[] visitedLinks);
2020    private native boolean nativeOnDraw(long nativeAwContents, Canvas canvas,
2021            boolean isHardwareAccelerated, int scrollX, int scrollY,
2022            int clipLeft, int clipTop, int clipRight, int clipBottom);
2023    private native void nativeSetGlobalVisibleRect(long nativeAwContents, int visibleLeft,
2024            int visibleTop, int visibleRight, int visibleBottom);
2025    private native void nativeFindAllAsync(long nativeAwContents, String searchString);
2026    private native void nativeFindNext(long nativeAwContents, boolean forward);
2027    private native void nativeClearMatches(long nativeAwContents);
2028    private native void nativeClearCache(long nativeAwContents, boolean includeDiskFiles);
2029    private native byte[] nativeGetCertificate(long nativeAwContents);
2030
2031    // Coordinates in desity independent pixels.
2032    private native void nativeRequestNewHitTestDataAt(long nativeAwContents, int x, int y);
2033    private native void nativeUpdateLastHitTestData(long nativeAwContents);
2034
2035    private native void nativeOnSizeChanged(long nativeAwContents, int w, int h, int ow, int oh);
2036    private native void nativeScrollTo(long nativeAwContents, int x, int y);
2037    private native void nativeSetViewVisibility(long nativeAwContents, boolean visible);
2038    private native void nativeSetWindowVisibility(long nativeAwContents, boolean visible);
2039    private native void nativeSetIsPaused(long nativeAwContents, boolean paused);
2040    private native void nativeOnAttachedToWindow(long nativeAwContents, int w, int h);
2041    private static native void nativeOnDetachedFromWindow(long nativeAwContents);
2042    private native void nativeSetDipScale(long nativeAwContents, float dipScale);
2043    private native void nativeSetFixedLayoutSize(long nativeAwContents,
2044            int widthDip, int heightDip);
2045
2046    // Returns null if save state fails.
2047    private native byte[] nativeGetOpaqueState(long nativeAwContents);
2048
2049    // Returns false if restore state fails.
2050    private native boolean nativeRestoreFromOpaqueState(long nativeAwContents, byte[] state);
2051
2052    private native int nativeReleasePopupAwContents(long nativeAwContents);
2053    private native void nativeFocusFirstNode(long nativeAwContents);
2054    private native void nativeSetBackgroundColor(long nativeAwContents, int color);
2055
2056    private native int nativeGetAwDrawGLViewContext(long nativeAwContents);
2057    private native long nativeCapturePicture(long nativeAwContents, int width, int height);
2058    private native void nativeEnableOnNewPicture(long nativeAwContents, boolean enabled);
2059    private native void nativeClearView(long nativeAwContents);
2060    private native void nativeSetExtraHeadersForUrl(long nativeAwContents,
2061            String url, String extraHeaders);
2062
2063    private native void nativeInvokeGeolocationCallback(
2064            long nativeAwContents, boolean value, String requestingFrame);
2065
2066    private native void nativeSetJsOnlineProperty(long nativeAwContents, boolean networkUp);
2067
2068    private native void nativeTrimMemory(long nativeAwContents, int level);
2069
2070    private native void nativeCreatePdfExporter(long nativeAwContents, AwPdfExporter awPdfExporter);
2071}
2072