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