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