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