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