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.content.browser;
7 import android.annotation.SuppressLint;
8 import android.app.Activity;
9 import android.app.SearchManager;
10 import android.content.ContentResolver;
11 import android.content.Context;
12 import android.content.Intent;
13 import android.content.pm.PackageManager;
14 import android.content.res.Configuration;
15 import android.database.ContentObserver;
16 import android.graphics.Bitmap;
17 import android.graphics.Canvas;
18 import android.graphics.Color;
19 import android.graphics.Rect;
20 import android.net.Uri;
21 import android.os.Build;
22 import android.os.Bundle;
23 import android.os.Handler;
24 import android.os.ResultReceiver;
25 import android.os.SystemClock;
26 import android.provider.Browser;
27 import android.provider.Settings;
28 import android.text.Editable;
29 import android.text.Selection;
30 import android.text.TextUtils;
31 import android.util.Log;
32 import android.view.ActionMode;
33 import android.view.HapticFeedbackConstants;
34 import android.view.InputDevice;
35 import android.view.KeyEvent;
36 import android.view.MotionEvent;
37 import android.view.View;
38 import android.view.ViewGroup;
39 import android.view.accessibility.AccessibilityEvent;
40 import android.view.accessibility.AccessibilityManager;
41 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
42 import android.view.accessibility.AccessibilityNodeInfo;
43 import android.view.accessibility.AccessibilityNodeProvider;
44 import android.view.inputmethod.EditorInfo;
45 import android.view.inputmethod.InputConnection;
46 import android.view.inputmethod.InputMethodManager;
47 import android.widget.FrameLayout;
49 import com.google.common.annotations.VisibleForTesting;
51 import org.chromium.base.ApiCompatibilityUtils;
52 import org.chromium.base.CalledByNative;
53 import org.chromium.base.CommandLine;
54 import org.chromium.base.JNINamespace;
55 import org.chromium.base.ObserverList;
56 import org.chromium.base.ObserverList.RewindableIterator;
57 import org.chromium.base.TraceEvent;
58 import org.chromium.content.R;
59 import org.chromium.content.browser.ScreenOrientationListener.ScreenOrientationObserver;
60 import org.chromium.content.browser.accessibility.AccessibilityInjector;
61 import org.chromium.content.browser.accessibility.BrowserAccessibilityManager;
62 import org.chromium.content.browser.input.AdapterInputConnection;
63 import org.chromium.content.browser.input.GamepadList;
64 import org.chromium.content.browser.input.HandleView;
65 import org.chromium.content.browser.input.ImeAdapter;
66 import org.chromium.content.browser.input.ImeAdapter.AdapterInputConnectionFactory;
67 import org.chromium.content.browser.input.InputMethodManagerWrapper;
68 import org.chromium.content.browser.input.InsertionHandleController;
69 import org.chromium.content.browser.input.SelectPopup;
70 import org.chromium.content.browser.input.SelectPopupDialog;
71 import org.chromium.content.browser.input.SelectPopupDropdown;
72 import org.chromium.content.browser.input.SelectPopupItem;
73 import org.chromium.content.browser.input.SelectionHandleController;
74 import org.chromium.content.common.ContentSwitches;
75 import org.chromium.content_public.browser.GestureStateListener;
76 import org.chromium.content_public.browser.WebContents;
77 import org.chromium.ui.base.ViewAndroid;
78 import org.chromium.ui.base.ViewAndroidDelegate;
79 import org.chromium.ui.base.WindowAndroid;
80 import org.chromium.ui.gfx.DeviceDisplayInfo;
82 import java.lang.annotation.Annotation;
83 import java.lang.reflect.Field;
84 import java.util.ArrayList;
85 import java.util.HashMap;
86 import java.util.HashSet;
87 import java.util.List;
91 * Provides a Java-side 'wrapper' around a WebContent (native) instance.
92 * Contains all the major functionality necessary to manage the lifecycle of a ContentView without
93 * being tied to the view system.
95 @JNINamespace("content")
96 public class ContentViewCore
97 implements NavigationClient, AccessibilityStateChangeListener, ScreenOrientationObserver {
99 private static final String TAG = "ContentViewCore";
101 // Used to avoid enabling zooming in / out if resulting zooming will
102 // produce little visible difference.
103 private static final float ZOOM_CONTROLS_EPSILON = 0.007f;
105 // Used to represent gestures for long press and long tap.
106 private static final int IS_LONG_PRESS = 1;
107 private static final int IS_LONG_TAP = 2;
109 // Length of the delay (in ms) before fading in handles after the last page movement.
110 private static final int TEXT_HANDLE_FADE_IN_DELAY = 300;
112 // If the embedder adds a JavaScript interface object that contains an indirect reference to
113 // the ContentViewCore, then storing a strong ref to the interface object on the native
114 // side would prevent garbage collection of the ContentViewCore (as that strong ref would
115 // create a new GC root).
116 // For that reason, we store only a weak reference to the interface object on the
117 // native side. However we still need a strong reference on the Java side to
118 // prevent garbage collection if the embedder doesn't maintain their own ref to the
119 // interface object - the Java side ref won't create a new GC root.
120 // This map stores those refernces. We put into the map on addJavaScriptInterface()
121 // and remove from it in removeJavaScriptInterface().
122 private final Map<String, Object> mJavaScriptInterfaces = new HashMap<String, Object>();
124 // Additionally, we keep track of all Java bound JS objects that are in use on the
125 // current page to ensure that they are not garbage collected until the page is
126 // navigated. This includes interface objects that have been removed
127 // via the removeJavaScriptInterface API and transient objects returned from methods
128 // on the interface object. Note we use HashSet rather than Set as the native side
129 // expects HashSet (no bindings for interfaces).
130 private final HashSet<Object> mRetainedJavaScriptObjects = new HashSet<Object>();
133 * Interface that consumers of {@link ContentViewCore} must implement to allow the proper
134 * dispatching of view methods through the containing view.
137 * All methods with the "super_" prefix should be routed to the parent of the
138 * implementing container view.
140 @SuppressWarnings("javadoc")
141 public interface InternalAccessDelegate {
143 * @see View#drawChild(Canvas, View, long)
145 boolean drawChild(Canvas canvas, View child, long drawingTime);
148 * @see View#onKeyUp(keyCode, KeyEvent)
150 boolean super_onKeyUp(int keyCode, KeyEvent event);
153 * @see View#dispatchKeyEventPreIme(KeyEvent)
155 boolean super_dispatchKeyEventPreIme(KeyEvent event);
158 * @see View#dispatchKeyEvent(KeyEvent)
160 boolean super_dispatchKeyEvent(KeyEvent event);
163 * @see View#onGenericMotionEvent(MotionEvent)
165 boolean super_onGenericMotionEvent(MotionEvent event);
168 * @see View#onConfigurationChanged(Configuration)
170 void super_onConfigurationChanged(Configuration newConfig);
173 * @see View#onScrollChanged(int, int, int, int)
175 void onScrollChanged(int lPix, int tPix, int oldlPix, int oldtPix);
178 * @see View#awakenScrollBars()
180 boolean awakenScrollBars();
183 * @see View#awakenScrollBars(int, boolean)
185 boolean super_awakenScrollBars(int startDelay, boolean invalidate);
189 * An interface for controlling visibility and state of embedder-provided zoom controls.
191 public interface ZoomControlsDelegate {
193 * Called when it's reasonable to show zoom controls.
195 void invokeZoomPicker();
198 * Called when zoom controls need to be hidden (e.g. when the view hides).
200 void dismissZoomPicker();
203 * Called when page scale has been changed, so the controls can update their state.
205 void updateZoomControls();
209 * An interface that allows the embedder to be notified when the results of
210 * extractSmartClipData are available.
212 public interface SmartClipDataListener {
213 public void onSmartClipDataExtracted(String result);
216 private final Context mContext;
217 private ViewGroup mContainerView;
218 private InternalAccessDelegate mContainerViewInternals;
219 private WebContents mWebContents;
220 private WebContentsObserverAndroid mWebContentsObserver;
222 private ContentViewClient mContentViewClient;
224 private ContentSettings mContentSettings;
226 // Native pointer to C++ ContentViewCoreImpl object which will be set by nativeInit().
227 private long mNativeContentViewCore = 0;
229 private final ObserverList<GestureStateListener> mGestureStateListeners;
230 private final RewindableIterator<GestureStateListener> mGestureStateListenersIterator;
231 private ZoomControlsDelegate mZoomControlsDelegate;
233 private PopupZoomer mPopupZoomer;
234 private SelectPopup mSelectPopup;
236 private Runnable mFakeMouseMoveRunnable = null;
238 // Only valid when focused on a text / password field.
239 private ImeAdapter mImeAdapter;
240 private ImeAdapter.AdapterInputConnectionFactory mAdapterInputConnectionFactory;
241 private AdapterInputConnection mInputConnection;
242 private InputMethodManagerWrapper mInputMethodManagerWrapper;
244 private SelectionHandleController mSelectionHandleController;
245 private InsertionHandleController mInsertionHandleController;
247 private Runnable mDeferredHandleFadeInRunnable;
249 private PositionObserver mPositionObserver;
250 private PositionObserver.Listener mPositionListener;
252 // Size of the viewport in physical pixels as set from onSizeChanged.
253 private int mViewportWidthPix;
254 private int mViewportHeightPix;
255 private int mPhysicalBackingWidthPix;
256 private int mPhysicalBackingHeightPix;
257 private int mOverdrawBottomHeightPix;
258 private int mViewportSizeOffsetWidthPix;
259 private int mViewportSizeOffsetHeightPix;
261 // Cached copy of all positions and scales as reported by the renderer.
262 private final RenderCoordinates mRenderCoordinates;
264 private final RenderCoordinates.NormalizedPoint mStartHandlePoint;
265 private final RenderCoordinates.NormalizedPoint mEndHandlePoint;
266 private final RenderCoordinates.NormalizedPoint mInsertionHandlePoint;
268 // Tracks whether a selection is currently active. When applied to selected text, indicates
269 // whether the last selected text is still highlighted.
270 private boolean mHasSelection;
271 private String mLastSelectedText;
272 private boolean mSelectionEditable;
273 private ActionMode mActionMode;
274 private boolean mUnselectAllOnActionModeDismiss;
276 // Delegate that will handle GET downloads, and be notified of completion of POST downloads.
277 private ContentViewDownloadDelegate mDownloadDelegate;
279 // The AccessibilityInjector that handles loading Accessibility scripts into the web page.
280 private AccessibilityInjector mAccessibilityInjector;
282 // Whether native accessibility, i.e. without any script injection, is allowed.
283 private boolean mNativeAccessibilityAllowed;
285 // Whether native accessibility, i.e. without any script injection, has been enabled.
286 private boolean mNativeAccessibilityEnabled;
288 // Handles native accessibility, i.e. without any script injection.
289 private BrowserAccessibilityManager mBrowserAccessibilityManager;
291 // System accessibility service.
292 private final AccessibilityManager mAccessibilityManager;
294 // Accessibility touch exploration state.
295 private boolean mTouchExplorationEnabled;
297 // Allows us to dynamically respond when the accessibility script injection flag changes.
298 private ContentObserver mAccessibilityScriptInjectionObserver;
300 // Temporary notification to tell onSizeChanged to focus a form element,
301 // because the OSK was just brought up.
302 private final Rect mFocusPreOSKViewportRect = new Rect();
304 // On tap this will store the x, y coordinates of the touch.
305 private int mLastTapX;
306 private int mLastTapY;
308 // Whether a touch scroll sequence is active, used to hide text selection
309 // handles. Note that a scroll sequence will *always* bound a pinch
310 // sequence, so this will also be true for the duration of a pinch gesture.
311 private boolean mTouchScrollInProgress;
313 // The outstanding fling start events that hasn't got fling end yet. It may be > 1 because
314 // onNativeFlingStopped() is called asynchronously.
315 private int mPotentiallyActiveFlingCount;
317 private ViewAndroid mViewAndroid;
319 private SmartClipDataListener mSmartClipDataListener = null;
321 // This holds the state of editable text (e.g. contents of <input>, contenteditable) of
322 // a focused element.
323 // Every time the user, IME, javascript (Blink), autofill etc. modifies the content, the new
324 // state must be reflected to this to keep consistency.
325 private final Editable mEditable;
328 * PID used to indicate an invalid render process.
330 // Keep in sync with the value returned from ContentViewCoreImpl::GetCurrentRendererProcessId()
331 // if there is no render process.
332 public static final int INVALID_RENDER_PROCESS_PID = 0;
334 // Offsets for the events that passes through this ContentViewCore.
335 private float mCurrentTouchOffsetX;
336 private float mCurrentTouchOffsetY;
339 * Constructs a new ContentViewCore. Embedders must call initialize() after constructing
340 * a ContentViewCore and before using it.
342 * @param context The context used to create this.
344 public ContentViewCore(Context context) {
347 mAdapterInputConnectionFactory = new AdapterInputConnectionFactory();
348 mInputMethodManagerWrapper = new InputMethodManagerWrapper(mContext);
350 mRenderCoordinates = new RenderCoordinates();
351 float deviceScaleFactor = getContext().getResources().getDisplayMetrics().density;
352 String forceScaleFactor = CommandLine.getInstance().getSwitchValue(
353 ContentSwitches.FORCE_DEVICE_SCALE_FACTOR);
354 if (forceScaleFactor != null) {
355 deviceScaleFactor = Float.valueOf(forceScaleFactor);
357 mRenderCoordinates.setDeviceScaleFactor(deviceScaleFactor);
358 mStartHandlePoint = mRenderCoordinates.createNormalizedPoint();
359 mEndHandlePoint = mRenderCoordinates.createNormalizedPoint();
360 mInsertionHandlePoint = mRenderCoordinates.createNormalizedPoint();
361 mAccessibilityManager = (AccessibilityManager)
362 getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
363 mGestureStateListeners = new ObserverList<GestureStateListener>();
364 mGestureStateListenersIterator = mGestureStateListeners.rewindableIterator();
366 mEditable = Editable.Factory.getInstance().newEditable("");
367 Selection.setSelection(mEditable, 0);
371 * @return The context used for creating this ContentViewCore.
374 public Context getContext() {
379 * @return The ViewGroup that all view actions of this ContentViewCore should interact with.
381 public ViewGroup getContainerView() {
382 return mContainerView;
386 * @return The WebContents currently being rendered.
388 public WebContents getWebContents() {
393 * Specifies how much smaller the WebKit layout size should be relative to the size of this
395 * @param offsetXPix The X amount in pixels to shrink the viewport by.
396 * @param offsetYPix The Y amount in pixels to shrink the viewport by.
398 public void setViewportSizeOffset(int offsetXPix, int offsetYPix) {
399 if (offsetXPix != mViewportSizeOffsetWidthPix ||
400 offsetYPix != mViewportSizeOffsetHeightPix) {
401 mViewportSizeOffsetWidthPix = offsetXPix;
402 mViewportSizeOffsetHeightPix = offsetYPix;
403 if (mNativeContentViewCore != 0) nativeWasResized(mNativeContentViewCore);
408 * Returns a delegate that can be used to add and remove views from the ContainerView.
410 * NOTE: Use with care, as not all ContentViewCore users setup their ContainerView in the same
411 * way. In particular, the Android WebView has limitations on what implementation details can
412 * be provided via a child view, as they are visible in the API and could introduce
413 * compatibility breaks with existing applications. If in doubt, contact the
414 * android_webview/OWNERS
416 * @return A ViewAndroidDelegate that can be used to add and remove views.
419 public ViewAndroidDelegate getViewAndroidDelegate() {
420 return new ViewAndroidDelegate() {
421 // mContainerView can change, but this ViewAndroidDelegate can only be used to
422 // add and remove views from the mContainerViewAtCreation.
423 private final ViewGroup mContainerViewAtCreation = mContainerView;
426 public View acquireAnchorView() {
427 View anchorView = new View(mContext);
428 mContainerViewAtCreation.addView(anchorView);
433 @SuppressWarnings("deprecation") // AbsoluteLayout
434 public void setAnchorViewPosition(
435 View view, float x, float y, float width, float height) {
436 assert view.getParent() == mContainerViewAtCreation;
438 float scale = (float) DeviceDisplayInfo.create(mContext).getDIPScale();
440 // The anchor view should not go outside the bounds of the ContainerView.
441 int leftMargin = Math.round(x * scale);
442 int topMargin = Math.round(mRenderCoordinates.getContentOffsetYPix() + y * scale);
443 int scaledWidth = Math.round(width * scale);
444 // ContentViewCore currently only supports these two container view types.
445 if (mContainerViewAtCreation instanceof FrameLayout) {
447 if (ApiCompatibilityUtils.isLayoutRtl(mContainerViewAtCreation)) {
448 startMargin = mContainerViewAtCreation.getMeasuredWidth()
449 - Math.round((width + x) * scale);
451 startMargin = leftMargin;
453 if (scaledWidth + startMargin > mContainerViewAtCreation.getWidth()) {
454 scaledWidth = mContainerViewAtCreation.getWidth() - startMargin;
456 FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
457 scaledWidth, Math.round(height * scale));
458 ApiCompatibilityUtils.setMarginStart(lp, startMargin);
459 lp.topMargin = topMargin;
460 view.setLayoutParams(lp);
461 } else if (mContainerViewAtCreation instanceof android.widget.AbsoluteLayout) {
462 // This fixes the offset due to a difference in
463 // scrolling model of WebView vs. Chrome.
464 // TODO(sgurun) fix this to use mContainerViewAtCreation.getScroll[X/Y]()
465 // as it naturally accounts for scroll differences between
467 leftMargin += mRenderCoordinates.getScrollXPixInt();
468 topMargin += mRenderCoordinates.getScrollYPixInt();
470 android.widget.AbsoluteLayout.LayoutParams lp =
471 new android.widget.AbsoluteLayout.LayoutParams(
472 scaledWidth, (int) (height * scale), leftMargin, topMargin);
473 view.setLayoutParams(lp);
475 Log.e(TAG, "Unknown layout " + mContainerViewAtCreation.getClass().getName());
480 public void releaseAnchorView(View anchorView) {
481 mContainerViewAtCreation.removeView(anchorView);
487 public void setImeAdapterForTest(ImeAdapter imeAdapter) {
488 mImeAdapter = imeAdapter;
492 public ImeAdapter getImeAdapterForTest() {
497 public void setAdapterInputConnectionFactory(AdapterInputConnectionFactory factory) {
498 mAdapterInputConnectionFactory = factory;
502 public void setInputMethodManagerWrapperForTest(InputMethodManagerWrapper immw) {
503 mInputMethodManagerWrapper = immw;
507 public AdapterInputConnection getInputConnectionForTest() {
508 return mInputConnection;
511 private ImeAdapter createImeAdapter(Context context) {
512 return new ImeAdapter(mInputMethodManagerWrapper,
513 new ImeAdapter.ImeAdapterDelegate() {
515 public void onImeEvent(boolean isFinish) {
516 getContentViewClient().onImeEvent();
523 public void onDismissInput() {
524 getContentViewClient().onImeStateChangeRequested(false);
528 public View getAttachedView() {
529 return mContainerView;
533 public ResultReceiver getNewShowKeyboardReceiver() {
534 return new ResultReceiver(new Handler()) {
536 public void onReceiveResult(int resultCode, Bundle resultData) {
537 getContentViewClient().onImeStateChangeRequested(
538 resultCode == InputMethodManager.RESULT_SHOWN ||
539 resultCode == InputMethodManager.RESULT_UNCHANGED_SHOWN);
540 if (resultCode == InputMethodManager.RESULT_SHOWN) {
541 // If OSK is newly shown, delay the form focus until
542 // the onSizeChanged (in order to adjust relative to the
544 // TODO(jdduke): We should not assume that onSizeChanged will
545 // always be called, crbug.com/294908.
546 getContainerView().getWindowVisibleDisplayFrame(
547 mFocusPreOSKViewportRect);
548 } else if (hasFocus() && resultCode ==
549 InputMethodManager.RESULT_UNCHANGED_SHOWN) {
550 // If the OSK was already there, focus the form immediately.
551 scrollFocusedEditableNodeIntoView();
562 * @param containerView The view that will act as a container for all views created by this.
563 * @param internalDispatcher Handles dispatching all hidden or super methods to the
565 * @param nativeWebContents A pointer to the native web contents.
566 * @param windowAndroid An instance of the WindowAndroid.
568 // Perform important post-construction set up of the ContentViewCore.
569 // We do not require the containing view in the constructor to allow embedders to create a
570 // ContentViewCore without having fully created its containing view. The containing view
571 // is a vital component of the ContentViewCore, so embedders must exercise caution in what
572 // they do with the ContentViewCore before calling initialize().
573 // We supply the nativeWebContents pointer here rather than in the constructor to allow us
574 // to set the private browsing mode at a later point for the WebView implementation.
575 // Note that the caller remains the owner of the nativeWebContents and is responsible for
576 // deleting it after destroying the ContentViewCore.
577 public void initialize(ViewGroup containerView, InternalAccessDelegate internalDispatcher,
578 long nativeWebContents, WindowAndroid windowAndroid) {
579 setContainerView(containerView);
581 mPositionListener = new PositionObserver.Listener() {
583 public void onPositionChanged(int x, int y) {
584 if (isSelectionHandleShowing() || isInsertionHandleShowing()) {
585 temporarilyHideTextHandles();
590 long windowNativePointer = windowAndroid != null ? windowAndroid.getNativePointer() : 0;
592 long viewAndroidNativePointer = 0;
593 if (windowNativePointer != 0) {
594 mViewAndroid = new ViewAndroid(windowAndroid, getViewAndroidDelegate());
595 viewAndroidNativePointer = mViewAndroid.getNativePointer();
598 mZoomControlsDelegate = new ZoomControlsDelegate() {
600 public void invokeZoomPicker() {}
602 public void dismissZoomPicker() {}
604 public void updateZoomControls() {}
607 mNativeContentViewCore = nativeInit(
608 nativeWebContents, viewAndroidNativePointer, windowNativePointer,
609 mRetainedJavaScriptObjects);
610 mWebContents = nativeGetWebContentsAndroid(mNativeContentViewCore);
611 mContentSettings = new ContentSettings(this, mNativeContentViewCore);
613 setContainerViewInternals(internalDispatcher);
614 mRenderCoordinates.reset();
615 initPopupZoomer(mContext);
616 mImeAdapter = createImeAdapter(mContext);
618 mAccessibilityInjector = AccessibilityInjector.newInstance(this);
620 mWebContentsObserver = new WebContentsObserverAndroid(this) {
622 public void didNavigateMainFrame(String url, String baseUrl,
623 boolean isNavigationToDifferentPage, boolean isFragmentNavigation) {
624 if (!isNavigationToDifferentPage) return;
626 resetScrollInProgress();
627 resetGestureDetection();
631 public void renderProcessGone(boolean wasOomProtected) {
633 resetScrollInProgress();
634 // No need to reset gesture detection as the detector will have
635 // been destroyed in the RenderWidgetHostView.
641 * Sets a new container view for this {@link ContentViewCore}.
643 * <p>WARNING: This is not a general purpose method and has been designed with WebView
644 * fullscreen in mind. Please be aware that it might not be appropriate for other use cases
645 * and that it has a number of limitations. For example the PopupZoomer only works with the
646 * container view with which this ContentViewCore has been initialized.
648 * <p>This method only performs a small part of replacing the container view and
649 * embedders are responsible for:
651 * <li>Disconnecting the old container view from this ContentViewCore</li>
652 * <li>Updating the InternalAccessDelegate</li>
653 * <li>Reconciling the state of this ContentViewCore with the new container view</li>
654 * <li>Tearing down and recreating the native GL rendering where appropriate</li>
658 public void setContainerView(ViewGroup containerView) {
660 if (mContainerView != null) {
661 mPositionObserver.removeListener(mPositionListener);
662 mSelectionHandleController = null;
663 mInsertionHandleController = null;
664 mInputConnection = null;
667 mContainerView = containerView;
668 mPositionObserver = new ViewPositionObserver(mContainerView);
669 String contentDescription = "Web View";
670 if (R.string.accessibility_content_view == 0) {
671 Log.w(TAG, "Setting contentDescription to 'Web View' as no value was specified.");
673 contentDescription = mContext.getResources().getString(
674 R.string.accessibility_content_view);
676 mContainerView.setContentDescription(contentDescription);
677 mContainerView.setWillNotDraw(false);
678 mContainerView.setClickable(true);
683 void onNativeContentViewCoreDestroyed(long nativeContentViewCore) {
684 assert nativeContentViewCore == mNativeContentViewCore;
685 mNativeContentViewCore = 0;
689 * Set the Container view Internals.
690 * @param internalDispatcher Handles dispatching all hidden or super methods to the
693 public void setContainerViewInternals(InternalAccessDelegate internalDispatcher) {
694 mContainerViewInternals = internalDispatcher;
697 private void initPopupZoomer(Context context) {
698 mPopupZoomer = new PopupZoomer(context);
699 mPopupZoomer.setOnVisibilityChangedListener(new PopupZoomer.OnVisibilityChangedListener() {
700 // mContainerView can change, but this OnVisibilityChangedListener can only be used
701 // to add and remove views from the mContainerViewAtCreation.
702 private final ViewGroup mContainerViewAtCreation = mContainerView;
705 public void onPopupZoomerShown(final PopupZoomer zoomer) {
706 mContainerViewAtCreation.post(new Runnable() {
709 if (mContainerViewAtCreation.indexOfChild(zoomer) == -1) {
710 mContainerViewAtCreation.addView(zoomer);
712 assert false : "PopupZoomer should never be shown without being hidden";
719 public void onPopupZoomerHidden(final PopupZoomer zoomer) {
720 mContainerViewAtCreation.post(new Runnable() {
723 if (mContainerViewAtCreation.indexOfChild(zoomer) != -1) {
724 mContainerViewAtCreation.removeView(zoomer);
725 mContainerViewAtCreation.invalidate();
727 assert false : "PopupZoomer should never be hidden without being shown";
733 // TODO(yongsheng): LONG_TAP is not enabled in PopupZoomer. So need to dispatch a LONG_TAP
734 // gesture if a user completes a tap on PopupZoomer UI after a LONG_PRESS gesture.
735 PopupZoomer.OnTapListener listener = new PopupZoomer.OnTapListener() {
736 // mContainerView can change, but this OnTapListener can only be used
737 // with the mContainerViewAtCreation.
738 private final ViewGroup mContainerViewAtCreation = mContainerView;
741 public boolean onSingleTap(View v, MotionEvent e) {
742 mContainerViewAtCreation.requestFocus();
743 if (mNativeContentViewCore != 0) {
744 nativeSingleTap(mNativeContentViewCore, e.getEventTime(), e.getX(), e.getY());
750 public boolean onLongPress(View v, MotionEvent e) {
751 if (mNativeContentViewCore != 0) {
752 nativeLongPress(mNativeContentViewCore, e.getEventTime(), e.getX(), e.getY());
757 mPopupZoomer.setOnTapListener(listener);
761 * Destroy the internal state of the ContentView. This method may only be
762 * called after the ContentView has been removed from the view system. No
763 * other methods may be called on this ContentView after this method has
766 public void destroy() {
767 if (mNativeContentViewCore != 0) {
768 nativeOnJavaContentViewCoreDestroyed(mNativeContentViewCore);
771 if (mViewAndroid != null) mViewAndroid.destroy();
772 mNativeContentViewCore = 0;
773 mContentSettings = null;
774 mJavaScriptInterfaces.clear();
775 mRetainedJavaScriptObjects.clear();
776 unregisterAccessibilityContentObserver();
777 mGestureStateListeners.clear();
778 ScreenOrientationListener.getInstance().removeObserver(this);
781 private void unregisterAccessibilityContentObserver() {
782 if (mAccessibilityScriptInjectionObserver == null) {
785 getContext().getContentResolver().unregisterContentObserver(
786 mAccessibilityScriptInjectionObserver);
787 mAccessibilityScriptInjectionObserver = null;
791 * Returns true initially, false after destroy() has been called.
792 * It is illegal to call any other public method after destroy().
794 public boolean isAlive() {
795 return mNativeContentViewCore != 0;
799 * This is only useful for passing over JNI to native code that requires ContentViewCore*.
800 * @return native ContentViewCore pointer.
803 public long getNativeContentViewCore() {
804 return mNativeContentViewCore;
807 public void setContentViewClient(ContentViewClient client) {
808 if (client == null) {
809 throw new IllegalArgumentException("The client can't be null.");
811 mContentViewClient = client;
815 public ContentViewClient getContentViewClient() {
816 if (mContentViewClient == null) {
817 // We use the Null Object pattern to avoid having to perform a null check in this class.
818 // We create it lazily because most of the time a client will be set almost immediately
819 // after ContentView is created.
820 mContentViewClient = new ContentViewClient();
821 // We don't set the native ContentViewClient pointer here on purpose. The native
822 // implementation doesn't mind a null delegate and using one is better than passing a
823 // Null Object, since we cut down on the number of JNI calls.
825 return mContentViewClient;
828 public int getBackgroundColor() {
829 if (mNativeContentViewCore != 0) {
830 return nativeGetBackgroundColor(mNativeContentViewCore);
836 private void onBackgroundColorChanged(int color) {
837 getContentViewClient().onBackgroundColorChanged(color);
841 * Load url without fixing up the url string. Consumers of ContentView are responsible for
842 * ensuring the URL passed in is properly formatted (i.e. the scheme has been added if left
843 * off during user input).
845 * @param params Parameters for this load.
847 public void loadUrl(LoadUrlParams params) {
848 if (mNativeContentViewCore == 0) return;
850 nativeLoadUrl(mNativeContentViewCore,
853 params.mTransitionType,
854 params.getReferrer() != null ? params.getReferrer().getUrl() : null,
855 params.getReferrer() != null ? params.getReferrer().getPolicy() : 0,
856 params.mUaOverrideOption,
857 params.getExtraHeadersString(),
859 params.mBaseUrlForDataUrl,
860 params.mVirtualUrlForDataUrl,
861 params.mCanLoadLocalResources,
862 params.mIsRendererInitiated);
866 * Stops loading the current web contents.
868 public void stopLoading() {
869 if (mWebContents != null) mWebContents.stop();
873 * Get the URL of the current page.
875 * @return The URL of the current page.
877 public String getUrl() {
878 if (mNativeContentViewCore != 0) return nativeGetURL(mNativeContentViewCore);
883 * Get the title of the current page.
885 * @return The title of the current page.
887 public String getTitle() {
888 return mWebContents == null ? null : mWebContents.getTitle();
892 * Shows an interstitial page driven by the passed in delegate.
894 * @param url The URL being blocked by the interstitial.
895 * @param delegate The delegate handling the interstitial.
898 public void showInterstitialPage(
899 String url, InterstitialPageDelegateAndroid delegate) {
900 if (mNativeContentViewCore == 0) return;
901 nativeShowInterstitialPage(mNativeContentViewCore, url, delegate.getNative());
905 * @return Whether the page is currently showing an interstitial, such as a bad HTTPS page.
907 public boolean isShowingInterstitialPage() {
908 return mNativeContentViewCore == 0 ?
909 false : nativeIsShowingInterstitialPage(mNativeContentViewCore);
913 * @return Viewport width in physical pixels as set from onSizeChanged.
916 public int getViewportWidthPix() { return mViewportWidthPix; }
919 * @return Viewport height in physical pixels as set from onSizeChanged.
922 public int getViewportHeightPix() { return mViewportHeightPix; }
925 * @return Width of underlying physical surface.
928 public int getPhysicalBackingWidthPix() { return mPhysicalBackingWidthPix; }
931 * @return Height of underlying physical surface.
934 public int getPhysicalBackingHeightPix() { return mPhysicalBackingHeightPix; }
937 * @return Amount the output surface extends past the bottom of the window viewport.
940 public int getOverdrawBottomHeightPix() { return mOverdrawBottomHeightPix; }
943 * @return The amount to shrink the viewport relative to {@link #getViewportWidthPix()}.
946 public int getViewportSizeOffsetWidthPix() { return mViewportSizeOffsetWidthPix; }
949 * @return The amount to shrink the viewport relative to {@link #getViewportHeightPix()}.
952 public int getViewportSizeOffsetHeightPix() { return mViewportSizeOffsetHeightPix; }
955 * @see android.webkit.WebView#getContentHeight()
957 public float getContentHeightCss() {
958 return mRenderCoordinates.getContentHeightCss();
962 * @see android.webkit.WebView#getContentWidth()
964 public float getContentWidthCss() {
965 return mRenderCoordinates.getContentWidthCss();
968 // TODO(teddchoc): Remove all these navigation controller methods from here and have the
969 // embedders manage it.
971 * @return Whether the current WebContents has a previous navigation entry.
973 public boolean canGoBack() {
974 return mWebContents != null && mWebContents.getNavigationController().canGoBack();
978 * @return Whether the current WebContents has a navigation entry after the current one.
980 public boolean canGoForward() {
981 return mWebContents != null && mWebContents.getNavigationController().canGoForward();
985 * @param offset The offset into the navigation history.
986 * @return Whether we can move in history by given offset
988 public boolean canGoToOffset(int offset) {
989 return mWebContents != null &&
990 mWebContents.getNavigationController().canGoToOffset(offset);
994 * Navigates to the specified offset from the "current entry". Does nothing if the offset is out
996 * @param offset The offset into the navigation history.
998 public void goToOffset(int offset) {
999 if (mWebContents != null) mWebContents.getNavigationController().goToOffset(offset);
1003 public void goToNavigationIndex(int index) {
1004 if (mWebContents != null) {
1005 mWebContents.getNavigationController().goToNavigationIndex(index);
1010 * Goes to the navigation entry before the current one.
1012 public void goBack() {
1013 if (mWebContents != null) mWebContents.getNavigationController().goBack();
1017 * Goes to the navigation entry following the current one.
1019 public void goForward() {
1020 if (mWebContents != null) mWebContents.getNavigationController().goForward();
1024 * Loads the current navigation if there is a pending lazy load (after tab restore).
1026 public void loadIfNecessary() {
1027 if (mNativeContentViewCore != 0) nativeLoadIfNecessary(mNativeContentViewCore);
1031 * Requests the current navigation to be loaded upon the next call to loadIfNecessary().
1033 public void requestRestoreLoad() {
1034 if (mNativeContentViewCore != 0) nativeRequestRestoreLoad(mNativeContentViewCore);
1038 * Reload the current page.
1040 public void reload(boolean checkForRepost) {
1041 mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary();
1042 if (mNativeContentViewCore != 0) {
1043 nativeReload(mNativeContentViewCore, checkForRepost);
1048 * Reload the current page, ignoring the contents of the cache.
1050 public void reloadIgnoringCache(boolean checkForRepost) {
1051 mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary();
1052 if (mNativeContentViewCore != 0) {
1053 nativeReloadIgnoringCache(mNativeContentViewCore, checkForRepost);
1058 * Cancel the pending reload.
1060 public void cancelPendingReload() {
1061 if (mNativeContentViewCore != 0) nativeCancelPendingReload(mNativeContentViewCore);
1065 * Continue the pending reload.
1067 public void continuePendingReload() {
1068 if (mNativeContentViewCore != 0) nativeContinuePendingReload(mNativeContentViewCore);
1072 * Clears the ContentViewCore's page history in both the backwards and
1073 * forwards directions.
1075 public void clearHistory() {
1076 if (mNativeContentViewCore != 0) nativeClearHistory(mNativeContentViewCore);
1080 * @return The selected text (empty if no text selected).
1082 public String getSelectedText() {
1083 return mHasSelection ? mLastSelectedText : "";
1087 * @return Whether the current selection is editable (false if no text selected).
1089 public boolean isSelectionEditable() {
1090 return mHasSelection ? mSelectionEditable : false;
1093 // End FrameLayout overrides.
1096 * @see View#onTouchEvent(MotionEvent)
1098 public boolean onTouchEvent(MotionEvent event) {
1099 TraceEvent.begin("onTouchEvent");
1101 cancelRequestToScrollFocusedEditableNodeIntoView();
1103 final int eventAction = event.getActionMasked();
1105 // Only these actions have any effect on gesture detection. Other
1106 // actions have no corresponding WebTouchEvent type and may confuse the
1107 // touch pipline, so we ignore them entirely.
1108 if (eventAction != MotionEvent.ACTION_DOWN
1109 && eventAction != MotionEvent.ACTION_UP
1110 && eventAction != MotionEvent.ACTION_CANCEL
1111 && eventAction != MotionEvent.ACTION_MOVE
1112 && eventAction != MotionEvent.ACTION_POINTER_DOWN
1113 && eventAction != MotionEvent.ACTION_POINTER_UP) {
1117 if (mNativeContentViewCore == 0) return false;
1119 // A zero offset is quite common, in which case the unnecessary copy should be avoided.
1120 MotionEvent offset = null;
1121 if (mCurrentTouchOffsetX != 0 || mCurrentTouchOffsetY != 0) {
1122 offset = createOffsetMotionEvent(event);
1126 final int pointerCount = event.getPointerCount();
1127 final boolean consumed = nativeOnTouchEvent(mNativeContentViewCore, event,
1128 event.getEventTime(), eventAction,
1129 pointerCount, event.getHistorySize(), event.getActionIndex(),
1130 event.getX(), event.getY(),
1131 pointerCount > 1 ? event.getX(1) : 0,
1132 pointerCount > 1 ? event.getY(1) : 0,
1133 event.getPointerId(0), pointerCount > 1 ? event.getPointerId(1) : -1,
1134 event.getTouchMajor(), pointerCount > 1 ? event.getTouchMajor(1) : 0,
1135 event.getRawX(), event.getRawY());
1137 if (offset != null) offset.recycle();
1140 TraceEvent.end("onTouchEvent");
1144 public void setIgnoreRemainingTouchEvents() {
1145 resetGestureDetection();
1148 public boolean isScrollInProgress() {
1149 return mTouchScrollInProgress || mPotentiallyActiveFlingCount > 0;
1152 @SuppressWarnings("unused")
1154 private void onFlingStartEventConsumed(int vx, int vy) {
1155 mTouchScrollInProgress = false;
1156 mPotentiallyActiveFlingCount++;
1157 temporarilyHideTextHandles();
1158 for (mGestureStateListenersIterator.rewind();
1159 mGestureStateListenersIterator.hasNext();) {
1160 mGestureStateListenersIterator.next().onFlingStartGesture(
1161 vx, vy, computeVerticalScrollOffset(), computeVerticalScrollExtent());
1165 @SuppressWarnings("unused")
1167 private void onFlingStartEventHadNoConsumer(int vx, int vy) {
1168 mTouchScrollInProgress = false;
1169 for (mGestureStateListenersIterator.rewind();
1170 mGestureStateListenersIterator.hasNext();) {
1171 mGestureStateListenersIterator.next().onUnhandledFlingStartEvent(vx, vy);
1175 @SuppressWarnings("unused")
1177 private void onFlingCancelEventAck() {
1178 updateGestureStateListener(GestureEventType.FLING_CANCEL);
1181 @SuppressWarnings("unused")
1183 private void onScrollBeginEventAck() {
1184 mTouchScrollInProgress = true;
1185 temporarilyHideTextHandles();
1186 mZoomControlsDelegate.invokeZoomPicker();
1187 updateGestureStateListener(GestureEventType.SCROLL_START);
1190 @SuppressWarnings("unused")
1192 private void onScrollUpdateGestureConsumed() {
1193 mZoomControlsDelegate.invokeZoomPicker();
1194 for (mGestureStateListenersIterator.rewind();
1195 mGestureStateListenersIterator.hasNext();) {
1196 mGestureStateListenersIterator.next().onScrollUpdateGestureConsumed();
1200 @SuppressWarnings("unused")
1202 private void onScrollEndEventAck() {
1203 if (!mTouchScrollInProgress) return;
1204 mTouchScrollInProgress = false;
1205 updateGestureStateListener(GestureEventType.SCROLL_END);
1208 @SuppressWarnings("unused")
1210 private void onPinchBeginEventAck() {
1211 temporarilyHideTextHandles();
1212 updateGestureStateListener(GestureEventType.PINCH_BEGIN);
1215 @SuppressWarnings("unused")
1217 private void onPinchEndEventAck() {
1218 updateGestureStateListener(GestureEventType.PINCH_END);
1221 @SuppressWarnings("unused")
1223 private void onSingleTapEventAck(boolean consumed, int x, int y) {
1224 for (mGestureStateListenersIterator.rewind();
1225 mGestureStateListenersIterator.hasNext();) {
1226 mGestureStateListenersIterator.next().onSingleTap(consumed, x, y);
1230 @SuppressWarnings("unused")
1232 private void onDoubleTapEventAck() {
1233 temporarilyHideTextHandles();
1237 * Called just prior to a tap or press gesture being forwarded to the renderer.
1239 @SuppressWarnings("unused")
1241 private boolean filterTapOrPressEvent(int type, int x, int y) {
1242 if (type == GestureEventType.LONG_PRESS && offerLongPressToEmbedder()) {
1245 updateForTapOrPress(type, x, y);
1250 public void sendDoubleTapForTest(long timeMs, int x, int y) {
1251 if (mNativeContentViewCore == 0) return;
1252 nativeDoubleTap(mNativeContentViewCore, timeMs, x, y);
1256 public void flingForTest(long timeMs, int x, int y, int velocityX, int velocityY) {
1257 if (mNativeContentViewCore == 0) return;
1258 nativeFlingCancel(mNativeContentViewCore, timeMs);
1259 nativeScrollBegin(mNativeContentViewCore, timeMs, x, y, velocityX, velocityY);
1260 nativeFlingStart(mNativeContentViewCore, timeMs, x, y, velocityX, velocityY);
1264 * Cancel any fling gestures active.
1265 * @param timeMs Current time (in milliseconds).
1267 public void cancelFling(long timeMs) {
1268 if (mNativeContentViewCore == 0) return;
1269 nativeFlingCancel(mNativeContentViewCore, timeMs);
1273 * Add a listener that gets alerted on gesture state changes.
1274 * @param listener Listener to add.
1276 public void addGestureStateListener(GestureStateListener listener) {
1277 mGestureStateListeners.addObserver(listener);
1281 * Removes a listener that was added to watch for gesture state changes.
1282 * @param listener Listener to remove.
1284 public void removeGestureStateListener(GestureStateListener listener) {
1285 mGestureStateListeners.removeObserver(listener);
1288 void updateGestureStateListener(int gestureType) {
1289 for (mGestureStateListenersIterator.rewind();
1290 mGestureStateListenersIterator.hasNext();) {
1291 GestureStateListener listener = mGestureStateListenersIterator.next();
1292 switch (gestureType) {
1293 case GestureEventType.PINCH_BEGIN:
1294 listener.onPinchStarted();
1296 case GestureEventType.PINCH_END:
1297 listener.onPinchEnded();
1299 case GestureEventType.FLING_END:
1300 listener.onFlingEndGesture(
1301 computeVerticalScrollOffset(),
1302 computeVerticalScrollExtent());
1304 case GestureEventType.FLING_CANCEL:
1305 listener.onFlingCancelGesture();
1307 case GestureEventType.SCROLL_START:
1308 listener.onScrollStarted(
1309 computeVerticalScrollOffset(),
1310 computeVerticalScrollExtent());
1312 case GestureEventType.SCROLL_END:
1313 listener.onScrollEnded(
1314 computeVerticalScrollOffset(),
1315 computeVerticalScrollExtent());
1324 * Requests the renderer insert a link to the specified stylesheet in the
1325 * main frame's document.
1327 void addStyleSheetByURL(String url) {
1328 nativeAddStyleSheetByURL(mNativeContentViewCore, url);
1331 /** Callback interface for evaluateJavaScript(). */
1332 public interface JavaScriptCallback {
1333 void handleJavaScriptResult(String jsonResult);
1337 * Injects the passed Javascript code in the current page and evaluates it.
1338 * If a result is required, pass in a callback.
1339 * Used in automation tests.
1341 * @param script The Javascript to execute.
1342 * @param callback The callback to be fired off when a result is ready. The script's
1343 * result will be json encoded and passed as the parameter, and the call
1344 * will be made on the main thread.
1345 * If no result is required, pass null.
1347 public void evaluateJavaScript(String script, JavaScriptCallback callback) {
1348 if (mNativeContentViewCore == 0) return;
1349 nativeEvaluateJavaScript(mNativeContentViewCore, script, callback, false);
1353 * Injects the passed Javascript code in the current page and evaluates it.
1354 * If there is no page existing, a new one will be created.
1356 * @param script The Javascript to execute.
1358 public void evaluateJavaScriptEvenIfNotYetNavigated(String script) {
1359 if (mNativeContentViewCore == 0) return;
1360 nativeEvaluateJavaScript(mNativeContentViewCore, script, null, true);
1364 * To be called when the ContentView is shown.
1366 public void onShow() {
1367 assert mNativeContentViewCore != 0;
1368 nativeOnShow(mNativeContentViewCore);
1369 setAccessibilityState(mAccessibilityManager.isEnabled());
1373 * @return The ID of the renderer process that backs this tab or
1374 * {@link #INVALID_RENDER_PROCESS_PID} if there is none.
1376 public int getCurrentRenderProcessId() {
1377 return nativeGetCurrentRenderProcessId(mNativeContentViewCore);
1381 * To be called when the ContentView is hidden.
1383 public void onHide() {
1384 assert mNativeContentViewCore != 0;
1386 setInjectedAccessibility(false);
1387 nativeOnHide(mNativeContentViewCore);
1391 * Return the ContentSettings object used to retrieve the settings for this
1392 * ContentViewCore. For modifications, ChromeNativePreferences is to be used.
1393 * @return A ContentSettings object that can be used to retrieve this
1394 * ContentViewCore's settings.
1396 public ContentSettings getContentSettings() {
1397 return mContentSettings;
1400 private void hidePopups() {
1403 hideSelectActionBar();
1406 public void hideSelectActionBar() {
1407 if (mActionMode != null) {
1408 mActionMode.finish();
1413 public boolean isSelectActionBarShowing() {
1414 return mActionMode != null;
1417 private void resetGestureDetection() {
1418 if (mNativeContentViewCore == 0) return;
1419 nativeResetGestureDetection(mNativeContentViewCore);
1423 * @see View#onAttachedToWindow()
1425 @SuppressWarnings("javadoc")
1426 public void onAttachedToWindow() {
1427 setAccessibilityState(mAccessibilityManager.isEnabled());
1429 ScreenOrientationListener.getInstance().addObserver(this, mContext);
1430 GamepadList.onAttachedToWindow(mContext);
1434 * @see View#onDetachedFromWindow()
1436 @SuppressWarnings("javadoc")
1437 @SuppressLint("MissingSuperCall")
1438 public void onDetachedFromWindow() {
1439 setInjectedAccessibility(false);
1441 mZoomControlsDelegate.dismissZoomPicker();
1442 unregisterAccessibilityContentObserver();
1444 ScreenOrientationListener.getInstance().removeObserver(this);
1445 GamepadList.onDetachedFromWindow();
1449 * @see View#onVisibilityChanged(android.view.View, int)
1451 public void onVisibilityChanged(View changedView, int visibility) {
1452 if (visibility != View.VISIBLE) {
1453 mZoomControlsDelegate.dismissZoomPicker();
1458 * @see View#onCreateInputConnection(EditorInfo)
1460 public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
1461 if (!mImeAdapter.hasTextInputType()) {
1462 // Although onCheckIsTextEditor will return false in this case, the EditorInfo
1463 // is still used by the InputMethodService. Need to make sure the IME doesn't
1464 // enter fullscreen mode.
1465 outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN;
1467 mInputConnection = mAdapterInputConnectionFactory.get(mContainerView, mImeAdapter,
1468 mEditable, outAttrs);
1469 return mInputConnection;
1473 public AdapterInputConnection getAdapterInputConnectionForTest() {
1474 return mInputConnection;
1478 public Editable getEditableForTest() {
1483 * @see View#onCheckIsTextEditor()
1485 public boolean onCheckIsTextEditor() {
1486 return mImeAdapter.hasTextInputType();
1490 * @see View#onConfigurationChanged(Configuration)
1492 @SuppressWarnings("javadoc")
1493 public void onConfigurationChanged(Configuration newConfig) {
1496 if (newConfig.keyboard != Configuration.KEYBOARD_NOKEYS) {
1497 if (mNativeContentViewCore != 0) {
1498 mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore),
1499 ImeAdapter.getTextInputTypeNone());
1501 mInputMethodManagerWrapper.restartInput(mContainerView);
1503 mContainerViewInternals.super_onConfigurationChanged(newConfig);
1505 // To request layout has side effect, but it seems OK as it only happen in
1506 // onConfigurationChange and layout has to be changed in most case.
1507 mContainerView.requestLayout();
1512 * @see View#onSizeChanged(int, int, int, int)
1514 @SuppressWarnings("javadoc")
1515 public void onSizeChanged(int wPix, int hPix, int owPix, int ohPix) {
1516 if (getViewportWidthPix() == wPix && getViewportHeightPix() == hPix) return;
1518 mViewportWidthPix = wPix;
1519 mViewportHeightPix = hPix;
1520 if (mNativeContentViewCore != 0) {
1521 nativeWasResized(mNativeContentViewCore);
1524 updateAfterSizeChanged();
1528 * Called when the underlying surface the compositor draws to changes size.
1529 * This may be larger than the viewport size.
1531 public void onPhysicalBackingSizeChanged(int wPix, int hPix) {
1532 if (mPhysicalBackingWidthPix == wPix && mPhysicalBackingHeightPix == hPix) return;
1534 mPhysicalBackingWidthPix = wPix;
1535 mPhysicalBackingHeightPix = hPix;
1537 if (mNativeContentViewCore != 0) {
1538 nativeWasResized(mNativeContentViewCore);
1543 * Called when the amount the surface is overdrawing off the bottom has changed.
1544 * @param overdrawHeightPix The overdraw height.
1546 public void onOverdrawBottomHeightChanged(int overdrawHeightPix) {
1547 if (mOverdrawBottomHeightPix == overdrawHeightPix) return;
1549 mOverdrawBottomHeightPix = overdrawHeightPix;
1551 if (mNativeContentViewCore != 0) {
1552 nativeWasResized(mNativeContentViewCore);
1556 private void updateAfterSizeChanged() {
1557 mPopupZoomer.hide(false);
1559 // Execute a delayed form focus operation because the OSK was brought
1561 if (!mFocusPreOSKViewportRect.isEmpty()) {
1562 Rect rect = new Rect();
1563 getContainerView().getWindowVisibleDisplayFrame(rect);
1564 if (!rect.equals(mFocusPreOSKViewportRect)) {
1565 // Only assume the OSK triggered the onSizeChanged if width was preserved.
1566 if (rect.width() == mFocusPreOSKViewportRect.width()) {
1567 scrollFocusedEditableNodeIntoView();
1569 cancelRequestToScrollFocusedEditableNodeIntoView();
1574 private void cancelRequestToScrollFocusedEditableNodeIntoView() {
1575 // Zero-ing the rect will prevent |updateAfterSizeChanged()| from
1576 // issuing the delayed form focus event.
1577 mFocusPreOSKViewportRect.setEmpty();
1580 private void scrollFocusedEditableNodeIntoView() {
1581 if (mNativeContentViewCore == 0) return;
1582 // The native side keeps track of whether the zoom and scroll actually occurred. It is
1583 // more efficient to do it this way and sometimes fire an unnecessary message rather
1584 // than synchronize with the renderer and always have an additional message.
1585 nativeScrollFocusedEditableNodeIntoView(mNativeContentViewCore);
1589 * Selects the word around the caret, if any.
1590 * The caller can check if selection actually occurred by listening to OnSelectionChanged.
1592 public void selectWordAroundCaret() {
1593 if (mNativeContentViewCore == 0) return;
1594 nativeSelectWordAroundCaret(mNativeContentViewCore);
1598 * @see View#onWindowFocusChanged(boolean)
1600 public void onWindowFocusChanged(boolean hasWindowFocus) {
1601 if (!hasWindowFocus) resetGestureDetection();
1604 public void onFocusChanged(boolean gainFocus) {
1607 cancelRequestToScrollFocusedEditableNodeIntoView();
1609 if (mNativeContentViewCore != 0) nativeSetFocus(mNativeContentViewCore, gainFocus);
1613 * @see View#onKeyUp(int, KeyEvent)
1615 public boolean onKeyUp(int keyCode, KeyEvent event) {
1616 if (mPopupZoomer.isShowing() && keyCode == KeyEvent.KEYCODE_BACK) {
1617 mPopupZoomer.hide(true);
1620 return mContainerViewInternals.super_onKeyUp(keyCode, event);
1624 * @see View#dispatchKeyEventPreIme(KeyEvent)
1626 public boolean dispatchKeyEventPreIme(KeyEvent event) {
1629 return mContainerViewInternals.super_dispatchKeyEventPreIme(event);
1636 * @see View#dispatchKeyEvent(KeyEvent)
1638 public boolean dispatchKeyEvent(KeyEvent event) {
1639 if (GamepadList.dispatchKeyEvent(event)) return true;
1640 if (getContentViewClient().shouldOverrideKeyEvent(event)) {
1641 return mContainerViewInternals.super_dispatchKeyEvent(event);
1644 if (mImeAdapter.dispatchKeyEvent(event)) return true;
1646 return mContainerViewInternals.super_dispatchKeyEvent(event);
1650 * @see View#onHoverEvent(MotionEvent)
1651 * Mouse move events are sent on hover enter, hover move and hover exit.
1652 * They are sent on hover exit because sometimes it acts as both a hover
1653 * move and hover exit.
1655 public boolean onHoverEvent(MotionEvent event) {
1656 TraceEvent.begin("onHoverEvent");
1657 MotionEvent offset = createOffsetMotionEvent(event);
1659 if (mBrowserAccessibilityManager != null) {
1660 return mBrowserAccessibilityManager.onHoverEvent(offset);
1663 // Work around Android bug where the x, y coordinates of a hover exit
1664 // event are incorrect when touch exploration is on.
1665 if (mTouchExplorationEnabled && offset.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
1669 mContainerView.removeCallbacks(mFakeMouseMoveRunnable);
1670 if (mNativeContentViewCore != 0) {
1671 nativeSendMouseMoveEvent(mNativeContentViewCore, offset.getEventTime(),
1672 offset.getX(), offset.getY());
1677 TraceEvent.end("onHoverEvent");
1682 * @see View#onGenericMotionEvent(MotionEvent)
1684 public boolean onGenericMotionEvent(MotionEvent event) {
1685 if (GamepadList.onGenericMotionEvent(event)) return true;
1686 if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
1687 switch (event.getAction()) {
1688 case MotionEvent.ACTION_SCROLL:
1689 if (mNativeContentViewCore == 0) return false;
1691 nativeSendMouseWheelEvent(mNativeContentViewCore, event.getEventTime(),
1692 event.getX(), event.getY(),
1693 event.getAxisValue(MotionEvent.AXIS_VSCROLL));
1695 mContainerView.removeCallbacks(mFakeMouseMoveRunnable);
1696 // Send a delayed onMouseMove event so that we end
1697 // up hovering over the right position after the scroll.
1698 final MotionEvent eventFakeMouseMove = MotionEvent.obtain(event);
1699 mFakeMouseMoveRunnable = new Runnable() {
1702 onHoverEvent(eventFakeMouseMove);
1703 eventFakeMouseMove.recycle();
1706 mContainerView.postDelayed(mFakeMouseMoveRunnable, 250);
1710 return mContainerViewInternals.super_onGenericMotionEvent(event);
1714 * Sets the current amount to offset incoming touch events by. This is used to handle content
1715 * moving and not lining up properly with the android input system.
1716 * @param dx The X offset in pixels to shift touch events.
1717 * @param dy The Y offset in pixels to shift touch events.
1719 public void setCurrentMotionEventOffsets(float dx, float dy) {
1720 mCurrentTouchOffsetX = dx;
1721 mCurrentTouchOffsetY = dy;
1724 private MotionEvent createOffsetMotionEvent(MotionEvent src) {
1725 MotionEvent dst = MotionEvent.obtain(src);
1726 dst.offsetLocation(mCurrentTouchOffsetX, mCurrentTouchOffsetY);
1731 * @see View#scrollBy(int, int)
1732 * Currently the ContentView scrolling happens in the native side. In
1733 * the Java view system, it is always pinned at (0, 0). scrollBy() and scrollTo()
1734 * are overridden, so that View's mScrollX and mScrollY will be unchanged at
1735 * (0, 0). This is critical for drawing ContentView correctly.
1737 public void scrollBy(int xPix, int yPix) {
1738 if (mNativeContentViewCore != 0) {
1739 nativeScrollBy(mNativeContentViewCore,
1740 SystemClock.uptimeMillis(), 0, 0, xPix, yPix);
1745 * @see View#scrollTo(int, int)
1747 public void scrollTo(int xPix, int yPix) {
1748 if (mNativeContentViewCore == 0) return;
1749 final float xCurrentPix = mRenderCoordinates.getScrollXPix();
1750 final float yCurrentPix = mRenderCoordinates.getScrollYPix();
1751 final float dxPix = xPix - xCurrentPix;
1752 final float dyPix = yPix - yCurrentPix;
1753 if (dxPix != 0 || dyPix != 0) {
1754 long time = SystemClock.uptimeMillis();
1755 nativeScrollBegin(mNativeContentViewCore, time,
1756 xCurrentPix, yCurrentPix, -dxPix, -dyPix);
1757 nativeScrollBy(mNativeContentViewCore,
1758 time, xCurrentPix, yCurrentPix, dxPix, dyPix);
1759 nativeScrollEnd(mNativeContentViewCore, time);
1763 // NOTE: this can go away once ContentView.getScrollX() reports correct values.
1765 public int getNativeScrollXForTest() {
1766 return mRenderCoordinates.getScrollXPixInt();
1769 // NOTE: this can go away once ContentView.getScrollY() reports correct values.
1771 public int getNativeScrollYForTest() {
1772 return mRenderCoordinates.getScrollYPixInt();
1776 * @see View#computeHorizontalScrollExtent()
1778 @SuppressWarnings("javadoc")
1779 public int computeHorizontalScrollExtent() {
1780 return mRenderCoordinates.getLastFrameViewportWidthPixInt();
1784 * @see View#computeHorizontalScrollOffset()
1786 @SuppressWarnings("javadoc")
1787 public int computeHorizontalScrollOffset() {
1788 return mRenderCoordinates.getScrollXPixInt();
1792 * @see View#computeHorizontalScrollRange()
1794 @SuppressWarnings("javadoc")
1795 public int computeHorizontalScrollRange() {
1796 return mRenderCoordinates.getContentWidthPixInt();
1800 * @see View#computeVerticalScrollExtent()
1802 @SuppressWarnings("javadoc")
1803 public int computeVerticalScrollExtent() {
1804 return mRenderCoordinates.getLastFrameViewportHeightPixInt();
1808 * @see View#computeVerticalScrollOffset()
1810 @SuppressWarnings("javadoc")
1811 public int computeVerticalScrollOffset() {
1812 return mRenderCoordinates.getScrollYPixInt();
1816 * @see View#computeVerticalScrollRange()
1818 @SuppressWarnings("javadoc")
1819 public int computeVerticalScrollRange() {
1820 return mRenderCoordinates.getContentHeightPixInt();
1823 // End FrameLayout overrides.
1826 * @see View#awakenScrollBars(int, boolean)
1828 @SuppressWarnings("javadoc")
1829 public boolean awakenScrollBars(int startDelay, boolean invalidate) {
1830 // For the default implementation of ContentView which draws the scrollBars on the native
1831 // side, calling this function may get us into a bad state where we keep drawing the
1832 // scrollBars, so disable it by always returning false.
1833 if (mContainerView.getScrollBarStyle() == View.SCROLLBARS_INSIDE_OVERLAY) {
1836 return mContainerViewInternals.super_awakenScrollBars(startDelay, invalidate);
1840 private void updateForTapOrPress(int type, float xPix, float yPix) {
1841 if (type != GestureEventType.SINGLE_TAP_CONFIRMED
1842 && type != GestureEventType.SINGLE_TAP_UP
1843 && type != GestureEventType.LONG_PRESS
1844 && type != GestureEventType.LONG_TAP) {
1848 if (mContainerView.isFocusable() && mContainerView.isFocusableInTouchMode()
1849 && !mContainerView.isFocused()) {
1850 mContainerView.requestFocus();
1853 if (!mPopupZoomer.isShowing()) mPopupZoomer.setLastTouch(xPix, yPix);
1855 mLastTapX = (int) xPix;
1856 mLastTapY = (int) yPix;
1858 if (type == GestureEventType.LONG_PRESS
1859 || type == GestureEventType.LONG_TAP) {
1860 getInsertionHandleController().allowAutomaticShowing();
1861 getSelectionHandleController().allowAutomaticShowing();
1863 if (mSelectionEditable) getInsertionHandleController().allowAutomaticShowing();
1868 * @return The x coordinate for the last point that a tap or press gesture was initiated from.
1870 public int getLastTapX() {
1875 * @return The y coordinate for the last point that a tap or press gesture was initiated from.
1877 public int getLastTapY() {
1881 public void setZoomControlsDelegate(ZoomControlsDelegate zoomControlsDelegate) {
1882 mZoomControlsDelegate = zoomControlsDelegate;
1885 public void updateMultiTouchZoomSupport(boolean supportsMultiTouchZoom) {
1886 if (mNativeContentViewCore == 0) return;
1887 nativeSetMultiTouchZoomSupportEnabled(mNativeContentViewCore, supportsMultiTouchZoom);
1890 public void updateDoubleTapSupport(boolean supportsDoubleTap) {
1891 if (mNativeContentViewCore == 0) return;
1892 nativeSetDoubleTapSupportEnabled(mNativeContentViewCore, supportsDoubleTap);
1895 public void selectPopupMenuItems(int[] indices) {
1896 if (mNativeContentViewCore != 0) {
1897 nativeSelectPopupMenuItems(mNativeContentViewCore, indices);
1899 mSelectPopup = null;
1903 * Send the screen orientation value to the renderer.
1906 void sendOrientationChangeEvent(int orientation) {
1907 if (mNativeContentViewCore == 0) return;
1909 nativeSendOrientationChangeEvent(mNativeContentViewCore, orientation);
1913 * Register the delegate to be used when content can not be handled by
1914 * the rendering engine, and should be downloaded instead. This will replace
1915 * the current delegate, if any.
1916 * @param delegate An implementation of ContentViewDownloadDelegate.
1918 public void setDownloadDelegate(ContentViewDownloadDelegate delegate) {
1919 mDownloadDelegate = delegate;
1922 // Called by DownloadController.
1923 ContentViewDownloadDelegate getDownloadDelegate() {
1924 return mDownloadDelegate;
1927 private SelectionHandleController getSelectionHandleController() {
1928 if (mSelectionHandleController == null) {
1929 mSelectionHandleController = new SelectionHandleController(
1930 getContainerView(), mPositionObserver) {
1932 public void selectBetweenCoordinates(int x1, int y1, int x2, int y2) {
1933 if (mNativeContentViewCore != 0 && !(x1 == x2 && y1 == y2)) {
1934 nativeSelectBetweenCoordinates(mNativeContentViewCore,
1935 x1, y1 - mRenderCoordinates.getContentOffsetYPix(),
1936 x2, y2 - mRenderCoordinates.getContentOffsetYPix());
1941 public void showHandles(int startDir, int endDir) {
1942 final boolean wasShowing = isShowing();
1943 super.showHandles(startDir, endDir);
1944 if (!wasShowing || mActionMode == null) showSelectActionBar();
1949 mSelectionHandleController.hideAndDisallowAutomaticShowing();
1952 return mSelectionHandleController;
1955 private InsertionHandleController getInsertionHandleController() {
1956 if (mInsertionHandleController == null) {
1957 mInsertionHandleController = new InsertionHandleController(
1958 getContainerView(), mPositionObserver) {
1959 private static final int AVERAGE_LINE_HEIGHT = 14;
1962 public void setCursorPosition(int x, int y) {
1963 if (mNativeContentViewCore != 0) {
1964 nativeMoveCaret(mNativeContentViewCore,
1965 x, y - mRenderCoordinates.getContentOffsetYPix());
1970 public void paste() {
1971 mImeAdapter.paste();
1976 public int getLineHeight() {
1977 return (int) Math.ceil(
1978 mRenderCoordinates.fromLocalCssToPix(AVERAGE_LINE_HEIGHT));
1982 public void showHandle() {
1987 mInsertionHandleController.hideAndDisallowAutomaticShowing();
1990 return mInsertionHandleController;
1994 public InsertionHandleController getInsertionHandleControllerForTest() {
1995 return mInsertionHandleController;
1999 public SelectionHandleController getSelectionHandleControllerForTest() {
2000 return mSelectionHandleController;
2003 private void updateHandleScreenPositions() {
2004 if (isSelectionHandleShowing()) {
2005 mSelectionHandleController.setStartHandlePosition(
2006 mStartHandlePoint.getXPix(), mStartHandlePoint.getYPix());
2007 mSelectionHandleController.setEndHandlePosition(
2008 mEndHandlePoint.getXPix(), mEndHandlePoint.getYPix());
2011 if (isInsertionHandleShowing()) {
2012 mInsertionHandleController.setHandlePosition(
2013 mInsertionHandlePoint.getXPix(), mInsertionHandlePoint.getYPix());
2017 private void hideHandles() {
2018 if (mSelectionHandleController != null) {
2019 mSelectionHandleController.hideAndDisallowAutomaticShowing();
2021 if (mInsertionHandleController != null) {
2022 mInsertionHandleController.hideAndDisallowAutomaticShowing();
2024 mPositionObserver.removeListener(mPositionListener);
2027 private void showSelectActionBar() {
2028 if (mActionMode != null) {
2029 mActionMode.invalidate();
2033 // Start a new action mode with a SelectActionModeCallback.
2034 SelectActionModeCallback.ActionHandler actionHandler =
2035 new SelectActionModeCallback.ActionHandler() {
2037 public void selectAll() {
2038 mImeAdapter.selectAll();
2047 public void copy() {
2052 public void paste() {
2053 mImeAdapter.paste();
2057 public void share() {
2058 final String query = getSelectedText();
2059 if (TextUtils.isEmpty(query)) return;
2061 Intent send = new Intent(Intent.ACTION_SEND);
2062 send.setType("text/plain");
2063 send.putExtra(Intent.EXTRA_TEXT, query);
2065 Intent i = Intent.createChooser(send, getContext().getString(
2066 R.string.actionbar_share));
2067 i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2068 getContext().startActivity(i);
2069 } catch (android.content.ActivityNotFoundException ex) {
2070 // If no app handles it, do nothing.
2075 public void search() {
2076 final String query = getSelectedText();
2077 if (TextUtils.isEmpty(query)) return;
2079 // See if ContentViewClient wants to override
2080 if (getContentViewClient().doesPerformWebSearch()) {
2081 getContentViewClient().performWebSearch(query);
2085 Intent i = new Intent(Intent.ACTION_WEB_SEARCH);
2086 i.putExtra(SearchManager.EXTRA_NEW_SEARCH, true);
2087 i.putExtra(SearchManager.QUERY, query);
2088 i.putExtra(Browser.EXTRA_APPLICATION_ID, getContext().getPackageName());
2089 if (!(getContext() instanceof Activity)) {
2090 i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2093 getContext().startActivity(i);
2094 } catch (android.content.ActivityNotFoundException ex) {
2095 // If no app handles it, do nothing.
2100 public boolean isSelectionPassword() {
2101 return mImeAdapter.isSelectionPassword();
2105 public boolean isSelectionEditable() {
2106 return mSelectionEditable;
2110 public void onDestroyActionMode() {
2112 if (mUnselectAllOnActionModeDismiss) mImeAdapter.unselect();
2113 getContentViewClient().onContextualActionBarHidden();
2117 public boolean isShareAvailable() {
2118 Intent intent = new Intent(Intent.ACTION_SEND);
2119 intent.setType("text/plain");
2120 return getContext().getPackageManager().queryIntentActivities(intent,
2121 PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
2125 public boolean isWebSearchAvailable() {
2126 if (getContentViewClient().doesPerformWebSearch()) return true;
2127 Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
2128 intent.putExtra(SearchManager.EXTRA_NEW_SEARCH, true);
2129 return getContext().getPackageManager().queryIntentActivities(intent,
2130 PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
2134 // On ICS, startActionMode throws an NPE when getParent() is null.
2135 if (mContainerView.getParent() != null) {
2136 mActionMode = mContainerView.startActionMode(
2137 getContentViewClient().getSelectActionModeCallback(getContext(), actionHandler,
2138 nativeIsIncognito(mNativeContentViewCore)));
2140 mUnselectAllOnActionModeDismiss = true;
2141 if (mActionMode == null) {
2142 // There is no ActionMode, so remove the selection.
2143 mImeAdapter.unselect();
2145 getContentViewClient().onContextualActionBarShown();
2149 public boolean getUseDesktopUserAgent() {
2150 if (mNativeContentViewCore != 0) {
2151 return nativeGetUseDesktopUserAgent(mNativeContentViewCore);
2157 * Set whether or not we're using a desktop user agent for the currently loaded page.
2158 * @param override If true, use a desktop user agent. Use a mobile one otherwise.
2159 * @param reloadOnChange Reload the page if the UA has changed.
2161 public void setUseDesktopUserAgent(boolean override, boolean reloadOnChange) {
2162 if (mNativeContentViewCore != 0) {
2163 nativeSetUseDesktopUserAgent(mNativeContentViewCore, override, reloadOnChange);
2167 public void clearSslPreferences() {
2168 if (mNativeContentViewCore != 0) nativeClearSslPreferences(mNativeContentViewCore);
2171 private boolean isSelectionHandleShowing() {
2172 return mSelectionHandleController != null && mSelectionHandleController.isShowing();
2175 private boolean isInsertionHandleShowing() {
2176 return mInsertionHandleController != null && mInsertionHandleController.isShowing();
2179 // Makes the insertion/selection handles invisible. They will fade back in shortly after the
2180 // last call to scheduleTextHandleFadeIn (or temporarilyHideTextHandles).
2181 private void temporarilyHideTextHandles() {
2182 if (isSelectionHandleShowing() && !mSelectionHandleController.isDragging()) {
2183 mSelectionHandleController.setHandleVisibility(HandleView.INVISIBLE);
2185 if (isInsertionHandleShowing() && !mInsertionHandleController.isDragging()) {
2186 mInsertionHandleController.setHandleVisibility(HandleView.INVISIBLE);
2188 scheduleTextHandleFadeIn();
2191 private boolean allowTextHandleFadeIn() {
2192 if (mTouchScrollInProgress) return false;
2194 if (mPopupZoomer.isShowing()) return false;
2199 // Cancels any pending fade in and schedules a new one.
2200 private void scheduleTextHandleFadeIn() {
2201 if (!isInsertionHandleShowing() && !isSelectionHandleShowing()) return;
2203 if (mDeferredHandleFadeInRunnable == null) {
2204 mDeferredHandleFadeInRunnable = new Runnable() {
2207 if (!allowTextHandleFadeIn()) {
2208 // Delay fade in until it is allowed.
2209 scheduleTextHandleFadeIn();
2211 if (isSelectionHandleShowing()) {
2212 mSelectionHandleController.beginHandleFadeIn();
2214 if (isInsertionHandleShowing()) {
2215 mInsertionHandleController.beginHandleFadeIn();
2222 mContainerView.removeCallbacks(mDeferredHandleFadeInRunnable);
2223 mContainerView.postDelayed(mDeferredHandleFadeInRunnable, TEXT_HANDLE_FADE_IN_DELAY);
2227 * Shows the IME if the focused widget could accept text input.
2229 public void showImeIfNeeded() {
2230 if (mNativeContentViewCore != 0) nativeShowImeIfNeeded(mNativeContentViewCore);
2234 * Hides the IME if the containerView is the active view for IME.
2236 public void hideImeIfNeeded() {
2237 // Hide input method window from the current view synchronously
2238 // because ImeAdapter does so asynchronouly with a delay, and
2239 // by the time when ImeAdapter dismisses the input, the
2240 // containerView may have lost focus.
2241 // We cannot trust ContentViewClient#onImeStateChangeRequested to
2242 // hide the input window because it has an empty default implementation.
2243 // So we need to explicitly hide the input method window here.
2244 if (mInputMethodManagerWrapper.isActive(mContainerView)) {
2245 mInputMethodManagerWrapper.hideSoftInputFromWindow(
2246 mContainerView.getWindowToken(), 0, null);
2248 getContentViewClient().onImeStateChangeRequested(false);
2251 @SuppressWarnings("unused")
2253 private void updateFrameInfo(
2254 float scrollOffsetX, float scrollOffsetY,
2255 float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor,
2256 float contentWidth, float contentHeight,
2257 float viewportWidth, float viewportHeight,
2258 float controlsOffsetYCss, float contentOffsetYCss,
2259 float overdrawBottomHeightCss) {
2260 TraceEvent.instant("ContentViewCore:updateFrameInfo");
2261 // Adjust contentWidth/Height to be always at least as big as
2262 // the actual viewport (as set by onSizeChanged).
2263 final float deviceScale = mRenderCoordinates.getDeviceScaleFactor();
2264 contentWidth = Math.max(contentWidth,
2265 mViewportWidthPix / (deviceScale * pageScaleFactor));
2266 contentHeight = Math.max(contentHeight,
2267 mViewportHeightPix / (deviceScale * pageScaleFactor));
2268 final float contentOffsetYPix = mRenderCoordinates.fromDipToPix(contentOffsetYCss);
2270 final boolean contentSizeChanged =
2271 contentWidth != mRenderCoordinates.getContentWidthCss()
2272 || contentHeight != mRenderCoordinates.getContentHeightCss();
2273 final boolean scaleLimitsChanged =
2274 minPageScaleFactor != mRenderCoordinates.getMinPageScaleFactor()
2275 || maxPageScaleFactor != mRenderCoordinates.getMaxPageScaleFactor();
2276 final boolean pageScaleChanged =
2277 pageScaleFactor != mRenderCoordinates.getPageScaleFactor();
2278 final boolean scrollChanged =
2280 || scrollOffsetX != mRenderCoordinates.getScrollX()
2281 || scrollOffsetY != mRenderCoordinates.getScrollY();
2282 final boolean contentOffsetChanged =
2283 contentOffsetYPix != mRenderCoordinates.getContentOffsetYPix();
2285 final boolean needHidePopupZoomer = contentSizeChanged || scrollChanged;
2286 final boolean needUpdateZoomControls = scaleLimitsChanged || scrollChanged;
2287 final boolean needTemporarilyHideHandles = scrollChanged;
2289 if (needHidePopupZoomer) mPopupZoomer.hide(true);
2291 if (scrollChanged) {
2292 mContainerViewInternals.onScrollChanged(
2293 (int) mRenderCoordinates.fromLocalCssToPix(scrollOffsetX),
2294 (int) mRenderCoordinates.fromLocalCssToPix(scrollOffsetY),
2295 (int) mRenderCoordinates.getScrollXPix(),
2296 (int) mRenderCoordinates.getScrollYPix());
2299 mRenderCoordinates.updateFrameInfo(
2300 scrollOffsetX, scrollOffsetY,
2301 contentWidth, contentHeight,
2302 viewportWidth, viewportHeight,
2303 pageScaleFactor, minPageScaleFactor, maxPageScaleFactor,
2306 if (scrollChanged || contentOffsetChanged) {
2307 for (mGestureStateListenersIterator.rewind();
2308 mGestureStateListenersIterator.hasNext();) {
2309 mGestureStateListenersIterator.next().onScrollOffsetOrExtentChanged(
2310 computeVerticalScrollOffset(),
2311 computeVerticalScrollExtent());
2315 if (needTemporarilyHideHandles) temporarilyHideTextHandles();
2316 if (needUpdateZoomControls) mZoomControlsDelegate.updateZoomControls();
2317 if (contentOffsetChanged) updateHandleScreenPositions();
2319 // Update offsets for fullscreen.
2320 final float controlsOffsetPix = controlsOffsetYCss * deviceScale;
2321 final float overdrawBottomHeightPix = overdrawBottomHeightCss * deviceScale;
2322 getContentViewClient().onOffsetsForFullscreenChanged(
2323 controlsOffsetPix, contentOffsetYPix, overdrawBottomHeightPix);
2325 if (mBrowserAccessibilityManager != null) {
2326 mBrowserAccessibilityManager.notifyFrameInfoInitialized();
2331 private void updateImeAdapter(long nativeImeAdapterAndroid, int textInputType,
2332 String text, int selectionStart, int selectionEnd,
2333 int compositionStart, int compositionEnd, boolean showImeIfNeeded,
2334 boolean isNonImeChange) {
2336 mSelectionEditable = (textInputType != ImeAdapter.getTextInputTypeNone());
2338 mImeAdapter.updateKeyboardVisibility(
2339 nativeImeAdapterAndroid, textInputType, showImeIfNeeded);
2341 if (mInputConnection != null) {
2342 mInputConnection.updateState(text, selectionStart, selectionEnd, compositionStart,
2343 compositionEnd, isNonImeChange);
2346 if (mActionMode != null) mActionMode.invalidate();
2350 @SuppressWarnings("unused")
2352 private void setTitle(String title) {
2353 getContentViewClient().onUpdateTitle(title);
2357 * Called (from native) when the <select> popup needs to be shown.
2358 * @param items Items to show.
2359 * @param enabled POPUP_ITEM_TYPEs for items.
2360 * @param multiple Whether the popup menu should support multi-select.
2361 * @param selectedIndices Indices of selected items.
2363 @SuppressWarnings("unused")
2365 private void showSelectPopup(Rect bounds, String[] items, int[] enabled, boolean multiple,
2366 int[] selectedIndices) {
2367 if (mContainerView.getParent() == null || mContainerView.getVisibility() != View.VISIBLE) {
2368 selectPopupMenuItems(null);
2372 assert items.length == enabled.length;
2373 List<SelectPopupItem> popupItems = new ArrayList<SelectPopupItem>();
2374 for (int i = 0; i < items.length; i++) {
2375 popupItems.add(new SelectPopupItem(items[i], enabled[i]));
2378 if (DeviceUtils.isTablet(mContext) && !multiple) {
2379 mSelectPopup = new SelectPopupDropdown(this, popupItems, bounds, selectedIndices);
2381 mSelectPopup = new SelectPopupDialog(this, popupItems, multiple, selectedIndices);
2383 mSelectPopup.show();
2387 * Called when the <select> popup needs to be hidden.
2390 private void hideSelectPopup() {
2391 if (mSelectPopup != null) mSelectPopup.hide();
2395 * @return The visible select popup being shown.
2397 public SelectPopup getSelectPopupForTest() {
2398 return mSelectPopup;
2401 @SuppressWarnings("unused")
2403 private void showDisambiguationPopup(Rect targetRect, Bitmap zoomedBitmap) {
2404 mPopupZoomer.setBitmap(zoomedBitmap);
2405 mPopupZoomer.show(targetRect);
2406 temporarilyHideTextHandles();
2409 @SuppressWarnings("unused")
2411 private TouchEventSynthesizer createTouchEventSynthesizer() {
2412 return new TouchEventSynthesizer(this);
2415 @SuppressWarnings("unused")
2417 private void onSelectionChanged(String text) {
2418 mLastSelectedText = text;
2419 getContentViewClient().onSelectionChanged(text);
2422 @SuppressWarnings("unused")
2424 private void onSelectionBoundsChanged(Rect anchorRectDip, int anchorDir, Rect focusRectDip,
2425 int focusDir, boolean isAnchorFirst) {
2426 // All coordinates are in DIP.
2427 int x1 = anchorRectDip.left;
2428 int y1 = anchorRectDip.bottom;
2429 int x2 = focusRectDip.left;
2430 int y2 = focusRectDip.bottom;
2432 if (x1 != x2 || y1 != y2 ||
2433 (mSelectionHandleController != null && mSelectionHandleController.isDragging())) {
2434 if (mInsertionHandleController != null) {
2435 mInsertionHandleController.hide();
2437 if (isAnchorFirst) {
2438 mStartHandlePoint.setLocalDip(x1, y1);
2439 mEndHandlePoint.setLocalDip(x2, y2);
2441 mStartHandlePoint.setLocalDip(x2, y2);
2442 mEndHandlePoint.setLocalDip(x1, y1);
2445 boolean wereSelectionHandlesShowing = getSelectionHandleController().isShowing();
2447 getSelectionHandleController().onSelectionChanged(anchorDir, focusDir);
2448 updateHandleScreenPositions();
2449 mHasSelection = true;
2451 if (!wereSelectionHandlesShowing && getSelectionHandleController().isShowing()) {
2452 // TODO(cjhopman): Remove this when there is a better signal that long press caused
2453 // a selection. See http://crbug.com/150151.
2454 mContainerView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
2458 mUnselectAllOnActionModeDismiss = false;
2459 hideSelectActionBar();
2460 if (x1 != 0 && y1 != 0 && mSelectionEditable) {
2461 // Selection is a caret, and a text field is focused.
2462 if (mSelectionHandleController != null) {
2463 mSelectionHandleController.hide();
2465 mInsertionHandlePoint.setLocalDip(x1, y1);
2467 getInsertionHandleController().onCursorPositionChanged();
2468 updateHandleScreenPositions();
2469 if (mInputMethodManagerWrapper.isWatchingCursor(mContainerView)) {
2470 final int xPix = (int) mInsertionHandlePoint.getXPix();
2471 final int yPix = (int) mInsertionHandlePoint.getYPix();
2472 mInputMethodManagerWrapper.updateCursor(
2473 mContainerView, xPix, yPix, xPix, yPix);
2477 if (mSelectionHandleController != null) {
2478 mSelectionHandleController.hideAndDisallowAutomaticShowing();
2480 if (mInsertionHandleController != null) {
2481 mInsertionHandleController.hideAndDisallowAutomaticShowing();
2484 mHasSelection = false;
2486 if (isSelectionHandleShowing() || isInsertionHandleShowing()) {
2487 mPositionObserver.addListener(mPositionListener);
2491 @SuppressWarnings("unused")
2493 private static void onEvaluateJavaScriptResult(
2494 String jsonResult, JavaScriptCallback callback) {
2495 callback.handleJavaScriptResult(jsonResult);
2498 @SuppressWarnings("unused")
2500 private void showPastePopup(int xDip, int yDip) {
2501 mInsertionHandlePoint.setLocalDip(xDip, yDip);
2502 getInsertionHandleController().showHandle();
2503 updateHandleScreenPositions();
2504 getInsertionHandleController().showHandleWithPastePopup();
2507 @SuppressWarnings("unused")
2509 private void onRenderProcessChange() {
2514 * Attaches the native ImeAdapter object to the java ImeAdapter to allow communication via JNI.
2516 public void attachImeAdapter() {
2517 if (mImeAdapter != null && mNativeContentViewCore != 0) {
2518 mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore));
2523 * @see View#hasFocus()
2526 public boolean hasFocus() {
2527 return mContainerView.hasFocus();
2531 * Checks whether the ContentViewCore can be zoomed in.
2533 * @return True if the ContentViewCore can be zoomed in.
2535 // This method uses the term 'zoom' for legacy reasons, but relates
2536 // to what chrome calls the 'page scale factor'.
2537 public boolean canZoomIn() {
2538 final float zoomInExtent = mRenderCoordinates.getMaxPageScaleFactor()
2539 - mRenderCoordinates.getPageScaleFactor();
2540 return zoomInExtent > ZOOM_CONTROLS_EPSILON;
2544 * Checks whether the ContentViewCore can be zoomed out.
2546 * @return True if the ContentViewCore can be zoomed out.
2548 // This method uses the term 'zoom' for legacy reasons, but relates
2549 // to what chrome calls the 'page scale factor'.
2550 public boolean canZoomOut() {
2551 final float zoomOutExtent = mRenderCoordinates.getPageScaleFactor()
2552 - mRenderCoordinates.getMinPageScaleFactor();
2553 return zoomOutExtent > ZOOM_CONTROLS_EPSILON;
2557 * Zooms in the ContentViewCore by 25% (or less if that would result in
2558 * zooming in more than possible).
2560 * @return True if there was a zoom change, false otherwise.
2562 // This method uses the term 'zoom' for legacy reasons, but relates
2563 // to what chrome calls the 'page scale factor'.
2564 public boolean zoomIn() {
2568 return pinchByDelta(1.25f);
2572 * Zooms out the ContentViewCore by 20% (or less if that would result in
2573 * zooming out more than possible).
2575 * @return True if there was a zoom change, false otherwise.
2577 // This method uses the term 'zoom' for legacy reasons, but relates
2578 // to what chrome calls the 'page scale factor'.
2579 public boolean zoomOut() {
2580 if (!canZoomOut()) {
2583 return pinchByDelta(0.8f);
2587 * Resets the zoom factor of the ContentViewCore.
2589 * @return True if there was a zoom change, false otherwise.
2591 // This method uses the term 'zoom' for legacy reasons, but relates
2592 // to what chrome calls the 'page scale factor'.
2593 public boolean zoomReset() {
2594 // The page scale factor is initialized to mNativeMinimumScale when
2595 // the page finishes loading. Thus sets it back to mNativeMinimumScale.
2596 if (!canZoomOut()) return false;
2597 return pinchByDelta(
2598 mRenderCoordinates.getMinPageScaleFactor()
2599 / mRenderCoordinates.getPageScaleFactor());
2603 * Simulate a pinch zoom gesture.
2605 * @param delta the factor by which the current page scale should be multiplied by.
2606 * @return whether the gesture was sent.
2608 public boolean pinchByDelta(float delta) {
2609 if (mNativeContentViewCore == 0) return false;
2611 long timeMs = SystemClock.uptimeMillis();
2612 int xPix = getViewportWidthPix() / 2;
2613 int yPix = getViewportHeightPix() / 2;
2615 nativePinchBegin(mNativeContentViewCore, timeMs, xPix, yPix);
2616 nativePinchBy(mNativeContentViewCore, timeMs, xPix, yPix, delta);
2617 nativePinchEnd(mNativeContentViewCore, timeMs);
2623 * Invokes the graphical zoom picker widget for this ContentView.
2625 public void invokeZoomPicker() {
2626 mZoomControlsDelegate.invokeZoomPicker();
2630 * Enables or disables inspection of JavaScript objects added via
2631 * {@link #addJavascriptInterface(Object, String)} by means of Object.keys() method and
2632 * "for .. in" loop. Being able to inspect JavaScript objects is useful
2633 * when debugging hybrid Android apps, but can't be enabled for legacy applications due
2634 * to compatibility risks.
2636 * @param allow Whether to allow JavaScript objects inspection.
2638 public void setAllowJavascriptInterfacesInspection(boolean allow) {
2639 nativeSetAllowJavascriptInterfacesInspection(mNativeContentViewCore, allow);
2643 * This will mimic {@link #addPossiblyUnsafeJavascriptInterface(Object, String, Class)}
2644 * and automatically pass in {@link JavascriptInterface} as the required annotation.
2646 * @param object The Java object to inject into the ContentViewCore's JavaScript context. Null
2647 * values are ignored.
2648 * @param name The name used to expose the instance in JavaScript.
2650 public void addJavascriptInterface(Object object, String name) {
2651 addPossiblyUnsafeJavascriptInterface(object, name, JavascriptInterface.class);
2655 * This method injects the supplied Java object into the ContentViewCore.
2656 * The object is injected into the JavaScript context of the main frame,
2657 * using the supplied name. This allows the Java object to be accessed from
2658 * JavaScript. Note that that injected objects will not appear in
2659 * JavaScript until the page is next (re)loaded. For example:
2660 * <pre> view.addJavascriptInterface(new Object(), "injectedObject");
2661 * view.loadData("<!DOCTYPE html><title></title>", "text/html", null);
2662 * view.loadUrl("javascript:alert(injectedObject.toString())");</pre>
2663 * <p><strong>IMPORTANT:</strong>
2665 * <li> addJavascriptInterface() can be used to allow JavaScript to control
2666 * the host application. This is a powerful feature, but also presents a
2667 * security risk. Use of this method in a ContentViewCore containing
2668 * untrusted content could allow an attacker to manipulate the host
2669 * application in unintended ways, executing Java code with the permissions
2670 * of the host application. Use extreme care when using this method in a
2671 * ContentViewCore which could contain untrusted content. Particular care
2672 * should be taken to avoid unintentional access to inherited methods, such
2673 * as {@link Object#getClass()}. To prevent access to inherited methods,
2674 * pass an annotation for {@code requiredAnnotation}. This will ensure
2675 * that only methods with {@code requiredAnnotation} are exposed to the
2676 * Javascript layer. {@code requiredAnnotation} will be passed to all
2677 * subsequently injected Java objects if any methods return an object. This
2678 * means the same restrictions (or lack thereof) will apply. Alternatively,
2679 * {@link #addJavascriptInterface(Object, String)} can be called, which
2680 * automatically uses the {@link JavascriptInterface} annotation.
2681 * <li> JavaScript interacts with Java objects on a private, background
2682 * thread of the ContentViewCore. Care is therefore required to maintain
2683 * thread safety.</li>
2686 * @param object The Java object to inject into the
2687 * ContentViewCore's JavaScript context. Null
2688 * values are ignored.
2689 * @param name The name used to expose the instance in
2691 * @param requiredAnnotation Restrict exposed methods to ones with this
2692 * annotation. If {@code null} all methods are
2696 public void addPossiblyUnsafeJavascriptInterface(Object object, String name,
2697 Class<? extends Annotation> requiredAnnotation) {
2698 if (mNativeContentViewCore != 0 && object != null) {
2699 mJavaScriptInterfaces.put(name, object);
2700 nativeAddJavascriptInterface(mNativeContentViewCore, object, name, requiredAnnotation);
2705 * Removes a previously added JavaScript interface with the given name.
2707 * @param name The name of the interface to remove.
2709 public void removeJavascriptInterface(String name) {
2710 mJavaScriptInterfaces.remove(name);
2711 if (mNativeContentViewCore != 0) {
2712 nativeRemoveJavascriptInterface(mNativeContentViewCore, name);
2717 * Return the current scale of the ContentView.
2718 * @return The current page scale factor.
2720 public float getScale() {
2721 return mRenderCoordinates.getPageScaleFactor();
2725 * If the view is ready to draw contents to the screen. In hardware mode,
2726 * the initialization of the surface texture may not occur until after the
2727 * view has been added to the layout. This method will return {@code true}
2728 * once the texture is actually ready.
2730 public boolean isReady() {
2731 if (mNativeContentViewCore == 0) return false;
2732 return nativeIsRenderWidgetHostViewReady(mNativeContentViewCore);
2736 private void startContentIntent(String contentUrl) {
2737 getContentViewClient().onStartContentIntent(getContext(), contentUrl);
2741 public void onAccessibilityStateChanged(boolean enabled) {
2742 setAccessibilityState(enabled);
2746 * Determines whether or not this ContentViewCore can handle this accessibility action.
2747 * @param action The action to perform.
2748 * @return Whether or not this action is supported.
2750 public boolean supportsAccessibilityAction(int action) {
2751 return mAccessibilityInjector.supportsAccessibilityAction(action);
2755 * Attempts to perform an accessibility action on the web content. If the accessibility action
2756 * cannot be processed, it returns {@code null}, allowing the caller to know to call the
2757 * super {@link View#performAccessibilityAction(int, Bundle)} method and use that return value.
2758 * Otherwise the return value from this method should be used.
2759 * @param action The action to perform.
2760 * @param arguments Optional action arguments.
2761 * @return Whether the action was performed or {@code null} if the call should be delegated to
2762 * the super {@link View} class.
2764 public boolean performAccessibilityAction(int action, Bundle arguments) {
2765 if (mAccessibilityInjector.supportsAccessibilityAction(action)) {
2766 return mAccessibilityInjector.performAccessibilityAction(action, arguments);
2773 * Set the BrowserAccessibilityManager, used for native accessibility
2774 * (not script injection). This is only set when system accessibility
2776 * @param manager The new BrowserAccessibilityManager.
2778 public void setBrowserAccessibilityManager(BrowserAccessibilityManager manager) {
2779 mBrowserAccessibilityManager = manager;
2783 * Get the BrowserAccessibilityManager, used for native accessibility
2784 * (not script injection). This will return null when system accessibility
2786 * @return This view's BrowserAccessibilityManager.
2788 public BrowserAccessibilityManager getBrowserAccessibilityManager() {
2789 return mBrowserAccessibilityManager;
2793 * If native accessibility (not script injection) is enabled, and if this is
2794 * running on JellyBean or later, returns an AccessibilityNodeProvider that
2795 * implements native accessibility for this view. Returns null otherwise.
2796 * Lazily initializes native accessibility here if it's allowed.
2797 * @return The AccessibilityNodeProvider, if available, or null otherwise.
2799 public AccessibilityNodeProvider getAccessibilityNodeProvider() {
2800 if (mBrowserAccessibilityManager != null) {
2801 return mBrowserAccessibilityManager.getAccessibilityNodeProvider();
2804 if (mNativeAccessibilityAllowed &&
2805 !mNativeAccessibilityEnabled &&
2806 mNativeContentViewCore != 0 &&
2807 Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
2808 mNativeAccessibilityEnabled = true;
2809 nativeSetAccessibilityEnabled(mNativeContentViewCore, true);
2816 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
2818 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
2819 // Note: this is only used by the script-injecting accessibility code.
2820 mAccessibilityInjector.onInitializeAccessibilityNodeInfo(info);
2824 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent)
2826 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
2827 // Note: this is only used by the script-injecting accessibility code.
2828 event.setClassName(this.getClass().getName());
2830 // Identify where the top-left of the screen currently points to.
2831 event.setScrollX(mRenderCoordinates.getScrollXPixInt());
2832 event.setScrollY(mRenderCoordinates.getScrollYPixInt());
2834 // The maximum scroll values are determined by taking the content dimensions and
2835 // subtracting off the actual dimensions of the ChromeView.
2836 int maxScrollXPix = Math.max(0, mRenderCoordinates.getMaxHorizontalScrollPixInt());
2837 int maxScrollYPix = Math.max(0, mRenderCoordinates.getMaxVerticalScrollPixInt());
2838 event.setScrollable(maxScrollXPix > 0 || maxScrollYPix > 0);
2840 // Setting the maximum scroll values requires API level 15 or higher.
2841 final int SDK_VERSION_REQUIRED_TO_SET_SCROLL = 15;
2842 if (Build.VERSION.SDK_INT >= SDK_VERSION_REQUIRED_TO_SET_SCROLL) {
2843 event.setMaxScrollX(maxScrollXPix);
2844 event.setMaxScrollY(maxScrollYPix);
2849 * Returns whether accessibility script injection is enabled on the device
2851 public boolean isDeviceAccessibilityScriptInjectionEnabled() {
2853 // On JellyBean and higher, native accessibility is the default so script
2854 // injection is only allowed if enabled via a flag.
2855 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN &&
2856 !CommandLine.getInstance().hasSwitch(
2857 ContentSwitches.ENABLE_ACCESSIBILITY_SCRIPT_INJECTION)) {
2861 if (!mContentSettings.getJavaScriptEnabled()) {
2865 int result = getContext().checkCallingOrSelfPermission(
2866 android.Manifest.permission.INTERNET);
2867 if (result != PackageManager.PERMISSION_GRANTED) {
2871 Field field = Settings.Secure.class.getField("ACCESSIBILITY_SCRIPT_INJECTION");
2872 field.setAccessible(true);
2873 String accessibilityScriptInjection = (String) field.get(null);
2874 ContentResolver contentResolver = getContext().getContentResolver();
2876 if (mAccessibilityScriptInjectionObserver == null) {
2877 ContentObserver contentObserver = new ContentObserver(new Handler()) {
2879 public void onChange(boolean selfChange, Uri uri) {
2880 setAccessibilityState(mAccessibilityManager.isEnabled());
2883 contentResolver.registerContentObserver(
2884 Settings.Secure.getUriFor(accessibilityScriptInjection),
2887 mAccessibilityScriptInjectionObserver = contentObserver;
2890 return Settings.Secure.getInt(contentResolver, accessibilityScriptInjection, 0) == 1;
2891 } catch (NoSuchFieldException e) {
2892 // Do nothing, default to false.
2893 } catch (IllegalAccessException e) {
2894 // Do nothing, default to false.
2900 * Returns whether or not accessibility injection is being used.
2902 public boolean isInjectingAccessibilityScript() {
2903 return mAccessibilityInjector.accessibilityIsAvailable();
2907 * Returns true if accessibility is on and touch exploration is enabled.
2909 public boolean isTouchExplorationEnabled() {
2910 return mTouchExplorationEnabled;
2914 * Turns browser accessibility on or off.
2915 * If |state| is |false|, this turns off both native and injected accessibility.
2916 * Otherwise, if accessibility script injection is enabled, this will enable the injected
2917 * accessibility scripts. Native accessibility is enabled on demand.
2919 public void setAccessibilityState(boolean state) {
2921 setInjectedAccessibility(false);
2922 mNativeAccessibilityAllowed = false;
2923 mTouchExplorationEnabled = false;
2925 boolean useScriptInjection = isDeviceAccessibilityScriptInjectionEnabled();
2926 setInjectedAccessibility(useScriptInjection);
2927 mNativeAccessibilityAllowed = !useScriptInjection;
2928 mTouchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled();
2933 * Enable or disable injected accessibility features
2935 public void setInjectedAccessibility(boolean enabled) {
2936 mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary();
2937 mAccessibilityInjector.setScriptEnabled(enabled);
2941 * Stop any TTS notifications that are currently going on.
2943 public void stopCurrentAccessibilityNotifications() {
2944 mAccessibilityInjector.onPageLostFocus();
2948 * Inform WebKit that Fullscreen mode has been exited by the user.
2950 public void exitFullscreen() {
2951 if (mNativeContentViewCore != 0) nativeExitFullscreen(mNativeContentViewCore);
2955 * Changes whether hiding the top controls is enabled.
2957 * @param enableHiding Whether hiding the top controls should be enabled or not.
2958 * @param enableShowing Whether showing the top controls should be enabled or not.
2959 * @param animate Whether the transition should be animated or not.
2961 public void updateTopControlsState(boolean enableHiding, boolean enableShowing,
2963 if (mNativeContentViewCore != 0) {
2964 nativeUpdateTopControlsState(
2965 mNativeContentViewCore, enableHiding, enableShowing, animate);
2970 * Callback factory method for nativeGetNavigationHistory().
2973 private void addToNavigationHistory(Object history, int index, String url, String virtualUrl,
2974 String originalUrl, String title, Bitmap favicon) {
2975 NavigationEntry entry = new NavigationEntry(
2976 index, url, virtualUrl, originalUrl, title, favicon);
2977 ((NavigationHistory) history).addEntry(entry);
2981 * Get a copy of the navigation history of the view.
2983 public NavigationHistory getNavigationHistory() {
2984 NavigationHistory history = new NavigationHistory();
2985 if (mNativeContentViewCore != 0) {
2986 int currentIndex = nativeGetNavigationHistory(mNativeContentViewCore, history);
2987 history.setCurrentEntryIndex(currentIndex);
2993 public NavigationHistory getDirectedNavigationHistory(boolean isForward, int itemLimit) {
2994 NavigationHistory history = new NavigationHistory();
2995 if (mNativeContentViewCore != 0) {
2996 nativeGetDirectedNavigationHistory(
2997 mNativeContentViewCore, history, isForward, itemLimit);
3003 * @return The original request URL for the current navigation entry, or null if there is no
3006 public String getOriginalUrlForActiveNavigationEntry() {
3007 if (mNativeContentViewCore != 0) {
3008 return nativeGetOriginalUrlForActiveNavigationEntry(mNativeContentViewCore);
3014 * @return The cached copy of render positions and scales.
3016 public RenderCoordinates getRenderCoordinates() {
3017 return mRenderCoordinates;
3021 private static Rect createRect(int x, int y, int right, int bottom) {
3022 return new Rect(x, y, right, bottom);
3025 public void extractSmartClipData(int x, int y, int width, int height) {
3026 if (mNativeContentViewCore != 0) {
3027 nativeExtractSmartClipData(mNativeContentViewCore, x, y, width, height);
3032 private void onSmartClipDataExtracted(String result) {
3033 if (mSmartClipDataListener != null ) {
3034 mSmartClipDataListener.onSmartClipDataExtracted(result);
3038 public void setSmartClipDataListener(SmartClipDataListener listener) {
3039 mSmartClipDataListener = listener;
3042 public void setBackgroundOpaque(boolean opaque) {
3043 if (mNativeContentViewCore != 0) {
3044 nativeSetBackgroundOpaque(mNativeContentViewCore, opaque);
3049 * Offer a long press gesture to the embedding View, primarily for WebView compatibility.
3051 * @return true if the embedder handled the event.
3053 private boolean offerLongPressToEmbedder() {
3054 return mContainerView.performLongClick();
3058 * Reset scroll and fling accounting, notifying listeners as appropriate.
3059 * This is useful as a failsafe when the input stream may have been interruped.
3061 private void resetScrollInProgress() {
3062 if (!isScrollInProgress()) return;
3064 final boolean touchScrollInProgress = mTouchScrollInProgress;
3065 final int potentiallyActiveFlingCount = mPotentiallyActiveFlingCount;
3067 mTouchScrollInProgress = false;
3068 mPotentiallyActiveFlingCount = 0;
3070 if (touchScrollInProgress) updateGestureStateListener(GestureEventType.SCROLL_END);
3071 if (potentiallyActiveFlingCount > 0) updateGestureStateListener(GestureEventType.FLING_END);
3074 private native long nativeInit(long webContentsPtr,
3075 long viewAndroidPtr, long windowAndroidPtr, HashSet<Object> retainedObjectSet);
3078 private ContentVideoViewClient getContentVideoViewClient() {
3079 return getContentViewClient().getContentVideoViewClient();
3083 private boolean shouldBlockMediaRequest(String url) {
3084 return getContentViewClient().shouldBlockMediaRequest(url);
3088 private void onNativeFlingStopped() {
3089 // Note that mTouchScrollInProgress should normally be false at this
3090 // point, but we reset it anyway as another failsafe.
3091 mTouchScrollInProgress = false;
3092 if (mPotentiallyActiveFlingCount <= 0) return;
3093 mPotentiallyActiveFlingCount--;
3094 updateGestureStateListener(GestureEventType.FLING_END);
3098 public void onScreenOrientationChanged(int orientation) {
3099 sendOrientationChangeEvent(orientation);
3102 private native WebContents nativeGetWebContentsAndroid(long nativeContentViewCoreImpl);
3104 private native void nativeOnJavaContentViewCoreDestroyed(long nativeContentViewCoreImpl);
3106 private native void nativeLoadUrl(
3107 long nativeContentViewCoreImpl,
3113 int uaOverrideOption,
3114 String extraHeaders,
3116 String baseUrlForDataUrl,
3117 String virtualUrlForDataUrl,
3118 boolean canLoadLocalResources,
3119 boolean isRendererInitiated);
3121 private native String nativeGetURL(long nativeContentViewCoreImpl);
3123 private native void nativeShowInterstitialPage(
3124 long nativeContentViewCoreImpl, String url, long nativeInterstitialPageDelegateAndroid);
3125 private native boolean nativeIsShowingInterstitialPage(long nativeContentViewCoreImpl);
3127 private native boolean nativeIsIncognito(long nativeContentViewCoreImpl);
3129 private native void nativeSetFocus(long nativeContentViewCoreImpl, boolean focused);
3131 private native void nativeSendOrientationChangeEvent(
3132 long nativeContentViewCoreImpl, int orientation);
3134 // All touch events (including flings, scrolls etc) accept coordinates in physical pixels.
3135 private native boolean nativeOnTouchEvent(
3136 long nativeContentViewCoreImpl, MotionEvent event,
3137 long timeMs, int action, int pointerCount, int historySize, int actionIndex,
3138 float x0, float y0, float x1, float y1,
3139 int pointerId0, int pointerId1,
3140 float touchMajor0, float touchMajor1,
3141 float rawX, float rawY);
3143 private native int nativeSendMouseMoveEvent(
3144 long nativeContentViewCoreImpl, long timeMs, float x, float y);
3146 private native int nativeSendMouseWheelEvent(
3147 long nativeContentViewCoreImpl, long timeMs, float x, float y, float verticalAxis);
3149 private native void nativeScrollBegin(
3150 long nativeContentViewCoreImpl, long timeMs, float x, float y, float hintX,
3153 private native void nativeScrollEnd(long nativeContentViewCoreImpl, long timeMs);
3155 private native void nativeScrollBy(
3156 long nativeContentViewCoreImpl, long timeMs, float x, float y,
3157 float deltaX, float deltaY);
3159 private native void nativeFlingStart(
3160 long nativeContentViewCoreImpl, long timeMs, float x, float y, float vx, float vy);
3162 private native void nativeFlingCancel(long nativeContentViewCoreImpl, long timeMs);
3164 private native void nativeSingleTap(
3165 long nativeContentViewCoreImpl, long timeMs, float x, float y);
3167 private native void nativeDoubleTap(
3168 long nativeContentViewCoreImpl, long timeMs, float x, float y);
3170 private native void nativeLongPress(
3171 long nativeContentViewCoreImpl, long timeMs, float x, float y);
3173 private native void nativePinchBegin(
3174 long nativeContentViewCoreImpl, long timeMs, float x, float y);
3176 private native void nativePinchEnd(long nativeContentViewCoreImpl, long timeMs);
3178 private native void nativePinchBy(long nativeContentViewCoreImpl, long timeMs,
3179 float anchorX, float anchorY, float deltaScale);
3181 private native void nativeSelectBetweenCoordinates(
3182 long nativeContentViewCoreImpl, float x1, float y1, float x2, float y2);
3184 private native void nativeMoveCaret(long nativeContentViewCoreImpl, float x, float y);
3186 private native void nativeResetGestureDetection(long nativeContentViewCoreImpl);
3187 private native void nativeSetDoubleTapSupportEnabled(
3188 long nativeContentViewCoreImpl, boolean enabled);
3189 private native void nativeSetMultiTouchZoomSupportEnabled(
3190 long nativeContentViewCoreImpl, boolean enabled);
3192 private native void nativeLoadIfNecessary(long nativeContentViewCoreImpl);
3193 private native void nativeRequestRestoreLoad(long nativeContentViewCoreImpl);
3195 private native void nativeReload(long nativeContentViewCoreImpl, boolean checkForRepost);
3196 private native void nativeReloadIgnoringCache(
3197 long nativeContentViewCoreImpl, boolean checkForRepost);
3199 private native void nativeCancelPendingReload(long nativeContentViewCoreImpl);
3201 private native void nativeContinuePendingReload(long nativeContentViewCoreImpl);
3203 private native void nativeSelectPopupMenuItems(long nativeContentViewCoreImpl, int[] indices);
3205 private native void nativeScrollFocusedEditableNodeIntoView(long nativeContentViewCoreImpl);
3207 private native void nativeSelectWordAroundCaret(long nativeContentViewCoreImpl);
3209 private native void nativeClearHistory(long nativeContentViewCoreImpl);
3211 private native void nativeAddStyleSheetByURL(long nativeContentViewCoreImpl,
3212 String stylesheetUrl);
3214 private native void nativeEvaluateJavaScript(long nativeContentViewCoreImpl,
3215 String script, JavaScriptCallback callback, boolean startRenderer);
3217 private native long nativeGetNativeImeAdapter(long nativeContentViewCoreImpl);
3219 private native int nativeGetCurrentRenderProcessId(long nativeContentViewCoreImpl);
3221 private native int nativeGetBackgroundColor(long nativeContentViewCoreImpl);
3223 private native void nativeOnShow(long nativeContentViewCoreImpl);
3224 private native void nativeOnHide(long nativeContentViewCoreImpl);
3226 private native void nativeSetUseDesktopUserAgent(long nativeContentViewCoreImpl,
3227 boolean enabled, boolean reloadOnChange);
3228 private native boolean nativeGetUseDesktopUserAgent(long nativeContentViewCoreImpl);
3230 private native void nativeClearSslPreferences(long nativeContentViewCoreImpl);
3232 private native void nativeSetAllowJavascriptInterfacesInspection(
3233 long nativeContentViewCoreImpl, boolean allow);
3235 private native void nativeAddJavascriptInterface(long nativeContentViewCoreImpl, Object object,
3236 String name, Class requiredAnnotation);
3238 private native void nativeRemoveJavascriptInterface(long nativeContentViewCoreImpl,
3241 private native int nativeGetNavigationHistory(long nativeContentViewCoreImpl, Object context);
3242 private native void nativeGetDirectedNavigationHistory(long nativeContentViewCoreImpl,
3243 Object context, boolean isForward, int maxEntries);
3244 private native String nativeGetOriginalUrlForActiveNavigationEntry(
3245 long nativeContentViewCoreImpl);
3247 private native void nativeWasResized(long nativeContentViewCoreImpl);
3249 private native boolean nativeIsRenderWidgetHostViewReady(long nativeContentViewCoreImpl);
3251 private native void nativeExitFullscreen(long nativeContentViewCoreImpl);
3252 private native void nativeUpdateTopControlsState(long nativeContentViewCoreImpl,
3253 boolean enableHiding, boolean enableShowing, boolean animate);
3255 private native void nativeShowImeIfNeeded(long nativeContentViewCoreImpl);
3257 private native void nativeSetAccessibilityEnabled(
3258 long nativeContentViewCoreImpl, boolean enabled);
3260 private native void nativeExtractSmartClipData(long nativeContentViewCoreImpl,
3261 int x, int y, int w, int h);
3262 private native void nativeSetBackgroundOpaque(long nativeContentViewCoreImpl, boolean opaque);