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.
5 package org.chromium.android_webview;
7 import android.annotation.SuppressLint;
8 import android.app.Activity;
9 import android.content.ComponentCallbacks2;
10 import android.content.Context;
11 import android.content.res.Configuration;
12 import android.graphics.Bitmap;
13 import android.graphics.Canvas;
14 import android.graphics.Color;
15 import android.graphics.Paint;
16 import android.graphics.Picture;
17 import android.graphics.Rect;
18 import android.net.Uri;
19 import android.net.http.SslCertificate;
20 import android.os.AsyncTask;
21 import android.os.Build;
22 import android.os.Bundle;
23 import android.os.Message;
24 import android.text.TextUtils;
25 import android.util.Log;
26 import android.util.Pair;
27 import android.view.KeyEvent;
28 import android.view.MotionEvent;
29 import android.view.View;
30 import android.view.ViewGroup;
31 import android.view.accessibility.AccessibilityEvent;
32 import android.view.accessibility.AccessibilityNodeInfo;
33 import android.view.accessibility.AccessibilityNodeProvider;
34 import android.view.inputmethod.EditorInfo;
35 import android.view.inputmethod.InputConnection;
36 import android.webkit.GeolocationPermissions;
37 import android.webkit.ValueCallback;
38 import android.widget.OverScroller;
40 import com.google.common.annotations.VisibleForTesting;
42 import org.chromium.android_webview.permission.AwPermissionRequest;
43 import org.chromium.base.CalledByNative;
44 import org.chromium.base.JNINamespace;
45 import org.chromium.base.ThreadUtils;
46 import org.chromium.components.navigation_interception.InterceptNavigationDelegate;
47 import org.chromium.components.navigation_interception.NavigationParams;
48 import org.chromium.content.browser.ContentSettings;
49 import org.chromium.content.browser.ContentViewClient;
50 import org.chromium.content.browser.ContentViewCore;
51 import org.chromium.content.browser.ContentViewStatics;
52 import org.chromium.content.browser.LoadUrlParams;
53 import org.chromium.content.browser.NavigationHistory;
54 import org.chromium.content.browser.PageTransitionTypes;
55 import org.chromium.content.browser.WebContentsObserverAndroid;
56 import org.chromium.content.common.CleanupReference;
57 import org.chromium.content_public.Referrer;
58 import org.chromium.content_public.browser.GestureStateListener;
59 import org.chromium.content_public.browser.JavaScriptCallback;
60 import org.chromium.ui.base.ActivityWindowAndroid;
61 import org.chromium.ui.base.WindowAndroid;
62 import org.chromium.ui.gfx.DeviceDisplayInfo;
65 import java.lang.annotation.Annotation;
66 import java.net.MalformedURLException;
68 import java.util.HashMap;
69 import java.util.Locale;
71 import java.util.concurrent.Callable;
74 * Exposes the native AwContents class, and together these classes wrap the ContentViewCore
75 * and Browser components that are required to implement Android WebView API. This is the
76 * primary entry point for the WebViewProvider implementation; it holds a 1:1 object
77 * relationship with application WebView instances.
78 * (We define this class independent of the hidden WebViewProvider interfaces, to allow
79 * continuous build & test in the open source SDK-based tree).
81 @JNINamespace("android_webview")
82 public class AwContents {
83 private static final String TAG = "AwContents";
85 private static final String WEB_ARCHIVE_EXTENSION = ".mht";
87 // Used to avoid enabling zooming in / out if resulting zooming will
88 // produce little visible difference.
89 private static final float ZOOM_CONTROLS_EPSILON = 0.007f;
92 * WebKit hit test related data strcutre. These are used to implement
93 * getHitTestResult, requestFocusNodeHref, requestImageRef methods in WebView.
94 * All values should be updated together. The native counterpart is
97 public static class HitTestData {
98 // Used in getHitTestResult.
99 public int hitTestResultType;
100 public String hitTestResultExtraData;
102 // Used in requestFocusNodeHref (all three) and requestImageRef (only imgSrc).
104 public String anchorText;
105 public String imgSrc;
109 * Interface that consumers of {@link AwContents} must implement to allow the proper
110 * dispatching of view methods through the containing view.
112 public interface InternalAccessDelegate extends ContentViewCore.InternalAccessDelegate {
115 * @see View#overScrollBy(int, int, int, int, int, int, int, int, boolean);
117 void overScrollBy(int deltaX, int deltaY,
118 int scrollX, int scrollY,
119 int scrollRangeX, int scrollRangeY,
120 int maxOverScrollX, int maxOverScrollY,
121 boolean isTouchEvent);
124 * @see View#scrollTo(int, int)
126 void super_scrollTo(int scrollX, int scrollY);
129 * @see View#setMeasuredDimension(int, int)
131 void setMeasuredDimension(int measuredWidth, int measuredHeight);
134 * @see View#getScrollBarStyle()
136 int super_getScrollBarStyle();
140 * Interface that consumers of {@link AwContents} must implement to support
141 * native GL rendering.
143 public interface NativeGLDelegate {
145 * Requests a callback on the native DrawGL method (see getAwDrawGLFunction)
146 * if called from within onDraw, |canvas| will be non-null and hardware accelerated.
147 * Otherwise, |canvas| will be null, and the container view itself will be hardware
148 * accelerated. If |waitForCompletion| is true, this method will not return until
149 * functor has returned.
150 * Should avoid setting |waitForCompletion| when |canvas| is not null.
151 * |containerView| is the view where the AwContents should be drawn.
153 * @return false indicates the GL draw request was not accepted, and the caller
154 * should fallback to the SW path.
156 boolean requestDrawGL(Canvas canvas, boolean waitForCompletion, View containerView);
159 * Detaches the GLFunctor from the view tree.
161 void detachGLFunctor();
165 * Class to facilitate dependency injection. Subclasses by test code to provide mock versions of
166 * certain AwContents dependencies.
168 public static class DependencyFactory {
169 public AwLayoutSizer createLayoutSizer() {
170 return new AwLayoutSizer();
173 public AwScrollOffsetManager createScrollOffsetManager(
174 AwScrollOffsetManager.Delegate delegate, OverScroller overScroller) {
175 return new AwScrollOffsetManager(delegate, overScroller);
179 private long mNativeAwContents;
180 private final AwBrowserContext mBrowserContext;
181 private ViewGroup mContainerView;
182 private final AwLayoutChangeListener mLayoutChangeListener;
183 private final Context mContext;
184 private ContentViewCore mContentViewCore;
185 private WindowAndroid mWindowAndroid;
186 private final AwContentsClient mContentsClient;
187 private final AwContentViewClient mContentViewClient;
188 private WebContentsObserverAndroid mWebContentsObserver;
189 private final AwContentsClientBridge mContentsClientBridge;
190 private final AwWebContentsDelegateAdapter mWebContentsDelegate;
191 private final AwContentsIoThreadClient mIoThreadClient;
192 private final InterceptNavigationDelegateImpl mInterceptNavigationDelegate;
193 private InternalAccessDelegate mInternalAccessAdapter;
194 private final NativeGLDelegate mNativeGLDelegate;
195 private final AwLayoutSizer mLayoutSizer;
196 private final AwZoomControls mZoomControls;
197 private final AwScrollOffsetManager mScrollOffsetManager;
198 private OverScrollGlow mOverScrollGlow;
199 // This can be accessed on any thread after construction. See AwContentsIoThreadClient.
200 private final AwSettings mSettings;
201 private final ScrollAccessibilityHelper mScrollAccessibilityHelper;
203 private boolean mIsPaused;
204 private boolean mIsViewVisible;
205 private boolean mIsWindowVisible;
206 private boolean mIsAttachedToWindow;
207 private Bitmap mFavicon;
208 private boolean mHasRequestedVisitedHistoryFromClient;
209 // TODO(boliu): This should be in a global context, not per webview.
210 private final double mDIPScale;
212 // The base background color, i.e. not accounting for any CSS body from the current page.
213 private int mBaseBackgroundColor = Color.WHITE;
215 // Must call nativeUpdateLastHitTestData first to update this before use.
216 private final HitTestData mPossiblyStaleHitTestData = new HitTestData();
218 private final DefaultVideoPosterRequestHandler mDefaultVideoPosterRequestHandler;
220 // Bound method for suppling Picture instances to the AwContentsClient. Will be null if the
221 // picture listener API has not yet been enabled, or if it is using invalidation-only mode.
222 private Callable<Picture> mPictureListenerContentProvider;
224 private boolean mContainerViewFocused;
225 private boolean mWindowFocused;
227 // These come from the compositor and are updated synchronously (in contrast to the values in
228 // ContentViewCore, which are updated at end of every frame).
229 private float mPageScaleFactor = 1.0f;
230 private float mMinPageScaleFactor = 1.0f;
231 private float mMaxPageScaleFactor = 1.0f;
232 private float mContentWidthDip;
233 private float mContentHeightDip;
235 private AwAutofillClient mAwAutofillClient;
237 private AwPdfExporter mAwPdfExporter;
239 private AwViewMethods mAwViewMethods;
240 private final FullScreenTransitionsState mFullScreenTransitionsState;
242 // This flag indicates that ShouldOverrideUrlNavigation should be posted
243 // through the resourcethrottle. This is only used for popup windows.
244 private boolean mDeferredShouldOverrideUrlLoadingIsPendingForPopup;
246 // The framework may temporarily detach our container view, for example during layout if
247 // we are a child of a ListView. This may cause many toggles of View focus, which we suppress
248 // when in this state.
249 private boolean mTemporarilyDetached;
251 private static final class DestroyRunnable implements Runnable {
252 private final long mNativeAwContents;
253 private DestroyRunnable(long nativeAwContents) {
254 mNativeAwContents = nativeAwContents;
258 nativeDestroy(mNativeAwContents);
263 * A class that stores the state needed to enter and exit fullscreen.
265 private static class FullScreenTransitionsState {
266 private final ViewGroup mInitialContainerView;
267 private final InternalAccessDelegate mInitialInternalAccessAdapter;
268 private final AwViewMethods mInitialAwViewMethods;
269 private FullScreenView mFullScreenView;
271 private FullScreenTransitionsState(ViewGroup initialContainerView,
272 InternalAccessDelegate initialInternalAccessAdapter,
273 AwViewMethods initialAwViewMethods) {
274 mInitialContainerView = initialContainerView;
275 mInitialInternalAccessAdapter = initialInternalAccessAdapter;
276 mInitialAwViewMethods = initialAwViewMethods;
279 private void enterFullScreen(FullScreenView fullScreenView) {
280 mFullScreenView = fullScreenView;
283 private void exitFullScreen() {
284 mFullScreenView = null;
287 private boolean isFullScreen() {
288 return mFullScreenView != null;
291 private ViewGroup getInitialContainerView() {
292 return mInitialContainerView;
295 private InternalAccessDelegate getInitialInternalAccessDelegate() {
296 return mInitialInternalAccessAdapter;
299 private AwViewMethods getInitialAwViewMethods() {
300 return mInitialAwViewMethods;
303 private FullScreenView getFullScreenView() {
304 return mFullScreenView;
308 // Reference to the active mNativeAwContents pointer while it is active use
309 // (ie before it is destroyed).
310 private CleanupReference mCleanupReference;
312 //--------------------------------------------------------------------------------------------
313 private class IoThreadClientImpl extends AwContentsIoThreadClient {
314 // All methods are called on the IO thread.
317 public int getCacheMode() {
318 return mSettings.getCacheMode();
322 public AwWebResourceResponse shouldInterceptRequest(
323 AwContentsClient.ShouldInterceptRequestParams params) {
324 String url = params.url;
325 AwWebResourceResponse awWebResourceResponse;
326 // Return the response directly if the url is default video poster url.
327 awWebResourceResponse = mDefaultVideoPosterRequestHandler.shouldInterceptRequest(url);
328 if (awWebResourceResponse != null) return awWebResourceResponse;
330 awWebResourceResponse = mContentsClient.shouldInterceptRequest(params);
332 if (awWebResourceResponse == null) {
333 mContentsClient.getCallbackHelper().postOnLoadResource(url);
336 if (params.isMainFrame && awWebResourceResponse != null &&
337 awWebResourceResponse.getData() == null) {
338 // In this case the intercepted URLRequest job will simulate an empty response
339 // which doesn't trigger the onReceivedError callback. For WebViewClassic
340 // compatibility we synthesize that callback. http://crbug.com/180950
341 mContentsClient.getCallbackHelper().postOnReceivedError(
342 ErrorCodeConversionHelper.ERROR_UNKNOWN,
343 null /* filled in by the glue layer */, url);
345 return awWebResourceResponse;
349 public boolean shouldBlockContentUrls() {
350 return !mSettings.getAllowContentAccess();
354 public boolean shouldBlockFileUrls() {
355 return !mSettings.getAllowFileAccess();
359 public boolean shouldBlockNetworkLoads() {
360 return mSettings.getBlockNetworkLoads();
364 public boolean shouldAcceptThirdPartyCookies() {
365 return mSettings.getAcceptThirdPartyCookies();
369 public void onDownloadStart(String url, String userAgent,
370 String contentDisposition, String mimeType, long contentLength) {
371 mContentsClient.getCallbackHelper().postOnDownloadStart(url, userAgent,
372 contentDisposition, mimeType, contentLength);
376 public void newLoginRequest(String realm, String account, String args) {
377 mContentsClient.getCallbackHelper().postOnReceivedLoginRequest(realm, account, args);
381 //--------------------------------------------------------------------------------------------
382 // When the navigation is for a newly created WebView (i.e. a popup), intercept the navigation
383 // here for implementing shouldOverrideUrlLoading. This is to send the shouldOverrideUrlLoading
384 // callback to the correct WebViewClient that is associated with the WebView.
385 // Otherwise, use this delegate only to post onPageStarted messages.
387 // We are not using WebContentsObserver.didStartLoading because of stale URLs, out of order
388 // onPageStarted's and double onPageStarted's.
390 private class InterceptNavigationDelegateImpl implements InterceptNavigationDelegate {
392 public boolean shouldIgnoreNavigation(NavigationParams navigationParams) {
393 final String url = navigationParams.url;
394 boolean ignoreNavigation = false;
395 if (mDeferredShouldOverrideUrlLoadingIsPendingForPopup) {
396 mDeferredShouldOverrideUrlLoadingIsPendingForPopup = false;
397 // If this is used for all navigations in future, cases for application initiated
398 // load, redirect and backforward should also be filtered out.
399 if (!navigationParams.isPost) {
400 ignoreNavigation = mContentsClient.shouldOverrideUrlLoading(url);
403 // The shouldOverrideUrlLoading call might have resulted in posting messages to the
404 // UI thread. Using sendMessage here (instead of calling onPageStarted directly)
405 // will allow those to run in order.
406 if (!ignoreNavigation) {
407 mContentsClient.getCallbackHelper().postOnPageStarted(url);
409 return ignoreNavigation;
413 //--------------------------------------------------------------------------------------------
414 private class AwLayoutSizerDelegate implements AwLayoutSizer.Delegate {
416 public void requestLayout() {
417 mContainerView.requestLayout();
421 public void setMeasuredDimension(int measuredWidth, int measuredHeight) {
422 mInternalAccessAdapter.setMeasuredDimension(measuredWidth, measuredHeight);
426 public boolean isLayoutParamsHeightWrapContent() {
427 return mContainerView.getLayoutParams() != null &&
428 mContainerView.getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT;
432 public void setForceZeroLayoutHeight(boolean forceZeroHeight) {
433 getSettings().setForceZeroLayoutHeight(forceZeroHeight);
437 //--------------------------------------------------------------------------------------------
438 private class AwScrollOffsetManagerDelegate implements AwScrollOffsetManager.Delegate {
440 public void overScrollContainerViewBy(int deltaX, int deltaY, int scrollX, int scrollY,
441 int scrollRangeX, int scrollRangeY, boolean isTouchEvent) {
442 mInternalAccessAdapter.overScrollBy(deltaX, deltaY, scrollX, scrollY,
443 scrollRangeX, scrollRangeY, 0, 0, isTouchEvent);
447 public void scrollContainerViewTo(int x, int y) {
448 mInternalAccessAdapter.super_scrollTo(x, y);
452 public void scrollNativeTo(int x, int y) {
453 if (mNativeAwContents == 0) return;
454 nativeScrollTo(mNativeAwContents, x, y);
458 public int getContainerViewScrollX() {
459 return mContainerView.getScrollX();
463 public int getContainerViewScrollY() {
464 return mContainerView.getScrollY();
468 public void invalidate() {
469 mContainerView.invalidate();
473 //--------------------------------------------------------------------------------------------
474 private class AwGestureStateListener extends GestureStateListener {
476 public void onPinchStarted() {
477 // While it's possible to re-layout the view during a pinch gesture, the effect is very
478 // janky (especially that the page scale update notification comes from the renderer
479 // main thread, not from the impl thread, so it's usually out of sync with what's on
480 // screen). It's also quite expensive to do a re-layout, so we simply postpone
481 // re-layout for the duration of the gesture. This is compatible with what
482 // WebViewClassic does.
483 mLayoutSizer.freezeLayoutRequests();
487 public void onPinchEnded() {
488 mLayoutSizer.unfreezeLayoutRequests();
492 public void onFlingCancelGesture() {
493 mScrollOffsetManager.onFlingCancelGesture();
497 public void onUnhandledFlingStartEvent(int velocityX, int velocityY) {
498 mScrollOffsetManager.onUnhandledFlingStartEvent(velocityX, velocityY);
502 public void onScrollUpdateGestureConsumed() {
503 mScrollAccessibilityHelper.postViewScrolledAccessibilityEventCallback();
507 //--------------------------------------------------------------------------------------------
508 private class AwComponentCallbacks implements ComponentCallbacks2 {
510 public void onTrimMemory(final int level) {
511 if (mNativeAwContents == 0) return;
512 boolean visibleRectEmpty = getGlobalVisibleRect().isEmpty();
513 final boolean visible = mIsViewVisible && mIsWindowVisible && !visibleRectEmpty;
514 nativeTrimMemory(mNativeAwContents, level, visible);
518 public void onLowMemory() {}
521 public void onConfigurationChanged(Configuration configuration) {}
524 //--------------------------------------------------------------------------------------------
525 private class AwLayoutChangeListener implements View.OnLayoutChangeListener {
527 public void onLayoutChange(View v, int left, int top, int right, int bottom,
528 int oldLeft, int oldTop, int oldRight, int oldBottom) {
529 assert v == mContainerView;
530 mLayoutSizer.onLayoutChange();
535 * @param browserContext the browsing context to associate this view contents with.
536 * @param containerView the view-hierarchy item this object will be bound to.
537 * @param context the context to use, usually containerView.getContext().
538 * @param internalAccessAdapter to access private methods on containerView.
539 * @param nativeGLDelegate to access the GL functor provided by the WebView.
540 * @param contentsClient will receive API callbacks from this WebView Contents.
541 * @param awSettings AwSettings instance used to configure the AwContents.
543 * This constructor uses the default view sizing policy.
545 public AwContents(AwBrowserContext browserContext, ViewGroup containerView, Context context,
546 InternalAccessDelegate internalAccessAdapter, NativeGLDelegate nativeGLDelegate,
547 AwContentsClient contentsClient, AwSettings awSettings) {
548 this(browserContext, containerView, context, internalAccessAdapter, nativeGLDelegate,
549 contentsClient, awSettings, new DependencyFactory());
553 * @param dependencyFactory an instance of the DependencyFactory used to provide instances of
554 * classes that this class depends on.
556 * This version of the constructor is used in test code to inject test versions of the above
557 * documented classes.
559 public AwContents(AwBrowserContext browserContext, ViewGroup containerView, Context context,
560 InternalAccessDelegate internalAccessAdapter, NativeGLDelegate nativeGLDelegate,
561 AwContentsClient contentsClient, AwSettings settings,
562 DependencyFactory dependencyFactory) {
563 mBrowserContext = browserContext;
564 mContainerView = containerView;
566 mInternalAccessAdapter = internalAccessAdapter;
567 mNativeGLDelegate = nativeGLDelegate;
568 mContentsClient = contentsClient;
569 mAwViewMethods = new AwViewMethodsImpl();
570 mFullScreenTransitionsState = new FullScreenTransitionsState(
571 mContainerView, mInternalAccessAdapter, mAwViewMethods);
572 mContentViewClient = new AwContentViewClient(contentsClient, settings, this, mContext);
573 mLayoutSizer = dependencyFactory.createLayoutSizer();
574 mSettings = settings;
575 mDIPScale = DeviceDisplayInfo.create(mContext).getDIPScale();
576 mLayoutSizer.setDelegate(new AwLayoutSizerDelegate());
577 mLayoutSizer.setDIPScale(mDIPScale);
578 mWebContentsDelegate = new AwWebContentsDelegateAdapter(
579 contentsClient, mContainerView, mContext);
580 mContentsClientBridge = new AwContentsClientBridge(contentsClient,
581 mBrowserContext.getKeyStore(), AwContentsStatics.getClientCertLookupTable());
582 mZoomControls = new AwZoomControls(this);
583 mIoThreadClient = new IoThreadClientImpl();
584 mInterceptNavigationDelegate = new InterceptNavigationDelegateImpl();
586 AwSettings.ZoomSupportChangeListener zoomListener =
587 new AwSettings.ZoomSupportChangeListener() {
589 public void onGestureZoomSupportChanged(
590 boolean supportsDoubleTapZoom, boolean supportsMultiTouchZoom) {
591 mContentViewCore.updateDoubleTapSupport(supportsDoubleTapZoom);
592 mContentViewCore.updateMultiTouchZoomSupport(supportsMultiTouchZoom);
596 mSettings.setZoomListener(zoomListener);
597 mDefaultVideoPosterRequestHandler = new DefaultVideoPosterRequestHandler(mContentsClient);
598 mSettings.setDefaultVideoPosterURL(
599 mDefaultVideoPosterRequestHandler.getDefaultVideoPosterURL());
600 mSettings.setDIPScale(mDIPScale);
601 mScrollOffsetManager = dependencyFactory.createScrollOffsetManager(
602 new AwScrollOffsetManagerDelegate(), new OverScroller(mContext));
603 mScrollAccessibilityHelper = new ScrollAccessibilityHelper(mContainerView);
605 setOverScrollMode(mContainerView.getOverScrollMode());
606 setScrollBarStyle(mInternalAccessAdapter.super_getScrollBarStyle());
607 mLayoutChangeListener = new AwLayoutChangeListener();
608 mContainerView.addOnLayoutChangeListener(mLayoutChangeListener);
610 setNewAwContents(nativeInit(mBrowserContext));
612 onContainerViewChanged();
615 private static ContentViewCore createAndInitializeContentViewCore(ViewGroup containerView,
616 Context context, InternalAccessDelegate internalDispatcher, long nativeWebContents,
617 GestureStateListener gestureStateListener,
618 ContentViewClient contentViewClient,
619 ContentViewCore.ZoomControlsDelegate zoomControlsDelegate,
620 WindowAndroid windowAndroid) {
621 ContentViewCore contentViewCore = new ContentViewCore(context);
622 contentViewCore.initialize(containerView, internalDispatcher, nativeWebContents,
624 contentViewCore.addGestureStateListener(gestureStateListener);
625 contentViewCore.setContentViewClient(contentViewClient);
626 contentViewCore.setZoomControlsDelegate(zoomControlsDelegate);
627 return contentViewCore;
630 boolean isFullScreen() {
631 return mFullScreenTransitionsState.isFullScreen();
635 * Transitions this {@link AwContents} to fullscreen mode and returns the
636 * {@link View} where the contents will be drawn while in fullscreen.
638 View enterFullScreen() {
639 assert !isFullScreen();
641 // Detach to tear down the GL functor if this is still associated with the old
642 // container view. It will be recreated during the next call to onDraw attached to
643 // the new container view.
644 onDetachedFromWindow();
646 // In fullscreen mode FullScreenView owns the AwViewMethodsImpl and AwContents
647 // a NullAwViewMethods.
648 FullScreenView fullScreenView = new FullScreenView(mContext, mAwViewMethods);
649 mFullScreenTransitionsState.enterFullScreen(fullScreenView);
650 mAwViewMethods = new NullAwViewMethods(this, mInternalAccessAdapter, mContainerView);
651 mContainerView.removeOnLayoutChangeListener(mLayoutChangeListener);
652 fullScreenView.addOnLayoutChangeListener(mLayoutChangeListener);
654 // Associate this AwContents with the FullScreenView.
655 setInternalAccessAdapter(fullScreenView.getInternalAccessAdapter());
656 setContainerView(fullScreenView);
658 return fullScreenView;
662 * Returns this {@link AwContents} to embedded mode, where the {@link AwContents} are drawn
665 void exitFullScreen() {
666 assert isFullScreen();
668 // Detach to tear down the GL functor if this is still associated with the old
669 // container view. It will be recreated during the next call to onDraw attached to
670 // the new container view.
671 // NOTE: we cannot use mAwViewMethods here because its type is NullAwViewMethods.
672 AwViewMethods awViewMethodsImpl = mFullScreenTransitionsState.getInitialAwViewMethods();
673 awViewMethodsImpl.onDetachedFromWindow();
675 // Swap the view delegates. In embedded mode the FullScreenView owns a
676 // NullAwViewMethods and AwContents the AwViewMethodsImpl.
677 FullScreenView fullscreenView = mFullScreenTransitionsState.getFullScreenView();
678 fullscreenView.setAwViewMethods(new NullAwViewMethods(
679 this, fullscreenView.getInternalAccessAdapter(), fullscreenView));
680 mAwViewMethods = awViewMethodsImpl;
681 ViewGroup initialContainerView = mFullScreenTransitionsState.getInitialContainerView();
682 initialContainerView.addOnLayoutChangeListener(mLayoutChangeListener);
683 fullscreenView.removeOnLayoutChangeListener(mLayoutChangeListener);
685 // Re-associate this AwContents with the WebView.
686 setInternalAccessAdapter(mFullScreenTransitionsState.getInitialInternalAccessDelegate());
687 setContainerView(initialContainerView);
689 mFullScreenTransitionsState.exitFullScreen();
692 private void setInternalAccessAdapter(InternalAccessDelegate internalAccessAdapter) {
693 mInternalAccessAdapter = internalAccessAdapter;
694 mContentViewCore.setContainerViewInternals(mInternalAccessAdapter);
697 private void setContainerView(ViewGroup newContainerView) {
698 mContainerView = newContainerView;
699 mContentViewCore.setContainerView(mContainerView);
700 if (mAwPdfExporter != null) {
701 mAwPdfExporter.setContainerView(mContainerView);
703 mWebContentsDelegate.setContainerView(mContainerView);
705 onContainerViewChanged();
709 * Reconciles the state of this AwContents object with the state of the new container view.
711 private void onContainerViewChanged() {
712 // NOTE: mAwViewMethods is used by the old container view, the WebView, so it might refer
713 // to a NullAwViewMethods when in fullscreen. To ensure that the state is reconciled with
714 // the new container view correctly, we bypass mAwViewMethods and use the real
715 // implementation directly.
716 AwViewMethods awViewMethodsImpl = mFullScreenTransitionsState.getInitialAwViewMethods();
717 awViewMethodsImpl.onVisibilityChanged(mContainerView, mContainerView.getVisibility());
718 awViewMethodsImpl.onWindowVisibilityChanged(mContainerView.getWindowVisibility());
720 // We should stop running WebView tests in JellyBean devices, see crbug/161864.
721 // Until then we skip calling isAttachedToWindow() as it has only been introduced in K.
722 if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT
723 || mContainerView.isAttachedToWindow()) {
724 awViewMethodsImpl.onAttachedToWindow();
726 awViewMethodsImpl.onDetachedFromWindow();
728 awViewMethodsImpl.onSizeChanged(
729 mContainerView.getWidth(), mContainerView.getHeight(), 0, 0);
730 awViewMethodsImpl.onWindowFocusChanged(mContainerView.hasWindowFocus());
731 awViewMethodsImpl.onFocusChanged(mContainerView.hasFocus(), 0, null);
732 mContainerView.requestLayout();
735 /* Common initialization routine for adopting a native AwContents instance into this
738 * TAKE CARE! This method can get called multiple times per java instance. Code accordingly.
739 * ^^^^^^^^^ See the native class declaration for more details on relative object lifetimes.
741 private void setNewAwContents(long newAwContentsPtr) {
742 if (mNativeAwContents != 0) {
744 mContentViewCore = null;
747 assert mNativeAwContents == 0 && mCleanupReference == null && mContentViewCore == null;
749 mNativeAwContents = newAwContentsPtr;
750 // TODO(joth): when the native and java counterparts of AwBrowserContext are hooked up to
751 // each other, we should update |mBrowserContext| according to the newly received native
752 // WebContent's browser context.
754 // The native side object has been bound to this java instance, so now is the time to
755 // bind all the native->java relationships.
756 mCleanupReference = new CleanupReference(this, new DestroyRunnable(mNativeAwContents));
758 long nativeWebContents = nativeGetWebContents(mNativeAwContents);
760 mWindowAndroid = mContext instanceof Activity ?
761 new ActivityWindowAndroid((Activity) mContext) :
762 new WindowAndroid(mContext.getApplicationContext());
763 mContentViewCore = createAndInitializeContentViewCore(
764 mContainerView, mContext, mInternalAccessAdapter, nativeWebContents,
765 new AwGestureStateListener(), mContentViewClient, mZoomControls, mWindowAndroid);
766 nativeSetJavaPeers(mNativeAwContents, this, mWebContentsDelegate, mContentsClientBridge,
767 mIoThreadClient, mInterceptNavigationDelegate);
768 installWebContentsObserver();
769 mSettings.setWebContents(nativeWebContents);
770 nativeSetDipScale(mNativeAwContents, (float) mDIPScale);
772 // The only call to onShow. onHide should never be called.
773 mContentViewCore.onShow();
776 private void installWebContentsObserver() {
777 if (mWebContentsObserver != null) {
778 mWebContentsObserver.detachFromWebContents();
780 mWebContentsObserver = new AwWebContentsObserver(mContentViewCore.getWebContents(),
785 * Called on the "source" AwContents that is opening the popup window to
786 * provide the AwContents to host the pop up content.
788 public void supplyContentsForPopup(AwContents newContents) {
789 long popupNativeAwContents = nativeReleasePopupAwContents(mNativeAwContents);
790 if (popupNativeAwContents == 0) {
791 Log.w(TAG, "Popup WebView bind failed: no pending content.");
792 if (newContents != null) newContents.destroy();
795 if (newContents == null) {
796 nativeDestroy(popupNativeAwContents);
800 newContents.receivePopupContents(popupNativeAwContents);
803 // Recap: supplyContentsForPopup() is called on the parent window's content, this method is
804 // called on the popup window's content.
805 private void receivePopupContents(long popupNativeAwContents) {
806 mDeferredShouldOverrideUrlLoadingIsPendingForPopup = true;
807 // Save existing view state.
808 final boolean wasAttached = mIsAttachedToWindow;
809 final boolean wasViewVisible = mIsViewVisible;
810 final boolean wasWindowVisible = mIsWindowVisible;
811 final boolean wasPaused = mIsPaused;
812 final boolean wasFocused = mContainerViewFocused;
813 final boolean wasWindowFocused = mWindowFocused;
815 // Properly clean up existing mContentViewCore and mNativeAwContents.
816 if (wasFocused) onFocusChanged(false, 0, null);
817 if (wasWindowFocused) onWindowFocusChanged(false);
818 if (wasViewVisible) setViewVisibilityInternal(false);
819 if (wasWindowVisible) setWindowVisibilityInternal(false);
820 if (wasAttached) onDetachedFromWindow();
821 if (!wasPaused) onPause();
823 // Save injected JavaScript interfaces.
824 Map<String, Pair<Object, Class>> javascriptInterfaces =
825 new HashMap<String, Pair<Object, Class>>();
826 if (mContentViewCore != null) {
827 javascriptInterfaces.putAll(mContentViewCore.getJavascriptInterfaces());
830 setNewAwContents(popupNativeAwContents);
832 // Finally refresh all view state for mContentViewCore and mNativeAwContents.
833 if (!wasPaused) onResume();
835 onAttachedToWindow();
836 postInvalidateOnAnimation();
838 onSizeChanged(mContainerView.getWidth(), mContainerView.getHeight(), 0, 0);
839 if (wasWindowVisible) setWindowVisibilityInternal(true);
840 if (wasViewVisible) setViewVisibilityInternal(true);
841 if (wasWindowFocused) onWindowFocusChanged(wasWindowFocused);
842 if (wasFocused) onFocusChanged(true, 0, null);
844 // Restore injected JavaScript interfaces.
845 for (Map.Entry<String, Pair<Object, Class>> entry : javascriptInterfaces.entrySet()) {
846 @SuppressWarnings("unchecked")
847 Class<? extends Annotation> requiredAnnotation = (Class<? extends Annotation>)
848 entry.getValue().second;
849 mContentViewCore.addPossiblyUnsafeJavascriptInterface(
850 entry.getValue().first,
857 * Deletes the native counterpart of this object.
859 public void destroy() {
860 if (mCleanupReference != null) {
861 assert mNativeAwContents != 0;
862 // If we are attached, we have to call native detach to clean up
863 // hardware resources.
864 if (mIsAttachedToWindow) {
865 nativeOnDetachedFromWindow(mNativeAwContents);
868 // We explicitly do not null out the mContentViewCore reference here
869 // because ContentViewCore already has code to deal with the case
870 // methods are called on it after it's been destroyed, and other
871 // code relies on AwContents.mContentViewCore to be non-null.
872 mContentViewCore.destroy();
873 mNativeAwContents = 0;
875 mCleanupReference.cleanupNow();
876 mCleanupReference = null;
879 assert !mContentViewCore.isAlive();
880 assert mNativeAwContents == 0;
884 public ContentViewCore getContentViewCore() {
885 return mContentViewCore;
888 // Can be called from any thread.
889 public AwSettings getSettings() {
893 public AwPdfExporter getPdfExporter() {
894 // mNativeAwContents can be null, due to destroy().
895 if (mNativeAwContents == 0) {
898 if (mAwPdfExporter == null) {
899 mAwPdfExporter = new AwPdfExporter(mContainerView);
900 nativeCreatePdfExporter(mNativeAwContents, mAwPdfExporter);
902 return mAwPdfExporter;
905 public static void setAwDrawSWFunctionTable(long functionTablePointer) {
906 nativeSetAwDrawSWFunctionTable(functionTablePointer);
909 public static void setAwDrawGLFunctionTable(long functionTablePointer) {
910 nativeSetAwDrawGLFunctionTable(functionTablePointer);
913 public static long getAwDrawGLFunction() {
914 return nativeGetAwDrawGLFunction();
917 public static void setShouldDownloadFavicons() {
918 nativeSetShouldDownloadFavicons();
922 * Disables contents of JS-to-Java bridge objects to be inspectable using
923 * Object.keys() method and "for .. in" loops. This is intended for applications
924 * targeting earlier Android releases where this was not possible, and we want
925 * to ensure backwards compatible behavior.
927 public void disableJavascriptInterfacesInspection() {
928 mContentViewCore.setAllowJavascriptInterfacesInspection(false);
932 * Intended for test code.
933 * @return the number of native instances of this class.
936 public static int getNativeInstanceCount() {
937 return nativeGetNativeInstanceCount();
940 public long getAwDrawGLViewContext() {
941 // Only called during early construction, so client should not have had a chance to
943 assert mNativeAwContents != 0;
945 // Using the native pointer as the returned viewContext. This is matched by the
946 // reinterpret_cast back to BrowserViewRenderer pointer in the native DrawGLFunction.
947 return nativeGetAwDrawGLViewContext(mNativeAwContents);
950 // This is only to avoid heap allocations inside getGlobalVisibleRect. It should treated
951 // as a local variable in the function and not used anywhere else.
952 private static final Rect sLocalGlobalVisibleRect = new Rect();
954 private Rect getGlobalVisibleRect() {
955 if (!mContainerView.getGlobalVisibleRect(sLocalGlobalVisibleRect)) {
956 sLocalGlobalVisibleRect.setEmpty();
958 return sLocalGlobalVisibleRect;
961 //--------------------------------------------------------------------------------------------
962 // WebView[Provider] method implementations (where not provided by ContentViewCore)
963 //--------------------------------------------------------------------------------------------
965 public void onDraw(Canvas canvas) {
966 mAwViewMethods.onDraw(canvas);
969 public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
970 mAwViewMethods.onMeasure(widthMeasureSpec, heightMeasureSpec);
973 public int getContentHeightCss() {
974 return (int) Math.ceil(mContentHeightDip);
977 public int getContentWidthCss() {
978 return (int) Math.ceil(mContentWidthDip);
981 public Picture capturePicture() {
982 if (mNativeAwContents == 0) return null;
983 return new AwPicture(nativeCapturePicture(mNativeAwContents,
984 mScrollOffsetManager.computeHorizontalScrollRange(),
985 mScrollOffsetManager.computeVerticalScrollRange()));
988 public void clearView() {
989 if (mNativeAwContents == 0) return;
990 nativeClearView(mNativeAwContents);
994 * Enable the onNewPicture callback.
995 * @param enabled Flag to enable the callback.
996 * @param invalidationOnly Flag to call back only on invalidation without providing a picture.
998 public void enableOnNewPicture(boolean enabled, boolean invalidationOnly) {
999 if (mNativeAwContents == 0) return;
1000 if (invalidationOnly) {
1001 mPictureListenerContentProvider = null;
1002 } else if (enabled && mPictureListenerContentProvider == null) {
1003 mPictureListenerContentProvider = new Callable<Picture>() {
1005 public Picture call() {
1006 return capturePicture();
1010 nativeEnableOnNewPicture(mNativeAwContents, enabled);
1013 public void findAllAsync(String searchString) {
1014 if (mNativeAwContents == 0) return;
1015 nativeFindAllAsync(mNativeAwContents, searchString);
1018 public void findNext(boolean forward) {
1019 if (mNativeAwContents == 0) return;
1020 nativeFindNext(mNativeAwContents, forward);
1023 public void clearMatches() {
1024 if (mNativeAwContents == 0) return;
1025 nativeClearMatches(mNativeAwContents);
1029 * @return load progress of the WebContents.
1031 public int getMostRecentProgress() {
1032 // WebContentsDelegateAndroid conveniently caches the most recent notified value for us.
1033 return mWebContentsDelegate.getMostRecentProgress();
1036 public Bitmap getFavicon() {
1040 private void requestVisitedHistoryFromClient() {
1041 ValueCallback<String[]> callback = new ValueCallback<String[]>() {
1043 public void onReceiveValue(final String[] value) {
1044 ThreadUtils.runOnUiThread(new Runnable() {
1047 if (mNativeAwContents == 0) return;
1048 nativeAddVisitedLinks(mNativeAwContents, value);
1053 mContentsClient.getVisitedHistory(callback);
1057 * Load url without fixing up the url string. Consumers of ContentView are responsible for
1058 * ensuring the URL passed in is properly formatted (i.e. the scheme has been added if left
1059 * off during user input).
1061 * @param params Parameters for this load.
1063 public void loadUrl(LoadUrlParams params) {
1064 if (params.getLoadUrlType() == LoadUrlParams.LOAD_TYPE_DATA &&
1065 !params.isBaseUrlDataScheme()) {
1066 // This allows data URLs with a non-data base URL access to file:///android_asset/ and
1067 // file:///android_res/ URLs. If AwSettings.getAllowFileAccess permits, it will also
1068 // allow access to file:// URLs (subject to OS level permission checks).
1069 params.setCanLoadLocalResources(true);
1072 // If we are reloading the same url, then set transition type as reload.
1073 if (params.getUrl() != null &&
1074 params.getUrl().equals(mContentViewCore.getUrl()) &&
1075 params.getTransitionType() == PageTransitionTypes.PAGE_TRANSITION_LINK) {
1076 params.setTransitionType(PageTransitionTypes.PAGE_TRANSITION_RELOAD);
1078 params.setTransitionType(
1079 params.getTransitionType() | PageTransitionTypes.PAGE_TRANSITION_FROM_API);
1081 // For WebView, always use the user agent override, which is set
1082 // every time the user agent in AwSettings is modified.
1083 params.setOverrideUserAgent(LoadUrlParams.UA_OVERRIDE_TRUE);
1086 // We don't pass extra headers to the content layer, as WebViewClassic
1087 // was adding them in a very narrow set of conditions. See http://crbug.com/306873
1088 // However, if the embedder is attempting to inject a Referer header for their
1089 // loadUrl call, then we set that separately and remove it from the extra headers map/
1090 final String REFERER = "referer";
1091 Map<String, String> extraHeaders = params.getExtraHeaders();
1092 if (extraHeaders != null) {
1093 for (String header : extraHeaders.keySet()) {
1094 if (REFERER.equals(header.toLowerCase(Locale.US))) {
1095 params.setReferrer(new Referrer(extraHeaders.remove(header), 1));
1096 params.setExtraHeaders(extraHeaders);
1102 if (mNativeAwContents != 0) {
1103 nativeSetExtraHeadersForUrl(
1104 mNativeAwContents, params.getUrl(), params.getExtraHttpRequestHeadersString());
1106 params.setExtraHeaders(new HashMap<String, String>());
1108 mContentViewCore.loadUrl(params);
1110 // The behavior of WebViewClassic uses the populateVisitedLinks callback in WebKit.
1111 // Chromium does not use this use code path and the best emulation of this behavior to call
1112 // request visited links once on the first URL load of the WebView.
1113 if (!mHasRequestedVisitedHistoryFromClient) {
1114 mHasRequestedVisitedHistoryFromClient = true;
1115 requestVisitedHistoryFromClient();
1118 if (params.getLoadUrlType() == LoadUrlParams.LOAD_TYPE_DATA &&
1119 params.getBaseUrl() != null) {
1120 // Data loads with a base url will be resolved in Blink, and not cause an onPageStarted
1121 // event to be sent. Sending the callback directly from here.
1122 mContentsClient.getCallbackHelper().postOnPageStarted(params.getBaseUrl());
1127 * Get the URL of the current page.
1129 * @return The URL of the current page or null if it's empty.
1131 public String getUrl() {
1132 String url = mContentViewCore.getUrl();
1133 if (url == null || url.trim().isEmpty()) return null;
1137 public void requestFocus() {
1138 mAwViewMethods.requestFocus();
1141 public void setBackgroundColor(int color) {
1142 mBaseBackgroundColor = color;
1143 if (mNativeAwContents != 0) nativeSetBackgroundColor(mNativeAwContents, color);
1147 * @see android.view.View#setLayerType()
1149 public void setLayerType(int layerType, Paint paint) {
1150 mAwViewMethods.setLayerType(layerType, paint);
1153 int getEffectiveBackgroundColor() {
1154 // Do not ask the ContentViewCore for the background color, as it will always
1155 // report white prior to initial navigation or post destruction, whereas we want
1156 // to use the client supplied base value in those cases.
1157 if (mNativeAwContents == 0 || !mContentsClient.isCachedRendererBackgroundColorValid()) {
1158 return mBaseBackgroundColor;
1160 return mContentsClient.getCachedRendererBackgroundColor();
1163 public boolean isMultiTouchZoomSupported() {
1164 return mSettings.supportsMultiTouchZoom();
1167 public View getZoomControlsForTest() {
1168 return mZoomControls.getZoomControlsViewForTest();
1172 * @see ContentViewCore#getContentSettings()
1174 public ContentSettings getContentSettings() {
1175 return mContentViewCore.getContentSettings();
1179 * @see View#setOverScrollMode(int)
1181 public void setOverScrollMode(int mode) {
1182 if (mode != View.OVER_SCROLL_NEVER) {
1183 mOverScrollGlow = new OverScrollGlow(mContext, mContainerView);
1185 mOverScrollGlow = null;
1189 // TODO(mkosiba): In WebViewClassic these appear in some of the scroll extent calculation
1190 // methods but toggling them has no visiual effect on the content (in other words the scrolling
1191 // code behaves as if the scrollbar-related padding is in place but the onDraw code doesn't
1192 // take that into consideration).
1193 // http://crbug.com/269032
1194 private boolean mOverlayHorizontalScrollbar = true;
1195 private boolean mOverlayVerticalScrollbar = false;
1198 * @see View#setScrollBarStyle(int)
1200 public void setScrollBarStyle(int style) {
1201 if (style == View.SCROLLBARS_INSIDE_OVERLAY
1202 || style == View.SCROLLBARS_OUTSIDE_OVERLAY) {
1203 mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = true;
1205 mOverlayHorizontalScrollbar = mOverlayVerticalScrollbar = false;
1210 * @see View#setHorizontalScrollbarOverlay(boolean)
1212 public void setHorizontalScrollbarOverlay(boolean overlay) {
1213 mOverlayHorizontalScrollbar = overlay;
1217 * @see View#setVerticalScrollbarOverlay(boolean)
1219 public void setVerticalScrollbarOverlay(boolean overlay) {
1220 mOverlayVerticalScrollbar = overlay;
1224 * @see View#overlayHorizontalScrollbar()
1226 public boolean overlayHorizontalScrollbar() {
1227 return mOverlayHorizontalScrollbar;
1231 * @see View#overlayVerticalScrollbar()
1233 public boolean overlayVerticalScrollbar() {
1234 return mOverlayVerticalScrollbar;
1238 * Called by the embedder when the scroll offset of the containing view has changed.
1239 * @see View#onScrollChanged(int,int)
1241 public void onContainerViewScrollChanged(int l, int t, int oldl, int oldt) {
1242 // A side-effect of View.onScrollChanged is that the scroll accessibility event being sent
1243 // by the base class implementation. This is completely hidden from the base classes and
1244 // cannot be prevented, which is why we need the code below.
1245 mScrollAccessibilityHelper.removePostedViewScrolledAccessibilityEventCallback();
1246 mScrollOffsetManager.onContainerViewScrollChanged(l, t);
1250 * Called by the embedder when the containing view is to be scrolled or overscrolled.
1251 * @see View#onOverScrolled(int,int,int,int)
1253 public void onContainerViewOverScrolled(int scrollX, int scrollY, boolean clampedX,
1255 int oldX = mContainerView.getScrollX();
1256 int oldY = mContainerView.getScrollY();
1258 mScrollOffsetManager.onContainerViewOverScrolled(scrollX, scrollY, clampedX, clampedY);
1260 if (mOverScrollGlow != null) {
1261 mOverScrollGlow.pullGlow(mContainerView.getScrollX(), mContainerView.getScrollY(),
1263 mScrollOffsetManager.computeMaximumHorizontalScrollOffset(),
1264 mScrollOffsetManager.computeMaximumVerticalScrollOffset());
1269 * @see android.webkit.WebView#requestChildRectangleOnScreen(View, Rect, boolean)
1271 public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) {
1272 return mScrollOffsetManager.requestChildRectangleOnScreen(
1273 child.getLeft() - child.getScrollX(), child.getTop() - child.getScrollY(),
1278 * @see View.computeScroll()
1280 public void computeScroll() {
1281 mScrollOffsetManager.computeScrollAndAbsorbGlow(mOverScrollGlow);
1285 * @see View#computeHorizontalScrollRange()
1287 public int computeHorizontalScrollRange() {
1288 return mScrollOffsetManager.computeHorizontalScrollRange();
1292 * @see View#computeHorizontalScrollOffset()
1294 public int computeHorizontalScrollOffset() {
1295 return mScrollOffsetManager.computeHorizontalScrollOffset();
1299 * @see View#computeVerticalScrollRange()
1301 public int computeVerticalScrollRange() {
1302 return mScrollOffsetManager.computeVerticalScrollRange();
1306 * @see View#computeVerticalScrollOffset()
1308 public int computeVerticalScrollOffset() {
1309 return mScrollOffsetManager.computeVerticalScrollOffset();
1313 * @see View#computeVerticalScrollExtent()
1315 public int computeVerticalScrollExtent() {
1316 return mScrollOffsetManager.computeVerticalScrollExtent();
1320 * @see android.webkit.WebView#stopLoading()
1322 public void stopLoading() {
1323 mContentViewCore.stopLoading();
1327 * @see android.webkit.WebView#reload()
1329 public void reload() {
1330 mContentViewCore.reload(true);
1334 * @see android.webkit.WebView#canGoBack()
1336 public boolean canGoBack() {
1337 return mContentViewCore.canGoBack();
1341 * @see android.webkit.WebView#goBack()
1343 public void goBack() {
1344 mContentViewCore.goBack();
1348 * @see android.webkit.WebView#canGoForward()
1350 public boolean canGoForward() {
1351 return mContentViewCore.canGoForward();
1355 * @see android.webkit.WebView#goForward()
1357 public void goForward() {
1358 mContentViewCore.goForward();
1362 * @see android.webkit.WebView#canGoBackOrForward(int)
1364 public boolean canGoBackOrForward(int steps) {
1365 return mContentViewCore.canGoToOffset(steps);
1369 * @see android.webkit.WebView#goBackOrForward(int)
1371 public void goBackOrForward(int steps) {
1372 mContentViewCore.goToOffset(steps);
1376 * @see android.webkit.WebView#pauseTimers()
1378 public void pauseTimers() {
1379 ContentViewStatics.setWebKitSharedTimersSuspended(true);
1383 * @see android.webkit.WebView#resumeTimers()
1385 public void resumeTimers() {
1386 ContentViewStatics.setWebKitSharedTimersSuspended(false);
1390 * @see android.webkit.WebView#onPause()
1392 public void onPause() {
1393 if (mIsPaused || mNativeAwContents == 0) return;
1395 nativeSetIsPaused(mNativeAwContents, mIsPaused);
1399 * @see android.webkit.WebView#onResume()
1401 public void onResume() {
1402 if (!mIsPaused || mNativeAwContents == 0) return;
1404 nativeSetIsPaused(mNativeAwContents, mIsPaused);
1408 * @see android.webkit.WebView#isPaused()
1410 public boolean isPaused() {
1415 * @see android.webkit.WebView#onCreateInputConnection(EditorInfo)
1417 public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
1418 return mAwViewMethods.onCreateInputConnection(outAttrs);
1422 * @see android.webkit.WebView#onKeyUp(int, KeyEvent)
1424 public boolean onKeyUp(int keyCode, KeyEvent event) {
1425 return mAwViewMethods.onKeyUp(keyCode, event);
1429 * @see android.webkit.WebView#dispatchKeyEvent(KeyEvent)
1431 public boolean dispatchKeyEvent(KeyEvent event) {
1432 return mAwViewMethods.dispatchKeyEvent(event);
1436 * Clears the resource cache. Note that the cache is per-application, so this will clear the
1437 * cache for all WebViews used.
1439 * @param includeDiskFiles if false, only the RAM cache is cleared
1441 public void clearCache(boolean includeDiskFiles) {
1442 if (mNativeAwContents == 0) return;
1443 nativeClearCache(mNativeAwContents, includeDiskFiles);
1446 public void documentHasImages(Message message) {
1447 if (mNativeAwContents == 0) return;
1448 nativeDocumentHasImages(mNativeAwContents, message);
1451 public void saveWebArchive(
1452 final String basename, boolean autoname, final ValueCallback<String> callback) {
1454 saveWebArchiveInternal(basename, callback);
1457 // If auto-generating the file name, handle the name generation on a background thread
1458 // as it will require I/O access for checking whether previous files existed.
1459 new AsyncTask<Void, Void, String>() {
1461 protected String doInBackground(Void... params) {
1462 return generateArchiveAutoNamePath(getOriginalUrl(), basename);
1466 protected void onPostExecute(String result) {
1467 saveWebArchiveInternal(result, callback);
1472 public String getOriginalUrl() {
1473 NavigationHistory history = mContentViewCore.getNavigationHistory();
1474 int currentIndex = history.getCurrentEntryIndex();
1475 if (currentIndex >= 0 && currentIndex < history.getEntryCount()) {
1476 return history.getEntryAtIndex(currentIndex).getOriginalUrl();
1482 * @see ContentViewCore#getNavigationHistory()
1484 public NavigationHistory getNavigationHistory() {
1485 return mContentViewCore.getNavigationHistory();
1489 * @see android.webkit.WebView#getTitle()
1491 public String getTitle() {
1492 return mContentViewCore.getTitle();
1496 * @see android.webkit.WebView#clearHistory()
1498 public void clearHistory() {
1499 mContentViewCore.clearHistory();
1502 public String[] getHttpAuthUsernamePassword(String host, String realm) {
1503 return mBrowserContext.getHttpAuthDatabase(mContext)
1504 .getHttpAuthUsernamePassword(host, realm);
1507 public void setHttpAuthUsernamePassword(String host, String realm, String username,
1509 mBrowserContext.getHttpAuthDatabase(mContext)
1510 .setHttpAuthUsernamePassword(host, realm, username, password);
1514 * @see android.webkit.WebView#getCertificate()
1516 public SslCertificate getCertificate() {
1517 if (mNativeAwContents == 0) return null;
1518 return SslUtil.getCertificateFromDerBytes(nativeGetCertificate(mNativeAwContents));
1522 * @see android.webkit.WebView#clearSslPreferences()
1524 public void clearSslPreferences() {
1525 mContentViewCore.clearSslPreferences();
1528 // TODO(sgurun) remove after this rolls in. To keep internal tree happy.
1529 public void clearClientCertPreferences() { }
1532 * Method to return all hit test values relevant to public WebView API.
1533 * Note that this expose more data than needed for WebView.getHitTestResult.
1534 * Unsafely returning reference to mutable internal object to avoid excessive
1535 * garbage allocation on repeated calls.
1537 public HitTestData getLastHitTestResult() {
1538 if (mNativeAwContents == 0) return null;
1539 nativeUpdateLastHitTestData(mNativeAwContents);
1540 return mPossiblyStaleHitTestData;
1544 * @see android.webkit.WebView#requestFocusNodeHref()
1546 public void requestFocusNodeHref(Message msg) {
1547 if (msg == null || mNativeAwContents == 0) return;
1549 nativeUpdateLastHitTestData(mNativeAwContents);
1550 Bundle data = msg.getData();
1552 // In order to maintain compatibility with the old WebView's implementation,
1553 // the absolute (full) url is passed in the |url| field, not only the href attribute.
1554 // Note: HitTestData could be cleaned up at this point. See http://crbug.com/290992.
1555 data.putString("url", mPossiblyStaleHitTestData.href);
1556 data.putString("title", mPossiblyStaleHitTestData.anchorText);
1557 data.putString("src", mPossiblyStaleHitTestData.imgSrc);
1563 * @see android.webkit.WebView#requestImageRef()
1565 public void requestImageRef(Message msg) {
1566 if (msg == null || mNativeAwContents == 0) return;
1568 nativeUpdateLastHitTestData(mNativeAwContents);
1569 Bundle data = msg.getData();
1570 data.putString("url", mPossiblyStaleHitTestData.imgSrc);
1576 public float getPageScaleFactor() {
1577 return mPageScaleFactor;
1581 * @see android.webkit.WebView#getScale()
1583 * Please note that the scale returned is the page scale multiplied by
1584 * the screen density factor. See CTS WebViewTest.testSetInitialScale.
1586 public float getScale() {
1587 return (float)(mPageScaleFactor * mDIPScale);
1591 * @see android.webkit.WebView#flingScroll(int, int)
1593 public void flingScroll(int velocityX, int velocityY) {
1594 mScrollOffsetManager.flingScroll(velocityX, velocityY);
1598 * @see android.webkit.WebView#pageUp(boolean)
1600 public boolean pageUp(boolean top) {
1601 return mScrollOffsetManager.pageUp(top);
1605 * @see android.webkit.WebView#pageDown(boolean)
1607 public boolean pageDown(boolean bottom) {
1608 return mScrollOffsetManager.pageDown(bottom);
1612 * @see android.webkit.WebView#canZoomIn()
1614 // This method uses the term 'zoom' for legacy reasons, but relates
1615 // to what chrome calls the 'page scale factor'.
1616 public boolean canZoomIn() {
1617 final float zoomInExtent = mMaxPageScaleFactor - mPageScaleFactor;
1618 return zoomInExtent > ZOOM_CONTROLS_EPSILON;
1622 * @see android.webkit.WebView#canZoomOut()
1624 // This method uses the term 'zoom' for legacy reasons, but relates
1625 // to what chrome calls the 'page scale factor'.
1626 public boolean canZoomOut() {
1627 final float zoomOutExtent = mPageScaleFactor - mMinPageScaleFactor;
1628 return zoomOutExtent > ZOOM_CONTROLS_EPSILON;
1632 * @see android.webkit.WebView#zoomIn()
1634 // This method uses the term 'zoom' for legacy reasons, but relates
1635 // to what chrome calls the 'page scale factor'.
1636 public boolean zoomIn() {
1640 return zoomBy(1.25f);
1644 * @see android.webkit.WebView#zoomOut()
1646 // This method uses the term 'zoom' for legacy reasons, but relates
1647 // to what chrome calls the 'page scale factor'.
1648 public boolean zoomOut() {
1649 if (!canZoomOut()) {
1652 return zoomBy(0.8f);
1656 * @see android.webkit.WebView#zoomBy()
1658 // This method uses the term 'zoom' for legacy reasons, but relates
1659 // to what chrome calls the 'page scale factor'.
1660 public boolean zoomBy(float delta) {
1661 if (delta < 0.01f || delta > 100.0f) {
1662 throw new IllegalStateException("zoom delta value outside [0.01, 100] range.");
1664 return mContentViewCore.pinchByDelta(delta);
1668 * @see android.webkit.WebView#invokeZoomPicker()
1670 public void invokeZoomPicker() {
1671 mContentViewCore.invokeZoomPicker();
1675 * @see android.webkit.WebView#preauthorizePermission(Uri, long)
1677 public void preauthorizePermission(Uri origin, long resources) {
1678 if (mNativeAwContents == 0) return;
1679 nativePreauthorizePermission(mNativeAwContents, origin.toString(), resources);
1683 * @see ContentViewCore.evaluateJavaScript(String, JavaScriptCallback)
1685 public void evaluateJavaScript(String script, final ValueCallback<String> callback) {
1686 JavaScriptCallback jsCallback = null;
1687 if (callback != null) {
1688 jsCallback = new JavaScriptCallback() {
1690 public void handleJavaScriptResult(String jsonResult) {
1691 callback.onReceiveValue(jsonResult);
1696 mContentViewCore.evaluateJavaScript(script, jsCallback);
1700 * @see ContentViewCore.evaluateJavaScriptEvenIfNotYetNavigated(String)
1702 public void evaluateJavaScriptEvenIfNotYetNavigated(String script) {
1703 mContentViewCore.evaluateJavaScriptEvenIfNotYetNavigated(script);
1706 //--------------------------------------------------------------------------------------------
1707 // View and ViewGroup method implementations
1708 //--------------------------------------------------------------------------------------------
1711 * @see android.webkit.View#onTouchEvent()
1713 public boolean onTouchEvent(MotionEvent event) {
1714 return mAwViewMethods.onTouchEvent(event);
1718 * @see android.view.View#onHoverEvent()
1720 public boolean onHoverEvent(MotionEvent event) {
1721 return mAwViewMethods.onHoverEvent(event);
1725 * @see android.view.View#onGenericMotionEvent()
1727 public boolean onGenericMotionEvent(MotionEvent event) {
1728 return mContentViewCore.onGenericMotionEvent(event);
1732 * @see android.view.View#onConfigurationChanged()
1734 public void onConfigurationChanged(Configuration newConfig) {
1735 mAwViewMethods.onConfigurationChanged(newConfig);
1739 * @see android.view.View#onAttachedToWindow()
1741 public void onAttachedToWindow() {
1742 mTemporarilyDetached = false;
1743 mAwViewMethods.onAttachedToWindow();
1747 * @see android.view.View#onDetachedFromWindow()
1749 @SuppressLint("MissingSuperCall")
1750 public void onDetachedFromWindow() {
1751 mAwViewMethods.onDetachedFromWindow();
1755 * @see android.view.View#onWindowFocusChanged()
1757 public void onWindowFocusChanged(boolean hasWindowFocus) {
1758 mAwViewMethods.onWindowFocusChanged(hasWindowFocus);
1762 * @see android.view.View#onFocusChanged()
1764 public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
1765 if (!mTemporarilyDetached) {
1766 mAwViewMethods.onFocusChanged(focused, direction, previouslyFocusedRect);
1771 * @see android.view.View#onStartTemporaryDetach()
1773 public void onStartTemporaryDetach() {
1774 mTemporarilyDetached = true;
1778 * @see android.view.View#onFinishTemporaryDetach()
1780 public void onFinishTemporaryDetach() {
1781 mTemporarilyDetached = false;
1785 * @see android.view.View#onSizeChanged()
1787 public void onSizeChanged(int w, int h, int ow, int oh) {
1788 mAwViewMethods.onSizeChanged(w, h, ow, oh);
1792 * @see android.view.View#onVisibilityChanged()
1794 public void onVisibilityChanged(View changedView, int visibility) {
1795 mAwViewMethods.onVisibilityChanged(changedView, visibility);
1799 * @see android.view.View#onWindowVisibilityChanged()
1801 public void onWindowVisibilityChanged(int visibility) {
1802 mAwViewMethods.onWindowVisibilityChanged(visibility);
1805 private void setViewVisibilityInternal(boolean visible) {
1806 mIsViewVisible = visible;
1807 if (mNativeAwContents == 0) return;
1808 nativeSetViewVisibility(mNativeAwContents, mIsViewVisible);
1811 private void setWindowVisibilityInternal(boolean visible) {
1812 mIsWindowVisible = visible;
1813 if (mNativeAwContents == 0) return;
1814 nativeSetWindowVisibility(mNativeAwContents, mIsWindowVisible);
1818 * Key for opaque state in bundle. Note this is only public for tests.
1820 public static final String SAVE_RESTORE_STATE_KEY = "WEBVIEW_CHROMIUM_STATE";
1823 * Save the state of this AwContents into provided Bundle.
1824 * @return False if saving state failed.
1826 public boolean saveState(Bundle outState) {
1827 if (mNativeAwContents == 0 || outState == null) return false;
1829 byte[] state = nativeGetOpaqueState(mNativeAwContents);
1830 if (state == null) return false;
1832 outState.putByteArray(SAVE_RESTORE_STATE_KEY, state);
1837 * Restore the state of this AwContents into provided Bundle.
1838 * @param inState Must be a bundle returned by saveState.
1839 * @return False if restoring state failed.
1841 public boolean restoreState(Bundle inState) {
1842 if (mNativeAwContents == 0 || inState == null) return false;
1844 byte[] state = inState.getByteArray(SAVE_RESTORE_STATE_KEY);
1845 if (state == null) return false;
1847 boolean result = nativeRestoreFromOpaqueState(mNativeAwContents, state);
1849 // The onUpdateTitle callback normally happens when a page is loaded,
1850 // but is optimized out in the restoreState case because the title is
1851 // already restored. See WebContentsImpl::UpdateTitleForEntry. So we
1852 // call the callback explicitly here.
1853 if (result) mContentsClient.onReceivedTitle(mContentViewCore.getTitle());
1859 * @see ContentViewCore#addPossiblyUnsafeJavascriptInterface(Object, String, Class)
1861 public void addPossiblyUnsafeJavascriptInterface(Object object, String name,
1862 Class<? extends Annotation> requiredAnnotation) {
1863 mContentViewCore.addPossiblyUnsafeJavascriptInterface(object, name, requiredAnnotation);
1867 * @see android.webkit.WebView#removeJavascriptInterface(String)
1869 public void removeJavascriptInterface(String interfaceName) {
1870 mContentViewCore.removeJavascriptInterface(interfaceName);
1874 * If native accessibility (not script injection) is enabled, and if this is
1875 * running on JellyBean or later, returns an AccessibilityNodeProvider that
1876 * implements native accessibility for this view. Returns null otherwise.
1877 * @return The AccessibilityNodeProvider, if available, or null otherwise.
1879 public AccessibilityNodeProvider getAccessibilityNodeProvider() {
1880 return mContentViewCore.getAccessibilityNodeProvider();
1884 * @see android.webkit.WebView#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
1886 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
1887 mContentViewCore.onInitializeAccessibilityNodeInfo(info);
1891 * @see android.webkit.WebView#onInitializeAccessibilityEvent(AccessibilityEvent)
1893 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
1894 mContentViewCore.onInitializeAccessibilityEvent(event);
1897 public boolean supportsAccessibilityAction(int action) {
1898 return mContentViewCore.supportsAccessibilityAction(action);
1902 * @see android.webkit.WebView#performAccessibilityAction(int, Bundle)
1904 public boolean performAccessibilityAction(int action, Bundle arguments) {
1905 return mContentViewCore.performAccessibilityAction(action, arguments);
1909 * @see android.webkit.WebView#clearFormData()
1911 public void hideAutofillPopup() {
1912 if (mAwAutofillClient != null) {
1913 mAwAutofillClient.hideAutofillPopup();
1917 public void setNetworkAvailable(boolean networkUp) {
1918 if (mNativeAwContents == 0) return;
1919 nativeSetJsOnlineProperty(mNativeAwContents, networkUp);
1922 //--------------------------------------------------------------------------------------------
1923 // Methods called from native via JNI
1924 //--------------------------------------------------------------------------------------------
1927 private static void onDocumentHasImagesResponse(boolean result, Message message) {
1928 message.arg1 = result ? 1 : 0;
1929 message.sendToTarget();
1933 private void onReceivedTouchIconUrl(String url, boolean precomposed) {
1934 mContentsClient.onReceivedTouchIconUrl(url, precomposed);
1938 private void onReceivedIcon(Bitmap bitmap) {
1939 mContentsClient.onReceivedIcon(bitmap);
1943 /** Callback for generateMHTML. */
1945 private static void generateMHTMLCallback(
1946 String path, long size, ValueCallback<String> callback) {
1947 if (callback == null) return;
1948 callback.onReceiveValue(size < 0 ? null : path);
1952 private void onReceivedHttpAuthRequest(AwHttpAuthHandler handler, String host, String realm) {
1953 mContentsClient.onReceivedHttpAuthRequest(handler, host, realm);
1956 private class AwGeolocationCallback implements GeolocationPermissions.Callback {
1959 public void invoke(final String origin, final boolean allow, final boolean retain) {
1960 ThreadUtils.runOnUiThread(new Runnable() {
1965 mBrowserContext.getGeolocationPermissions().allow(origin);
1967 mBrowserContext.getGeolocationPermissions().deny(origin);
1970 if (mNativeAwContents == 0) return;
1971 nativeInvokeGeolocationCallback(mNativeAwContents, allow, origin);
1978 private void onGeolocationPermissionsShowPrompt(String origin) {
1979 if (mNativeAwContents == 0) return;
1980 AwGeolocationPermissions permissions = mBrowserContext.getGeolocationPermissions();
1981 // Reject if geoloaction is disabled, or the origin has a retained deny
1982 if (!mSettings.getGeolocationEnabled()) {
1983 nativeInvokeGeolocationCallback(mNativeAwContents, false, origin);
1986 // Allow if the origin has a retained allow
1987 if (permissions.hasOrigin(origin)) {
1988 nativeInvokeGeolocationCallback(mNativeAwContents, permissions.isOriginAllowed(origin),
1992 mContentsClient.onGeolocationPermissionsShowPrompt(
1993 origin, new AwGeolocationCallback());
1997 private void onGeolocationPermissionsHidePrompt() {
1998 mContentsClient.onGeolocationPermissionsHidePrompt();
2002 private void onPermissionRequest(AwPermissionRequest awPermissionRequest) {
2003 mContentsClient.onPermissionRequest(awPermissionRequest);
2007 private void onPermissionRequestCanceled(AwPermissionRequest awPermissionRequest) {
2008 mContentsClient.onPermissionRequestCanceled(awPermissionRequest);
2012 public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
2013 boolean isDoneCounting) {
2014 mContentsClient.onFindResultReceived(activeMatchOrdinal, numberOfMatches, isDoneCounting);
2018 public void onNewPicture() {
2019 // Don't call capturePicture() here but instead defer it until the posted task runs within
2020 // the callback helper, to avoid doubling back into the renderer compositor in the middle
2021 // of the notification it is sending up to here.
2022 mContentsClient.getCallbackHelper().postOnNewPicture(mPictureListenerContentProvider);
2025 // Called as a result of nativeUpdateLastHitTestData.
2027 private void updateHitTestData(
2028 int type, String extra, String href, String anchorText, String imgSrc) {
2029 mPossiblyStaleHitTestData.hitTestResultType = type;
2030 mPossiblyStaleHitTestData.hitTestResultExtraData = extra;
2031 mPossiblyStaleHitTestData.href = href;
2032 mPossiblyStaleHitTestData.anchorText = anchorText;
2033 mPossiblyStaleHitTestData.imgSrc = imgSrc;
2037 private boolean requestDrawGL(Canvas canvas, boolean waitForCompletion) {
2038 return mNativeGLDelegate.requestDrawGL(canvas, waitForCompletion, mContainerView);
2041 private static final boolean SUPPORTS_ON_ANIMATION =
2042 Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
2045 private void postInvalidateOnAnimation() {
2046 if (SUPPORTS_ON_ANIMATION && !mWindowAndroid.isInsideVSync()) {
2047 mContainerView.postInvalidateOnAnimation();
2049 mContainerView.invalidate();
2053 // Call postInvalidateOnAnimation for invalidations. This is only used to synchronize
2054 // draw functor destruction.
2056 private void invalidateOnFunctorDestroy() {
2057 mContainerView.invalidate();
2061 private int[] getLocationOnScreen() {
2062 int[] result = new int[2];
2063 mContainerView.getLocationOnScreen(result);
2068 private void onWebLayoutPageScaleFactorChanged(float webLayoutPageScaleFactor) {
2069 // This change notification comes from the renderer thread, not from the cc/ impl thread.
2070 mLayoutSizer.onPageScaleChanged(webLayoutPageScaleFactor);
2074 private void onWebLayoutContentsSizeChanged(int widthCss, int heightCss) {
2075 // This change notification comes from the renderer thread, not from the cc/ impl thread.
2076 mLayoutSizer.onContentSizeChanged(widthCss, heightCss);
2080 private void scrollContainerViewTo(int x, int y) {
2081 mScrollOffsetManager.scrollContainerViewTo(x, y);
2085 private boolean isFlingActive() {
2086 return mScrollOffsetManager.isFlingActive();
2090 private void updateScrollState(int maxContainerViewScrollOffsetX,
2091 int maxContainerViewScrollOffsetY, int contentWidthDip, int contentHeightDip,
2092 float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor) {
2093 mContentWidthDip = contentWidthDip;
2094 mContentHeightDip = contentHeightDip;
2095 mScrollOffsetManager.setMaxScrollOffset(maxContainerViewScrollOffsetX,
2096 maxContainerViewScrollOffsetY);
2097 setPageScaleFactorAndLimits(pageScaleFactor, minPageScaleFactor, maxPageScaleFactor);
2101 private void setAwAutofillClient(AwAutofillClient client) {
2102 mAwAutofillClient = client;
2103 client.init(mContentViewCore);
2107 private void didOverscroll(int deltaX, int deltaY) {
2108 if (mOverScrollGlow != null) {
2109 mOverScrollGlow.setOverScrollDeltas(deltaX, deltaY);
2112 mScrollOffsetManager.overScrollBy(deltaX, deltaY);
2114 if (mOverScrollGlow != null && mOverScrollGlow.isAnimating()) {
2115 mContainerView.invalidate();
2119 // -------------------------------------------------------------------------------------------
2121 // -------------------------------------------------------------------------------------------
2123 private void setPageScaleFactorAndLimits(
2124 float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor) {
2125 if (mPageScaleFactor == pageScaleFactor &&
2126 mMinPageScaleFactor == minPageScaleFactor &&
2127 mMaxPageScaleFactor == maxPageScaleFactor) {
2130 mMinPageScaleFactor = minPageScaleFactor;
2131 mMaxPageScaleFactor = maxPageScaleFactor;
2132 if (mPageScaleFactor != pageScaleFactor) {
2133 float oldPageScaleFactor = mPageScaleFactor;
2134 mPageScaleFactor = pageScaleFactor;
2135 mContentsClient.getCallbackHelper().postOnScaleChangedScaled(
2136 (float)(oldPageScaleFactor * mDIPScale),
2137 (float)(mPageScaleFactor * mDIPScale));
2141 private void saveWebArchiveInternal(String path, final ValueCallback<String> callback) {
2142 if (path == null || mNativeAwContents == 0) {
2143 ThreadUtils.runOnUiThread(new Runnable() {
2146 callback.onReceiveValue(null);
2150 nativeGenerateMHTML(mNativeAwContents, path, callback);
2155 * Try to generate a pathname for saving an MHTML archive. This roughly follows WebView's
2158 private static String generateArchiveAutoNamePath(String originalUrl, String baseName) {
2160 if (originalUrl != null && !originalUrl.isEmpty()) {
2162 String path = new URL(originalUrl).getPath();
2163 int lastSlash = path.lastIndexOf('/');
2164 if (lastSlash > 0) {
2165 name = path.substring(lastSlash + 1);
2169 } catch (MalformedURLException e) {
2170 // If it fails parsing the URL, we'll just rely on the default name below.
2174 if (TextUtils.isEmpty(name)) name = "index";
2176 String testName = baseName + name + WEB_ARCHIVE_EXTENSION;
2177 if (!new File(testName).exists()) return testName;
2179 for (int i = 1; i < 100; i++) {
2180 testName = baseName + name + "-" + i + WEB_ARCHIVE_EXTENSION;
2181 if (!new File(testName).exists()) return testName;
2184 Log.e(TAG, "Unable to auto generate archive name for path: " + baseName);
2188 public void extractSmartClipData(int x, int y, int width, int height) {
2189 mContentViewCore.extractSmartClipData(x, y, width, height);
2192 public void setSmartClipDataListener(ContentViewCore.SmartClipDataListener listener) {
2193 mContentViewCore.setSmartClipDataListener(listener);
2196 // --------------------------------------------------------------------------------------------
2197 // This is the AwViewMethods implementation that does real work. The AwViewMethodsImpl is
2198 // hooked up to the WebView in embedded mode and to the FullScreenView in fullscreen mode,
2199 // but not to both at the same time.
2200 private class AwViewMethodsImpl implements AwViewMethods {
2201 private int mLayerType = View.LAYER_TYPE_NONE;
2202 private ComponentCallbacks2 mComponentCallbacks;
2204 // Only valid within software onDraw().
2205 private final Rect mClipBoundsTemporary = new Rect();
2208 public void onDraw(Canvas canvas) {
2209 if (mNativeAwContents == 0) {
2210 canvas.drawColor(getEffectiveBackgroundColor());
2214 // For hardware draws, the clip at onDraw time could be different
2215 // from the clip during DrawGL.
2216 if (!canvas.isHardwareAccelerated() && !canvas.getClipBounds(mClipBoundsTemporary)) {
2220 mScrollOffsetManager.syncScrollOffsetFromOnDraw();
2221 Rect globalVisibleRect = getGlobalVisibleRect();
2222 if (!nativeOnDraw(mNativeAwContents, canvas, canvas.isHardwareAccelerated(),
2223 mContainerView.getScrollX(), mContainerView.getScrollY(),
2224 globalVisibleRect.left, globalVisibleRect.top,
2225 globalVisibleRect.right, globalVisibleRect.bottom)) {
2226 // Can happen during initialization when compositor is not set
2227 // up. Or when clearView
2228 // is in effect. Just draw background color instead.
2229 canvas.drawColor(getEffectiveBackgroundColor());
2232 if (mOverScrollGlow != null && mOverScrollGlow.drawEdgeGlows(canvas,
2233 mScrollOffsetManager.computeMaximumHorizontalScrollOffset(),
2234 mScrollOffsetManager.computeMaximumVerticalScrollOffset())) {
2235 mContainerView.invalidate();
2240 public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
2241 mLayoutSizer.onMeasure(widthMeasureSpec, heightMeasureSpec);
2245 public void requestFocus() {
2246 if (mNativeAwContents == 0) return;
2247 if (!mContainerView.isInTouchMode() && mSettings.shouldFocusFirstNode()) {
2248 nativeFocusFirstNode(mNativeAwContents);
2253 public void setLayerType(int layerType, Paint paint) {
2254 mLayerType = layerType;
2255 updateHardwareAcceleratedFeaturesToggle();
2258 private void updateHardwareAcceleratedFeaturesToggle() {
2259 mSettings.setEnableSupportedHardwareAcceleratedFeatures(
2260 mIsAttachedToWindow && mContainerView.isHardwareAccelerated() &&
2261 (mLayerType == View.LAYER_TYPE_NONE
2262 || mLayerType == View.LAYER_TYPE_HARDWARE));
2266 public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
2267 return mContentViewCore.onCreateInputConnection(outAttrs);
2271 public boolean onKeyUp(int keyCode, KeyEvent event) {
2272 return mContentViewCore.onKeyUp(keyCode, event);
2276 public boolean dispatchKeyEvent(KeyEvent event) {
2277 if (isDpadEvent(event)) {
2278 mSettings.setSpatialNavigationEnabled(true);
2280 return mContentViewCore.dispatchKeyEvent(event);
2283 private boolean isDpadEvent(KeyEvent event) {
2284 if (event.getAction() == KeyEvent.ACTION_DOWN) {
2285 switch (event.getKeyCode()) {
2286 case KeyEvent.KEYCODE_DPAD_CENTER:
2287 case KeyEvent.KEYCODE_DPAD_DOWN:
2288 case KeyEvent.KEYCODE_DPAD_UP:
2289 case KeyEvent.KEYCODE_DPAD_LEFT:
2290 case KeyEvent.KEYCODE_DPAD_RIGHT:
2298 public boolean onTouchEvent(MotionEvent event) {
2299 if (mNativeAwContents == 0) return false;
2301 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
2302 mSettings.setSpatialNavigationEnabled(false);
2305 mScrollOffsetManager.setProcessingTouchEvent(true);
2306 boolean rv = mContentViewCore.onTouchEvent(event);
2307 mScrollOffsetManager.setProcessingTouchEvent(false);
2309 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
2310 int actionIndex = event.getActionIndex();
2312 // Note this will trigger IPC back to browser even if nothing is
2314 nativeRequestNewHitTestDataAt(mNativeAwContents,
2315 (int) Math.round(event.getX(actionIndex) / mDIPScale),
2316 (int) Math.round(event.getY(actionIndex) / mDIPScale));
2319 if (mOverScrollGlow != null) {
2320 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
2321 mOverScrollGlow.setShouldPull(true);
2322 } else if (event.getActionMasked() == MotionEvent.ACTION_UP ||
2323 event.getActionMasked() == MotionEvent.ACTION_CANCEL) {
2324 mOverScrollGlow.setShouldPull(false);
2325 mOverScrollGlow.releaseAll();
2333 public boolean onHoverEvent(MotionEvent event) {
2334 return mContentViewCore.onHoverEvent(event);
2338 public boolean onGenericMotionEvent(MotionEvent event) {
2339 return mContentViewCore.onGenericMotionEvent(event);
2343 public void onConfigurationChanged(Configuration newConfig) {
2344 mContentViewCore.onConfigurationChanged(newConfig);
2348 public void onAttachedToWindow() {
2349 if (mNativeAwContents == 0) return;
2350 if (mIsAttachedToWindow) {
2351 Log.w(TAG, "onAttachedToWindow called when already attached. Ignoring");
2354 mIsAttachedToWindow = true;
2356 mContentViewCore.onAttachedToWindow();
2357 nativeOnAttachedToWindow(mNativeAwContents, mContainerView.getWidth(),
2358 mContainerView.getHeight());
2359 updateHardwareAcceleratedFeaturesToggle();
2361 if (mComponentCallbacks != null) return;
2362 mComponentCallbacks = new AwComponentCallbacks();
2363 mContext.registerComponentCallbacks(mComponentCallbacks);
2367 public void onDetachedFromWindow() {
2368 if (!mIsAttachedToWindow) {
2369 Log.w(TAG, "onDetachedFromWindow called when already detached. Ignoring");
2372 mIsAttachedToWindow = false;
2373 hideAutofillPopup();
2374 if (mNativeAwContents != 0) {
2375 nativeOnDetachedFromWindow(mNativeAwContents);
2378 mContentViewCore.onDetachedFromWindow();
2379 updateHardwareAcceleratedFeaturesToggle();
2381 if (mComponentCallbacks != null) {
2382 mContext.unregisterComponentCallbacks(mComponentCallbacks);
2383 mComponentCallbacks = null;
2386 mScrollAccessibilityHelper.removePostedCallbacks();
2387 mNativeGLDelegate.detachGLFunctor();
2391 public void onWindowFocusChanged(boolean hasWindowFocus) {
2392 mWindowFocused = hasWindowFocus;
2393 mContentViewCore.onWindowFocusChanged(hasWindowFocus);
2397 public void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
2398 mContainerViewFocused = focused;
2399 mContentViewCore.onFocusChanged(focused);
2403 public void onSizeChanged(int w, int h, int ow, int oh) {
2404 if (mNativeAwContents == 0) return;
2405 mScrollOffsetManager.setContainerViewSize(w, h);
2406 // The AwLayoutSizer needs to go first so that if we're in
2407 // fixedLayoutSize mode the update
2408 // to enter fixedLayoutSize mode is sent before the first resize
2410 mLayoutSizer.onSizeChanged(w, h, ow, oh);
2411 mContentViewCore.onPhysicalBackingSizeChanged(w, h);
2412 mContentViewCore.onSizeChanged(w, h, ow, oh);
2413 nativeOnSizeChanged(mNativeAwContents, w, h, ow, oh);
2417 public void onVisibilityChanged(View changedView, int visibility) {
2418 boolean viewVisible = mContainerView.getVisibility() == View.VISIBLE;
2419 if (mIsViewVisible == viewVisible) return;
2420 setViewVisibilityInternal(viewVisible);
2424 public void onWindowVisibilityChanged(int visibility) {
2425 boolean windowVisible = visibility == View.VISIBLE;
2426 if (mIsWindowVisible == windowVisible) return;
2427 setWindowVisibilityInternal(windowVisible);
2431 // Return true if the GeolocationPermissionAPI should be used.
2433 private boolean useLegacyGeolocationPermissionAPI() {
2434 // Always return true since we are not ready to swap the geolocation yet.
2435 // TODO: If we decide not to migrate the geolocation, there are some unreachable
2436 // code need to remove. http://crbug.com/396184.
2440 //--------------------------------------------------------------------------------------------
2442 //--------------------------------------------------------------------------------------------
2444 private static native long nativeInit(AwBrowserContext browserContext);
2445 private static native void nativeDestroy(long nativeAwContents);
2446 private static native void nativeSetAwDrawSWFunctionTable(long functionTablePointer);
2447 private static native void nativeSetAwDrawGLFunctionTable(long functionTablePointer);
2448 private static native long nativeGetAwDrawGLFunction();
2449 private static native int nativeGetNativeInstanceCount();
2450 private static native void nativeSetShouldDownloadFavicons();
2452 private native void nativeSetJavaPeers(long nativeAwContents, AwContents awContents,
2453 AwWebContentsDelegate webViewWebContentsDelegate,
2454 AwContentsClientBridge contentsClientBridge,
2455 AwContentsIoThreadClient ioThreadClient,
2456 InterceptNavigationDelegate navigationInterceptionDelegate);
2457 private native long nativeGetWebContents(long nativeAwContents);
2459 private native void nativeDocumentHasImages(long nativeAwContents, Message message);
2460 private native void nativeGenerateMHTML(
2461 long nativeAwContents, String path, ValueCallback<String> callback);
2463 private native void nativeAddVisitedLinks(long nativeAwContents, String[] visitedLinks);
2464 private native boolean nativeOnDraw(long nativeAwContents, Canvas canvas,
2465 boolean isHardwareAccelerated, int scrollX, int scrollY,
2466 int visibleLeft, int visibleTop, int visibleRight, int visibleBottom);
2467 private native void nativeFindAllAsync(long nativeAwContents, String searchString);
2468 private native void nativeFindNext(long nativeAwContents, boolean forward);
2469 private native void nativeClearMatches(long nativeAwContents);
2470 private native void nativeClearCache(long nativeAwContents, boolean includeDiskFiles);
2471 private native byte[] nativeGetCertificate(long nativeAwContents);
2473 // Coordinates in desity independent pixels.
2474 private native void nativeRequestNewHitTestDataAt(long nativeAwContents, int x, int y);
2475 private native void nativeUpdateLastHitTestData(long nativeAwContents);
2477 private native void nativeOnSizeChanged(long nativeAwContents, int w, int h, int ow, int oh);
2478 private native void nativeScrollTo(long nativeAwContents, int x, int y);
2479 private native void nativeSetViewVisibility(long nativeAwContents, boolean visible);
2480 private native void nativeSetWindowVisibility(long nativeAwContents, boolean visible);
2481 private native void nativeSetIsPaused(long nativeAwContents, boolean paused);
2482 private native void nativeOnAttachedToWindow(long nativeAwContents, int w, int h);
2483 private static native void nativeOnDetachedFromWindow(long nativeAwContents);
2484 private native void nativeSetDipScale(long nativeAwContents, float dipScale);
2486 // Returns null if save state fails.
2487 private native byte[] nativeGetOpaqueState(long nativeAwContents);
2489 // Returns false if restore state fails.
2490 private native boolean nativeRestoreFromOpaqueState(long nativeAwContents, byte[] state);
2492 private native long nativeReleasePopupAwContents(long nativeAwContents);
2493 private native void nativeFocusFirstNode(long nativeAwContents);
2494 private native void nativeSetBackgroundColor(long nativeAwContents, int color);
2496 private native long nativeGetAwDrawGLViewContext(long nativeAwContents);
2497 private native long nativeCapturePicture(long nativeAwContents, int width, int height);
2498 private native void nativeEnableOnNewPicture(long nativeAwContents, boolean enabled);
2499 private native void nativeClearView(long nativeAwContents);
2500 private native void nativeSetExtraHeadersForUrl(long nativeAwContents,
2501 String url, String extraHeaders);
2503 private native void nativeInvokeGeolocationCallback(
2504 long nativeAwContents, boolean value, String requestingFrame);
2506 private native void nativeSetJsOnlineProperty(long nativeAwContents, boolean networkUp);
2508 private native void nativeTrimMemory(long nativeAwContents, int level, boolean visible);
2510 private native void nativeCreatePdfExporter(long nativeAwContents, AwPdfExporter awPdfExporter);
2512 private native void nativePreauthorizePermission(long nativeAwContents, String origin,