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