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.CalledByNative;
52 import org.chromium.base.CommandLine;
53 import org.chromium.base.JNINamespace;
54 import org.chromium.base.ObserverList;
55 import org.chromium.base.ObserverList.RewindableIterator;
56 import org.chromium.base.TraceEvent;
57 import org.chromium.content.R;
58 import org.chromium.content.browser.ScreenOrientationListener.ScreenOrientationObserver;
59 import org.chromium.content.browser.accessibility.AccessibilityInjector;
60 import org.chromium.content.browser.accessibility.BrowserAccessibilityManager;
61 import org.chromium.content.browser.input.AdapterInputConnection;
62 import org.chromium.content.browser.input.HandleView;
63 import org.chromium.content.browser.input.ImeAdapter;
64 import org.chromium.content.browser.input.ImeAdapter.AdapterInputConnectionFactory;
65 import org.chromium.content.browser.input.InputMethodManagerWrapper;
66 import org.chromium.content.browser.input.InsertionHandleController;
67 import org.chromium.content.browser.input.SelectPopupDialog;
68 import org.chromium.content.browser.input.SelectPopupItem;
69 import org.chromium.content.browser.input.SelectionHandleController;
70 import org.chromium.content.common.ContentSwitches;
71 import org.chromium.content_public.browser.GestureStateListener;
72 import org.chromium.content_public.browser.WebContents;
73 import org.chromium.ui.base.ViewAndroid;
74 import org.chromium.ui.base.ViewAndroidDelegate;
75 import org.chromium.ui.base.WindowAndroid;
76 import org.chromium.ui.gfx.DeviceDisplayInfo;
78 import java.lang.annotation.Annotation;
79 import java.lang.reflect.Field;
80 import java.util.ArrayList;
81 import java.util.HashMap;
82 import java.util.HashSet;
83 import java.util.List;
87 * Provides a Java-side 'wrapper' around a WebContent (native) instance.
88 * Contains all the major functionality necessary to manage the lifecycle of a ContentView without
89 * being tied to the view system.
91 @JNINamespace("content")
92 public class ContentViewCore
93 implements NavigationClient, AccessibilityStateChangeListener, ScreenOrientationObserver {
95 private static final String TAG = "ContentViewCore";
97 // Used to avoid enabling zooming in / out if resulting zooming will
98 // produce little visible difference.
99 private static final float ZOOM_CONTROLS_EPSILON = 0.007f;
101 // Used to represent gestures for long press and long tap.
102 private static final int IS_LONG_PRESS = 1;
103 private static final int IS_LONG_TAP = 2;
105 // Length of the delay (in ms) before fading in handles after the last page movement.
106 private static final int TEXT_HANDLE_FADE_IN_DELAY = 300;
108 // If the embedder adds a JavaScript interface object that contains an indirect reference to
109 // the ContentViewCore, then storing a strong ref to the interface object on the native
110 // side would prevent garbage collection of the ContentViewCore (as that strong ref would
111 // create a new GC root).
112 // For that reason, we store only a weak reference to the interface object on the
113 // native side. However we still need a strong reference on the Java side to
114 // prevent garbage collection if the embedder doesn't maintain their own ref to the
115 // interface object - the Java side ref won't create a new GC root.
116 // This map stores those refernces. We put into the map on addJavaScriptInterface()
117 // and remove from it in removeJavaScriptInterface().
118 private final Map<String, Object> mJavaScriptInterfaces = new HashMap<String, Object>();
120 // Additionally, we keep track of all Java bound JS objects that are in use on the
121 // current page to ensure that they are not garbage collected until the page is
122 // navigated. This includes interface objects that have been removed
123 // via the removeJavaScriptInterface API and transient objects returned from methods
124 // on the interface object. Note we use HashSet rather than Set as the native side
125 // expects HashSet (no bindings for interfaces).
126 private final HashSet<Object> mRetainedJavaScriptObjects = new HashSet<Object>();
129 * Interface that consumers of {@link ContentViewCore} must implement to allow the proper
130 * dispatching of view methods through the containing view.
133 * All methods with the "super_" prefix should be routed to the parent of the
134 * implementing container view.
136 @SuppressWarnings("javadoc")
137 public interface InternalAccessDelegate {
139 * @see View#drawChild(Canvas, View, long)
141 boolean drawChild(Canvas canvas, View child, long drawingTime);
144 * @see View#onKeyUp(keyCode, KeyEvent)
146 boolean super_onKeyUp(int keyCode, KeyEvent event);
149 * @see View#dispatchKeyEventPreIme(KeyEvent)
151 boolean super_dispatchKeyEventPreIme(KeyEvent event);
154 * @see View#dispatchKeyEvent(KeyEvent)
156 boolean super_dispatchKeyEvent(KeyEvent event);
159 * @see View#onGenericMotionEvent(MotionEvent)
161 boolean super_onGenericMotionEvent(MotionEvent event);
164 * @see View#onConfigurationChanged(Configuration)
166 void super_onConfigurationChanged(Configuration newConfig);
169 * @see View#onScrollChanged(int, int, int, int)
171 void onScrollChanged(int lPix, int tPix, int oldlPix, int oldtPix);
174 * @see View#awakenScrollBars()
176 boolean awakenScrollBars();
179 * @see View#awakenScrollBars(int, boolean)
181 boolean super_awakenScrollBars(int startDelay, boolean invalidate);
185 * An interface for controlling visibility and state of embedder-provided zoom controls.
187 public interface ZoomControlsDelegate {
189 * Called when it's reasonable to show zoom controls.
191 void invokeZoomPicker();
194 * Called when zoom controls need to be hidden (e.g. when the view hides).
196 void dismissZoomPicker();
199 * Called when page scale has been changed, so the controls can update their state.
201 void updateZoomControls();
205 * An interface that allows the embedder to be notified when the results of
206 * extractSmartClipData are available.
208 public interface SmartClipDataListener {
209 public void onSmartClipDataExtracted(String result);
212 private VSyncManager.Provider mVSyncProvider;
213 private VSyncManager.Listener mVSyncListener;
214 private int mVSyncSubscriberCount;
215 private boolean mVSyncListenerRegistered;
217 // To avoid IPC delay we use input events to directly trigger a vsync signal in the renderer.
218 // When we do this, we also need to avoid sending the real vsync signal for the current
219 // frame to avoid double-ticking. This flag is used to inhibit the next vsync notification.
220 private boolean mDidSignalVSyncUsingInputEvent;
222 public VSyncManager.Listener getVSyncListener(VSyncManager.Provider vsyncProvider) {
223 if (mVSyncProvider != null && mVSyncListenerRegistered) {
224 mVSyncProvider.unregisterVSyncListener(mVSyncListener);
225 mVSyncListenerRegistered = false;
228 mVSyncProvider = vsyncProvider;
229 mVSyncListener = new VSyncManager.Listener() {
231 public void updateVSync(long tickTimeMicros, long intervalMicros) {
232 if (mNativeContentViewCore != 0) {
233 nativeUpdateVSyncParameters(mNativeContentViewCore, tickTimeMicros,
239 public void onVSync(long frameTimeMicros) {
240 animateIfNecessary(frameTimeMicros);
242 if (mRequestedVSyncForInput) {
243 mRequestedVSyncForInput = false;
244 removeVSyncSubscriber();
246 if (mNativeContentViewCore != 0) {
247 nativeOnVSync(mNativeContentViewCore, frameTimeMicros);
252 if (mVSyncSubscriberCount > 0) {
253 // addVSyncSubscriber() is called before getVSyncListener.
254 vsyncProvider.registerVSyncListener(mVSyncListener);
255 mVSyncListenerRegistered = true;
258 return mVSyncListener;
262 void addVSyncSubscriber() {
263 if (!isVSyncNotificationEnabled()) {
264 mDidSignalVSyncUsingInputEvent = false;
266 if (mVSyncProvider != null && !mVSyncListenerRegistered) {
267 mVSyncProvider.registerVSyncListener(mVSyncListener);
268 mVSyncListenerRegistered = true;
270 mVSyncSubscriberCount++;
274 void removeVSyncSubscriber() {
275 if (mVSyncProvider != null && mVSyncSubscriberCount == 1) {
276 assert mVSyncListenerRegistered;
277 mVSyncProvider.unregisterVSyncListener(mVSyncListener);
278 mVSyncListenerRegistered = false;
280 mVSyncSubscriberCount--;
281 assert mVSyncSubscriberCount >= 0;
285 private void resetVSyncNotification() {
286 while (isVSyncNotificationEnabled()) removeVSyncSubscriber();
287 mVSyncSubscriberCount = 0;
288 mVSyncListenerRegistered = false;
289 mNeedAnimate = false;
292 private boolean isVSyncNotificationEnabled() {
293 return mVSyncProvider != null && mVSyncListenerRegistered;
297 private void setNeedsAnimate() {
300 addVSyncSubscriber();
304 private final Context mContext;
305 private ViewGroup mContainerView;
306 private InternalAccessDelegate mContainerViewInternals;
307 private WebContents mWebContents;
308 private WebContentsObserverAndroid mWebContentsObserver;
310 private ContentViewClient mContentViewClient;
312 private ContentSettings mContentSettings;
314 // Native pointer to C++ ContentViewCoreImpl object which will be set by nativeInit().
315 private long mNativeContentViewCore = 0;
317 private boolean mInForeground = false;
319 private final ObserverList<GestureStateListener> mGestureStateListeners;
320 private final RewindableIterator<GestureStateListener> mGestureStateListenersIterator;
321 private ZoomControlsDelegate mZoomControlsDelegate;
323 private PopupZoomer mPopupZoomer;
324 private SelectPopupDialog mSelectPopupDialog;
326 private Runnable mFakeMouseMoveRunnable = null;
328 // Only valid when focused on a text / password field.
329 private ImeAdapter mImeAdapter;
330 private ImeAdapter.AdapterInputConnectionFactory mAdapterInputConnectionFactory;
331 private AdapterInputConnection mInputConnection;
332 private InputMethodManagerWrapper mInputMethodManagerWrapper;
334 private SelectionHandleController mSelectionHandleController;
335 private InsertionHandleController mInsertionHandleController;
337 private Runnable mDeferredHandleFadeInRunnable;
339 private PositionObserver mPositionObserver;
340 private PositionObserver.Listener mPositionListener;
342 // Size of the viewport in physical pixels as set from onSizeChanged.
343 private int mViewportWidthPix;
344 private int mViewportHeightPix;
345 private int mPhysicalBackingWidthPix;
346 private int mPhysicalBackingHeightPix;
347 private int mOverdrawBottomHeightPix;
348 private int mViewportSizeOffsetWidthPix;
349 private int mViewportSizeOffsetHeightPix;
350 private int mLocationInWindowX;
351 private int mLocationInWindowY;
353 // Cached copy of all positions and scales as reported by the renderer.
354 private final RenderCoordinates mRenderCoordinates;
356 private final RenderCoordinates.NormalizedPoint mStartHandlePoint;
357 private final RenderCoordinates.NormalizedPoint mEndHandlePoint;
358 private final RenderCoordinates.NormalizedPoint mInsertionHandlePoint;
360 // Cached copy of the visible rectangle defined by two points. Needed to determine
361 // visibility of insertion/selection handles.
362 private final RenderCoordinates.NormalizedPoint mTopLeftVisibilityClippingPoint;
363 private final RenderCoordinates.NormalizedPoint mBottomRightVisibilityClippingPoint;
365 // Tracks whether a selection is currently active. When applied to selected text, indicates
366 // whether the last selected text is still highlighted.
367 private boolean mHasSelection;
368 private String mLastSelectedText;
369 private boolean mSelectionEditable;
370 private ActionMode mActionMode;
371 private boolean mUnselectAllOnActionModeDismiss;
373 // Delegate that will handle GET downloads, and be notified of completion of POST downloads.
374 private ContentViewDownloadDelegate mDownloadDelegate;
376 // The AccessibilityInjector that handles loading Accessibility scripts into the web page.
377 private AccessibilityInjector mAccessibilityInjector;
379 // Whether native accessibility, i.e. without any script injection, is allowed.
380 private boolean mNativeAccessibilityAllowed;
382 // Whether native accessibility, i.e. without any script injection, has been enabled.
383 private boolean mNativeAccessibilityEnabled;
385 // Handles native accessibility, i.e. without any script injection.
386 private BrowserAccessibilityManager mBrowserAccessibilityManager;
388 // System accessibility service.
389 private final AccessibilityManager mAccessibilityManager;
391 // Accessibility touch exploration state.
392 private boolean mTouchExplorationEnabled;
394 // Allows us to dynamically respond when the accessibility script injection flag changes.
395 private ContentObserver mAccessibilityScriptInjectionObserver;
397 // Temporary notification to tell onSizeChanged to focus a form element,
398 // because the OSK was just brought up.
399 private final Rect mFocusPreOSKViewportRect = new Rect();
401 // Whether we received a new frame since consumePendingRendererFrame() was last called.
402 private boolean mPendingRendererFrame = false;
404 // Whether we should animate at the next vsync tick.
405 private boolean mNeedAnimate = false;
407 // Whether we requested a proactive vsync event in response to touch input.
408 // This reduces the latency of responding to input by ensuring the renderer
409 // is sent a BeginFrame for every touch event we receive. Otherwise the
410 // renderer's SetNeedsBeginFrame message would get serviced at the next
412 private boolean mRequestedVSyncForInput = false;
414 // On single tap this will store the x, y coordinates of the touch.
415 private int mSingleTapX;
416 private int mSingleTapY;
418 // Whether a touch scroll sequence is active, used to hide text selection
419 // handles. Note that a scroll sequence will *always* bound a pinch
420 // sequence, so this will also be true for the duration of a pinch gesture.
421 private boolean mTouchScrollInProgress;
423 // The outstanding fling start events that hasn't got fling end yet. It may be > 1 because
424 // onNativeFlingStopped() is called asynchronously.
425 private int mPotentiallyActiveFlingCount;
427 private ViewAndroid mViewAndroid;
429 private SmartClipDataListener mSmartClipDataListener = null;
431 // This holds the state of editable text (e.g. contents of <input>, contenteditable) of
432 // a focused element.
433 // Every time the user, IME, javascript (Blink), autofill etc. modifies the content, the new
434 // state must be reflected to this to keep consistency.
435 private Editable mEditable;
438 * PID used to indicate an invalid render process.
440 // Keep in sync with the value returned from ContentViewCoreImpl::GetCurrentRendererProcessId()
441 // if there is no render process.
442 public static final int INVALID_RENDER_PROCESS_PID = 0;
445 * Constructs a new ContentViewCore. Embedders must call initialize() after constructing
446 * a ContentViewCore and before using it.
448 * @param context The context used to create this.
450 public ContentViewCore(Context context) {
453 mAdapterInputConnectionFactory = new AdapterInputConnectionFactory();
454 mInputMethodManagerWrapper = new InputMethodManagerWrapper(mContext);
456 mRenderCoordinates = new RenderCoordinates();
457 float deviceScaleFactor = getContext().getResources().getDisplayMetrics().density;
458 String forceScaleFactor = CommandLine.getInstance().getSwitchValue(
459 ContentSwitches.FORCE_DEVICE_SCALE_FACTOR);
460 if (forceScaleFactor != null) {
461 deviceScaleFactor = Float.valueOf(forceScaleFactor);
463 mRenderCoordinates.setDeviceScaleFactor(deviceScaleFactor);
464 mStartHandlePoint = mRenderCoordinates.createNormalizedPoint();
465 mEndHandlePoint = mRenderCoordinates.createNormalizedPoint();
466 mInsertionHandlePoint = mRenderCoordinates.createNormalizedPoint();
467 mTopLeftVisibilityClippingPoint = mRenderCoordinates.createNormalizedPoint();
468 mBottomRightVisibilityClippingPoint = mRenderCoordinates.createNormalizedPoint();
469 mAccessibilityManager = (AccessibilityManager)
470 getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
471 mGestureStateListeners = new ObserverList<GestureStateListener>();
472 mGestureStateListenersIterator = mGestureStateListeners.rewindableIterator();
474 mEditable = Editable.Factory.getInstance().newEditable("");
475 Selection.setSelection(mEditable, 0);
479 * @return The context used for creating this ContentViewCore.
482 public Context getContext() {
487 * @return The ViewGroup that all view actions of this ContentViewCore should interact with.
489 public ViewGroup getContainerView() {
490 return mContainerView;
494 * @return The WebContents currently being rendered.
496 public WebContents getWebContents() {
501 * Specifies how much smaller the WebKit layout size should be relative to the size of this
503 * @param offsetXPix The X amount in pixels to shrink the viewport by.
504 * @param offsetYPix The Y amount in pixels to shrink the viewport by.
506 public void setViewportSizeOffset(int offsetXPix, int offsetYPix) {
507 if (offsetXPix != mViewportSizeOffsetWidthPix ||
508 offsetYPix != mViewportSizeOffsetHeightPix) {
509 mViewportSizeOffsetWidthPix = offsetXPix;
510 mViewportSizeOffsetHeightPix = offsetYPix;
511 if (mNativeContentViewCore != 0) nativeWasResized(mNativeContentViewCore);
516 * Returns a delegate that can be used to add and remove views from the ContainerView.
518 * NOTE: Use with care, as not all ContentViewCore users setup their ContainerView in the same
519 * way. In particular, the Android WebView has limitations on what implementation details can
520 * be provided via a child view, as they are visible in the API and could introduce
521 * compatibility breaks with existing applications. If in doubt, contact the
522 * android_webview/OWNERS
524 * @return A ViewAndroidDelegate that can be used to add and remove views.
527 public ViewAndroidDelegate getViewAndroidDelegate() {
528 return new ViewAndroidDelegate() {
530 public View acquireAnchorView() {
531 View anchorView = new View(getContext());
532 mContainerView.addView(anchorView);
537 @SuppressWarnings("deprecation") // AbsoluteLayout
538 public void setAnchorViewPosition(
539 View view, float x, float y, float width, float height) {
540 assert view.getParent() == mContainerView;
542 float scale = (float) DeviceDisplayInfo.create(getContext()).getDIPScale();
544 // The anchor view should not go outside the bounds of the ContainerView.
545 int leftMargin = Math.round(x * scale);
546 int topMargin = Math.round(mRenderCoordinates.getContentOffsetYPix() + y * scale);
547 int scaledWidth = Math.round(width * scale);
548 // ContentViewCore currently only supports these two container view types.
549 if (mContainerView instanceof FrameLayout) {
550 if (scaledWidth + leftMargin > mContainerView.getWidth()) {
551 scaledWidth = mContainerView.getWidth() - leftMargin;
553 FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
554 scaledWidth, Math.round(height * scale));
555 lp.leftMargin = leftMargin;
556 lp.topMargin = topMargin;
557 view.setLayoutParams(lp);
558 } else if (mContainerView instanceof android.widget.AbsoluteLayout) {
559 // This fixes the offset due to a difference in
560 // scrolling model of WebView vs. Chrome.
561 // TODO(sgurun) fix this to use mContainerView.getScroll[X/Y]()
562 // as it naturally accounts for scroll differences between
564 leftMargin += mRenderCoordinates.getScrollXPixInt();
565 topMargin += mRenderCoordinates.getScrollYPixInt();
567 android.widget.AbsoluteLayout.LayoutParams lp =
568 new android.widget.AbsoluteLayout.LayoutParams(
569 scaledWidth, (int) (height * scale), leftMargin, topMargin);
570 view.setLayoutParams(lp);
572 Log.e(TAG, "Unknown layout " + mContainerView.getClass().getName());
577 public void releaseAnchorView(View anchorView) {
578 mContainerView.removeView(anchorView);
584 public void setImeAdapterForTest(ImeAdapter imeAdapter) {
585 mImeAdapter = imeAdapter;
589 public ImeAdapter getImeAdapterForTest() {
594 public void setAdapterInputConnectionFactory(AdapterInputConnectionFactory factory) {
595 mAdapterInputConnectionFactory = factory;
599 public void setInputMethodManagerWrapperForTest(InputMethodManagerWrapper immw) {
600 mInputMethodManagerWrapper = immw;
604 public AdapterInputConnection getInputConnectionForTest() {
605 return mInputConnection;
609 public void setContainerViewForTest(ViewGroup view) {
610 mContainerView = view;
613 private ImeAdapter createImeAdapter(Context context) {
614 return new ImeAdapter(mInputMethodManagerWrapper,
615 new ImeAdapter.ImeAdapterDelegate() {
617 public void onImeEvent(boolean isFinish) {
618 getContentViewClient().onImeEvent();
625 public void onSetFieldValue() {
626 scrollFocusedEditableNodeIntoView();
630 public void onDismissInput() {
631 getContentViewClient().onImeStateChangeRequested(false);
635 public View getAttachedView() {
636 return mContainerView;
640 public ResultReceiver getNewShowKeyboardReceiver() {
641 return new ResultReceiver(new Handler()) {
643 public void onReceiveResult(int resultCode, Bundle resultData) {
644 getContentViewClient().onImeStateChangeRequested(
645 resultCode == InputMethodManager.RESULT_SHOWN ||
646 resultCode == InputMethodManager.RESULT_UNCHANGED_SHOWN);
647 if (resultCode == InputMethodManager.RESULT_SHOWN) {
648 // If OSK is newly shown, delay the form focus until
649 // the onSizeChanged (in order to adjust relative to the
651 // TODO(jdduke): We should not assume that onSizeChanged will
652 // always be called, crbug.com/294908.
653 getContainerView().getWindowVisibleDisplayFrame(
654 mFocusPreOSKViewportRect);
655 } else if (resultCode ==
656 InputMethodManager.RESULT_UNCHANGED_SHOWN) {
657 // If the OSK was already there, focus the form immediately.
658 scrollFocusedEditableNodeIntoView();
669 * @param containerView The view that will act as a container for all views created by this.
670 * @param internalDispatcher Handles dispatching all hidden or super methods to the
672 * @param nativeWebContents A pointer to the native web contents.
673 * @param windowAndroid An instance of the WindowAndroid.
675 // Perform important post-construction set up of the ContentViewCore.
676 // We do not require the containing view in the constructor to allow embedders to create a
677 // ContentViewCore without having fully created its containing view. The containing view
678 // is a vital component of the ContentViewCore, so embedders must exercise caution in what
679 // they do with the ContentViewCore before calling initialize().
680 // We supply the nativeWebContents pointer here rather than in the constructor to allow us
681 // to set the private browsing mode at a later point for the WebView implementation.
682 // Note that the caller remains the owner of the nativeWebContents and is responsible for
683 // deleting it after destroying the ContentViewCore.
684 public void initialize(ViewGroup containerView, InternalAccessDelegate internalDispatcher,
685 long nativeWebContents, WindowAndroid windowAndroid) {
686 mContainerView = containerView;
687 mPositionObserver = new ViewPositionObserver(mContainerView);
688 mPositionListener = new PositionObserver.Listener() {
690 public void onPositionChanged(int x, int y) {
691 if (isSelectionHandleShowing() || isInsertionHandleShowing()) {
692 temporarilyHideTextHandles();
697 long windowNativePointer = windowAndroid != null ? windowAndroid.getNativePointer() : 0;
699 long viewAndroidNativePointer = 0;
700 if (windowNativePointer != 0) {
701 mViewAndroid = new ViewAndroid(windowAndroid, getViewAndroidDelegate());
702 viewAndroidNativePointer = mViewAndroid.getNativePointer();
705 mZoomControlsDelegate = new ZoomControlsDelegate() {
707 public void invokeZoomPicker() {}
709 public void dismissZoomPicker() {}
711 public void updateZoomControls() {}
714 mNativeContentViewCore = nativeInit(
715 nativeWebContents, viewAndroidNativePointer, windowNativePointer);
716 mWebContents = nativeGetWebContentsAndroid(mNativeContentViewCore);
717 mContentSettings = new ContentSettings(this, mNativeContentViewCore);
718 initializeContainerView(internalDispatcher);
720 mAccessibilityInjector = AccessibilityInjector.newInstance(this);
722 String contentDescription = "Web View";
723 if (R.string.accessibility_content_view == 0) {
724 Log.w(TAG, "Setting contentDescription to 'Web View' as no value was specified.");
726 contentDescription = mContext.getResources().getString(
727 R.string.accessibility_content_view);
729 mContainerView.setContentDescription(contentDescription);
730 mWebContentsObserver = new WebContentsObserverAndroid(this) {
732 public void didStartLoading(String url) {
734 resetGestureDetectors();
740 void onNativeContentViewCoreDestroyed(long nativeContentViewCore) {
741 assert nativeContentViewCore == mNativeContentViewCore;
742 mNativeContentViewCore = 0;
746 * Set the Container view Internals.
747 * @param internalDispatcher Handles dispatching all hidden or super methods to the
750 public void setContainerViewInternals(InternalAccessDelegate internalDispatcher) {
751 mContainerViewInternals = internalDispatcher;
755 * Initializes the View that will contain all Views created by the ContentViewCore.
757 * @param internalDispatcher Handles dispatching all hidden or super methods to the
760 private void initializeContainerView(InternalAccessDelegate internalDispatcher) {
762 mContainerViewInternals = internalDispatcher;
764 mContainerView.setWillNotDraw(false);
765 mContainerView.setClickable(true);
767 mRenderCoordinates.reset();
768 onRenderCoordinatesUpdated();
770 initPopupZoomer(mContext);
771 mImeAdapter = createImeAdapter(mContext);
775 private void initPopupZoomer(Context context) {
776 mPopupZoomer = new PopupZoomer(context);
777 mPopupZoomer.setOnVisibilityChangedListener(new PopupZoomer.OnVisibilityChangedListener() {
779 public void onPopupZoomerShown(final PopupZoomer zoomer) {
780 mContainerView.post(new Runnable() {
783 if (mContainerView.indexOfChild(zoomer) == -1) {
784 mContainerView.addView(zoomer);
786 assert false : "PopupZoomer should never be shown without being hidden";
793 public void onPopupZoomerHidden(final PopupZoomer zoomer) {
794 mContainerView.post(new Runnable() {
797 if (mContainerView.indexOfChild(zoomer) != -1) {
798 mContainerView.removeView(zoomer);
799 mContainerView.invalidate();
801 assert false : "PopupZoomer should never be hidden without being shown";
807 // TODO(yongsheng): LONG_TAP is not enabled in PopupZoomer. So need to dispatch a LONG_TAP
808 // gesture if a user completes a tap on PopupZoomer UI after a LONG_PRESS gesture.
809 PopupZoomer.OnTapListener listener = new PopupZoomer.OnTapListener() {
811 public boolean onSingleTap(View v, MotionEvent e) {
812 mContainerView.requestFocus();
813 if (mNativeContentViewCore != 0) {
814 nativeSingleTap(mNativeContentViewCore, e.getEventTime(), e.getX(), e.getY());
820 public boolean onLongPress(View v, MotionEvent e) {
821 if (mNativeContentViewCore != 0) {
822 nativeLongPress(mNativeContentViewCore, e.getEventTime(), e.getX(), e.getY());
827 mPopupZoomer.setOnTapListener(listener);
831 * Destroy the internal state of the ContentView. This method may only be
832 * called after the ContentView has been removed from the view system. No
833 * other methods may be called on this ContentView after this method has
836 public void destroy() {
837 if (mNativeContentViewCore != 0) {
838 nativeOnJavaContentViewCoreDestroyed(mNativeContentViewCore);
841 resetVSyncNotification();
842 mVSyncProvider = null;
843 if (mViewAndroid != null) mViewAndroid.destroy();
844 mNativeContentViewCore = 0;
845 mContentSettings = null;
846 mJavaScriptInterfaces.clear();
847 mRetainedJavaScriptObjects.clear();
848 unregisterAccessibilityContentObserver();
849 mGestureStateListeners.clear();
850 ScreenOrientationListener.getInstance().removeObserver(this);
853 private void unregisterAccessibilityContentObserver() {
854 if (mAccessibilityScriptInjectionObserver == null) {
857 getContext().getContentResolver().unregisterContentObserver(
858 mAccessibilityScriptInjectionObserver);
859 mAccessibilityScriptInjectionObserver = null;
863 * Returns true initially, false after destroy() has been called.
864 * It is illegal to call any other public method after destroy().
866 public boolean isAlive() {
867 return mNativeContentViewCore != 0;
871 * This is only useful for passing over JNI to native code that requires ContentViewCore*.
872 * @return native ContentViewCore pointer.
875 public long getNativeContentViewCore() {
876 return mNativeContentViewCore;
879 public void setContentViewClient(ContentViewClient client) {
880 if (client == null) {
881 throw new IllegalArgumentException("The client can't be null.");
883 mContentViewClient = client;
886 ContentViewClient getContentViewClient() {
887 if (mContentViewClient == null) {
888 // We use the Null Object pattern to avoid having to perform a null check in this class.
889 // We create it lazily because most of the time a client will be set almost immediately
890 // after ContentView is created.
891 mContentViewClient = new ContentViewClient();
892 // We don't set the native ContentViewClient pointer here on purpose. The native
893 // implementation doesn't mind a null delegate and using one is better than passing a
894 // Null Object, since we cut down on the number of JNI calls.
896 return mContentViewClient;
899 public int getBackgroundColor() {
900 if (mNativeContentViewCore != 0) {
901 return nativeGetBackgroundColor(mNativeContentViewCore);
907 private void onBackgroundColorChanged(int color) {
908 getContentViewClient().onBackgroundColorChanged(color);
912 * Load url without fixing up the url string. Consumers of ContentView are responsible for
913 * ensuring the URL passed in is properly formatted (i.e. the scheme has been added if left
914 * off during user input).
916 * @param params Parameters for this load.
918 public void loadUrl(LoadUrlParams params) {
919 if (mNativeContentViewCore == 0) return;
921 nativeLoadUrl(mNativeContentViewCore,
924 params.mTransitionType,
925 params.mUaOverrideOption,
926 params.getExtraHeadersString(),
928 params.mBaseUrlForDataUrl,
929 params.mVirtualUrlForDataUrl,
930 params.mCanLoadLocalResources);
934 * Stops loading the current web contents.
936 public void stopLoading() {
937 if (mNativeContentViewCore != 0) nativeStopLoading(mNativeContentViewCore);
941 * Get the URL of the current page.
943 * @return The URL of the current page.
945 public String getUrl() {
946 if (mNativeContentViewCore != 0) return nativeGetURL(mNativeContentViewCore);
951 * Get the title of the current page.
953 * @return The title of the current page.
955 public String getTitle() {
956 if (mNativeContentViewCore != 0) return nativeGetTitle(mNativeContentViewCore);
961 * Shows an interstitial page driven by the passed in delegate.
963 * @param url The URL being blocked by the interstitial.
964 * @param delegate The delegate handling the interstitial.
967 public void showInterstitialPage(
968 String url, InterstitialPageDelegateAndroid delegate) {
969 if (mNativeContentViewCore == 0) return;
970 nativeShowInterstitialPage(mNativeContentViewCore, url, delegate.getNative());
974 * @return Whether the page is currently showing an interstitial, such as a bad HTTPS page.
976 public boolean isShowingInterstitialPage() {
977 return mNativeContentViewCore == 0 ?
978 false : nativeIsShowingInterstitialPage(mNativeContentViewCore);
982 * Mark any new frames that have arrived since this function was last called as non-pending.
984 * @return Whether there was a pending frame from the renderer.
986 public boolean consumePendingRendererFrame() {
987 boolean hadPendingFrame = mPendingRendererFrame;
988 mPendingRendererFrame = false;
989 return hadPendingFrame;
993 * @return Viewport width in physical pixels as set from onSizeChanged.
996 public int getViewportWidthPix() { return mViewportWidthPix; }
999 * @return Viewport height in physical pixels as set from onSizeChanged.
1002 public int getViewportHeightPix() { return mViewportHeightPix; }
1005 * @return Width of underlying physical surface.
1008 public int getPhysicalBackingWidthPix() { return mPhysicalBackingWidthPix; }
1011 * @return Height of underlying physical surface.
1014 public int getPhysicalBackingHeightPix() { return mPhysicalBackingHeightPix; }
1017 * @return Amount the output surface extends past the bottom of the window viewport.
1020 public int getOverdrawBottomHeightPix() { return mOverdrawBottomHeightPix; }
1023 * @return The amount to shrink the viewport relative to {@link #getViewportWidthPix()}.
1026 public int getViewportSizeOffsetWidthPix() { return mViewportSizeOffsetWidthPix; }
1029 * @return The amount to shrink the viewport relative to {@link #getViewportHeightPix()}.
1032 public int getViewportSizeOffsetHeightPix() { return mViewportSizeOffsetHeightPix; }
1035 * @see android.webkit.WebView#getContentHeight()
1037 public float getContentHeightCss() {
1038 return mRenderCoordinates.getContentHeightCss();
1042 * @see android.webkit.WebView#getContentWidth()
1044 public float getContentWidthCss() {
1045 return mRenderCoordinates.getContentWidthCss();
1048 // TODO(teddchoc): Remove all these navigation controller methods from here and have the
1049 // embedders manage it.
1051 * @return Whether the current WebContents has a previous navigation entry.
1053 public boolean canGoBack() {
1054 return mWebContents != null && mWebContents.getNavigationController().canGoBack();
1058 * @return Whether the current WebContents has a navigation entry after the current one.
1060 public boolean canGoForward() {
1061 return mWebContents != null && mWebContents.getNavigationController().canGoForward();
1065 * @param offset The offset into the navigation history.
1066 * @return Whether we can move in history by given offset
1068 public boolean canGoToOffset(int offset) {
1069 return mWebContents != null &&
1070 mWebContents.getNavigationController().canGoToOffset(offset);
1074 * Navigates to the specified offset from the "current entry". Does nothing if the offset is out
1076 * @param offset The offset into the navigation history.
1078 public void goToOffset(int offset) {
1079 if (mWebContents != null) mWebContents.getNavigationController().goToOffset(offset);
1083 public void goToNavigationIndex(int index) {
1084 if (mWebContents != null) {
1085 mWebContents.getNavigationController().goToNavigationIndex(index);
1090 * Goes to the navigation entry before the current one.
1092 public void goBack() {
1093 if (mWebContents != null) mWebContents.getNavigationController().goBack();
1097 * Goes to the navigation entry following the current one.
1099 public void goForward() {
1100 if (mWebContents != null) mWebContents.getNavigationController().goForward();
1104 * Loads the current navigation if there is a pending lazy load (after tab restore).
1106 public void loadIfNecessary() {
1107 if (mNativeContentViewCore != 0) nativeLoadIfNecessary(mNativeContentViewCore);
1111 * Requests the current navigation to be loaded upon the next call to loadIfNecessary().
1113 public void requestRestoreLoad() {
1114 if (mNativeContentViewCore != 0) nativeRequestRestoreLoad(mNativeContentViewCore);
1118 * Reload the current page.
1120 public void reload(boolean checkForRepost) {
1121 mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary();
1122 if (mNativeContentViewCore != 0) {
1123 nativeReload(mNativeContentViewCore, checkForRepost);
1128 * Reload the current page, ignoring the contents of the cache.
1130 public void reloadIgnoringCache(boolean checkForRepost) {
1131 mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary();
1132 if (mNativeContentViewCore != 0) {
1133 nativeReloadIgnoringCache(mNativeContentViewCore, checkForRepost);
1138 * Cancel the pending reload.
1140 public void cancelPendingReload() {
1141 if (mNativeContentViewCore != 0) nativeCancelPendingReload(mNativeContentViewCore);
1145 * Continue the pending reload.
1147 public void continuePendingReload() {
1148 if (mNativeContentViewCore != 0) nativeContinuePendingReload(mNativeContentViewCore);
1152 * Clears the ContentViewCore's page history in both the backwards and
1153 * forwards directions.
1155 public void clearHistory() {
1156 if (mNativeContentViewCore != 0) nativeClearHistory(mNativeContentViewCore);
1160 * @return The selected text (empty if no text selected).
1162 public String getSelectedText() {
1163 return mHasSelection ? mLastSelectedText : "";
1167 * @return Whether the current selection is editable (false if no text selected).
1169 public boolean isSelectionEditable() {
1170 return mHasSelection ? mSelectionEditable : false;
1173 // End FrameLayout overrides.
1176 * @see View#onTouchEvent(MotionEvent)
1178 public boolean onTouchEvent(MotionEvent event) {
1179 cancelRequestToScrollFocusedEditableNodeIntoView();
1181 if (!mRequestedVSyncForInput) {
1182 mRequestedVSyncForInput = true;
1183 addVSyncSubscriber();
1186 final int eventAction = event.getActionMasked();
1188 // Only these actions have any effect on gesture detection. Other
1189 // actions have no corresponding WebTouchEvent type and may confuse the
1190 // touch pipline, so we ignore them entirely.
1191 if (eventAction != MotionEvent.ACTION_DOWN
1192 && eventAction != MotionEvent.ACTION_UP
1193 && eventAction != MotionEvent.ACTION_CANCEL
1194 && eventAction != MotionEvent.ACTION_MOVE
1195 && eventAction != MotionEvent.ACTION_POINTER_DOWN
1196 && eventAction != MotionEvent.ACTION_POINTER_UP) {
1200 if (mNativeContentViewCore == 0) return false;
1201 final int pointerCount = event.getPointerCount();
1202 return nativeOnTouchEvent(mNativeContentViewCore, event,
1203 event.getEventTime(), eventAction,
1204 pointerCount, event.getHistorySize(), event.getActionIndex(),
1205 event.getX(), event.getY(),
1206 pointerCount > 1 ? event.getX(1) : 0,
1207 pointerCount > 1 ? event.getY(1) : 0,
1208 event.getPointerId(0), pointerCount > 1 ? event.getPointerId(1) : -1,
1209 event.getTouchMajor(), pointerCount > 1 ? event.getTouchMajor(1) : 0);
1212 public void setIgnoreRemainingTouchEvents() {
1213 if (mNativeContentViewCore == 0) return;
1214 nativeIgnoreRemainingTouchEvents(mNativeContentViewCore);
1217 public boolean isScrollInProgress() {
1218 return mTouchScrollInProgress || mPotentiallyActiveFlingCount > 0;
1221 @SuppressWarnings("unused")
1223 private void onFlingStartEventConsumed(int vx, int vy) {
1224 mTouchScrollInProgress = false;
1225 mPotentiallyActiveFlingCount++;
1226 temporarilyHideTextHandles();
1227 for (mGestureStateListenersIterator.rewind();
1228 mGestureStateListenersIterator.hasNext();) {
1229 mGestureStateListenersIterator.next().onFlingStartGesture(
1230 vx, vy, computeVerticalScrollOffset(), computeVerticalScrollExtent());
1234 @SuppressWarnings("unused")
1236 private void onFlingStartEventHadNoConsumer(int vx, int vy) {
1237 mTouchScrollInProgress = false;
1238 for (mGestureStateListenersIterator.rewind();
1239 mGestureStateListenersIterator.hasNext();) {
1240 mGestureStateListenersIterator.next().onUnhandledFlingStartEvent(vx, vy);
1244 @SuppressWarnings("unused")
1246 private void onFlingCancelEventAck() {
1247 updateGestureStateListener(GestureEventType.FLING_CANCEL);
1250 @SuppressWarnings("unused")
1252 private void onScrollBeginEventAck() {
1253 mTouchScrollInProgress = true;
1254 temporarilyHideTextHandles();
1255 mZoomControlsDelegate.invokeZoomPicker();
1256 updateGestureStateListener(GestureEventType.SCROLL_START);
1259 @SuppressWarnings("unused")
1261 private void onScrollUpdateGestureConsumed() {
1262 mZoomControlsDelegate.invokeZoomPicker();
1263 for (mGestureStateListenersIterator.rewind();
1264 mGestureStateListenersIterator.hasNext();) {
1265 mGestureStateListenersIterator.next().onScrollUpdateGestureConsumed();
1269 @SuppressWarnings("unused")
1271 private void onScrollEndEventAck() {
1272 mTouchScrollInProgress = false;
1273 updateGestureStateListener(GestureEventType.SCROLL_END);
1276 @SuppressWarnings("unused")
1278 private void onPinchBeginEventAck() {
1279 temporarilyHideTextHandles();
1280 updateGestureStateListener(GestureEventType.PINCH_BEGIN);
1283 @SuppressWarnings("unused")
1285 private void onPinchEndEventAck() {
1286 updateGestureStateListener(GestureEventType.PINCH_END);
1289 @SuppressWarnings("unused")
1291 private void onDoubleTapEventAck() {
1292 temporarilyHideTextHandles();
1296 * Called just prior to a tap or press gesture being forwarded to the renderer.
1298 @SuppressWarnings("unused")
1300 private boolean filterTapOrPressEvent(int type, int x, int y) {
1301 if (type == GestureEventType.LONG_PRESS && offerLongPressToEmbedder()) {
1304 updateForTapOrPress(type, x, y);
1309 public void sendDoubleTapForTest(long timeMs, int x, int y) {
1310 if (mNativeContentViewCore == 0) return;
1311 nativeDoubleTap(mNativeContentViewCore, timeMs, x, y);
1315 public void flingForTest(long timeMs, int x, int y, int velocityX, int velocityY) {
1316 if (mNativeContentViewCore == 0) return;
1317 nativeFlingCancel(mNativeContentViewCore, timeMs);
1318 nativeScrollBegin(mNativeContentViewCore, timeMs, x, y, velocityX, velocityY);
1319 nativeFlingStart(mNativeContentViewCore, timeMs, x, y, velocityX, velocityY);
1323 * Add a listener that gets alerted on gesture state changes.
1324 * @param listener Listener to add.
1326 public void addGestureStateListener(GestureStateListener listener) {
1327 mGestureStateListeners.addObserver(listener);
1331 * Removes a listener that was added to watch for gesture state changes.
1332 * @param listener Listener to remove.
1334 public void removeGestureStateListener(GestureStateListener listener) {
1335 mGestureStateListeners.removeObserver(listener);
1338 void updateGestureStateListener(int gestureType) {
1339 for (mGestureStateListenersIterator.rewind();
1340 mGestureStateListenersIterator.hasNext();) {
1341 GestureStateListener listener = mGestureStateListenersIterator.next();
1342 switch (gestureType) {
1343 case GestureEventType.PINCH_BEGIN:
1344 listener.onPinchStarted();
1346 case GestureEventType.PINCH_END:
1347 listener.onPinchEnded();
1349 case GestureEventType.FLING_END:
1350 listener.onFlingEndGesture(
1351 computeVerticalScrollOffset(),
1352 computeVerticalScrollExtent());
1354 case GestureEventType.FLING_CANCEL:
1355 listener.onFlingCancelGesture();
1357 case GestureEventType.SCROLL_START:
1358 listener.onScrollStarted(
1359 computeVerticalScrollOffset(),
1360 computeVerticalScrollExtent());
1362 case GestureEventType.SCROLL_END:
1363 listener.onScrollEnded(
1364 computeVerticalScrollOffset(),
1365 computeVerticalScrollExtent());
1373 /** Callback interface for evaluateJavaScript(). */
1374 public interface JavaScriptCallback {
1375 void handleJavaScriptResult(String jsonResult);
1379 * Injects the passed Javascript code in the current page and evaluates it.
1380 * If a result is required, pass in a callback.
1381 * Used in automation tests.
1383 * @param script The Javascript to execute.
1384 * @param callback The callback to be fired off when a result is ready. The script's
1385 * result will be json encoded and passed as the parameter, and the call
1386 * will be made on the main thread.
1387 * If no result is required, pass null.
1389 public void evaluateJavaScript(String script, JavaScriptCallback callback) {
1390 if (mNativeContentViewCore == 0) return;
1391 nativeEvaluateJavaScript(mNativeContentViewCore, script, callback, false);
1395 * Injects the passed Javascript code in the current page and evaluates it.
1396 * If there is no page existing, a new one will be created.
1398 * @param script The Javascript to execute.
1400 public void evaluateJavaScriptEvenIfNotYetNavigated(String script) {
1401 if (mNativeContentViewCore == 0) return;
1402 nativeEvaluateJavaScript(mNativeContentViewCore, script, null, true);
1406 * To be called when the ContentView is shown.
1408 public void onShow() {
1409 assert mNativeContentViewCore != 0;
1410 if (!mInForeground) {
1411 ChildProcessLauncher.getBindingManager().setInForeground(getCurrentRenderProcessId(),
1414 mInForeground = true;
1415 nativeOnShow(mNativeContentViewCore);
1416 setAccessibilityState(mAccessibilityManager.isEnabled());
1420 * @return The ID of the renderer process that backs this tab or
1421 * {@link #INVALID_RENDER_PROCESS_PID} if there is none.
1423 public int getCurrentRenderProcessId() {
1424 return nativeGetCurrentRenderProcessId(mNativeContentViewCore);
1428 * To be called when the ContentView is hidden.
1430 public void onHide() {
1431 assert mNativeContentViewCore != 0;
1432 if (mInForeground) {
1433 ChildProcessLauncher.getBindingManager().setInForeground(getCurrentRenderProcessId(),
1436 mInForeground = false;
1438 setInjectedAccessibility(false);
1439 nativeOnHide(mNativeContentViewCore);
1443 * Return the ContentSettings object used to retrieve the settings for this
1444 * ContentViewCore. For modifications, ChromeNativePreferences is to be used.
1445 * @return A ContentSettings object that can be used to retrieve this
1446 * ContentViewCore's settings.
1448 public ContentSettings getContentSettings() {
1449 return mContentSettings;
1452 private void onRenderCoordinatesUpdated() {
1453 if (mNativeContentViewCore == 0) return;
1455 // We disable double tap zoom for pages that have a width=device-width
1456 // or narrower viewport (indicating that this is a mobile-optimized or
1457 // responsive web design, so text will be legible without zooming).
1458 // We also disable it for pages that disallow the user from zooming in
1459 // or out (even if they don't have a device-width or narrower viewport).
1460 nativeSetDoubleTapSupportForPageEnabled(mNativeContentViewCore,
1461 !mRenderCoordinates.hasMobileViewport() && !mRenderCoordinates.hasFixedPageScale());
1464 private void hidePopupDialog() {
1465 if (mSelectPopupDialog != null) {
1466 mSelectPopupDialog.hide();
1467 mSelectPopupDialog = null;
1470 hideSelectActionBar();
1473 void hideSelectActionBar() {
1474 if (mActionMode != null) {
1475 mActionMode.finish();
1480 public boolean isSelectActionBarShowing() {
1481 return mActionMode != null;
1484 private void resetGestureDetectors() {
1485 if (mNativeContentViewCore == 0) return;
1486 nativeResetGestureDetectors(mNativeContentViewCore);
1490 * @see View#onAttachedToWindow()
1492 @SuppressWarnings("javadoc")
1493 public void onAttachedToWindow() {
1494 setAccessibilityState(mAccessibilityManager.isEnabled());
1496 ScreenOrientationListener.getInstance().addObserver(this, mContext);
1500 * @see View#onDetachedFromWindow()
1502 @SuppressWarnings("javadoc")
1503 @SuppressLint("MissingSuperCall")
1504 public void onDetachedFromWindow() {
1505 setInjectedAccessibility(false);
1507 mZoomControlsDelegate.dismissZoomPicker();
1508 unregisterAccessibilityContentObserver();
1510 ScreenOrientationListener.getInstance().removeObserver(this);
1514 * @see View#onVisibilityChanged(android.view.View, int)
1516 public void onVisibilityChanged(View changedView, int visibility) {
1517 if (visibility != View.VISIBLE) {
1518 mZoomControlsDelegate.dismissZoomPicker();
1523 * @see View#onCreateInputConnection(EditorInfo)
1525 public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
1526 if (!mImeAdapter.hasTextInputType()) {
1527 // Although onCheckIsTextEditor will return false in this case, the EditorInfo
1528 // is still used by the InputMethodService. Need to make sure the IME doesn't
1529 // enter fullscreen mode.
1530 outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN;
1532 mInputConnection = mAdapterInputConnectionFactory.get(mContainerView, mImeAdapter,
1533 mEditable, outAttrs);
1534 return mInputConnection;
1538 public AdapterInputConnection getAdapterInputConnectionForTest() {
1539 return mInputConnection;
1543 public Editable getEditableForTest() {
1548 * @see View#onCheckIsTextEditor()
1550 public boolean onCheckIsTextEditor() {
1551 return mImeAdapter.hasTextInputType();
1555 * @see View#onConfigurationChanged(Configuration)
1557 @SuppressWarnings("javadoc")
1558 public void onConfigurationChanged(Configuration newConfig) {
1561 if (newConfig.keyboard != Configuration.KEYBOARD_NOKEYS) {
1562 mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore),
1563 ImeAdapter.getTextInputTypeNone());
1564 mInputMethodManagerWrapper.restartInput(mContainerView);
1566 mContainerViewInternals.super_onConfigurationChanged(newConfig);
1568 // To request layout has side effect, but it seems OK as it only happen in
1569 // onConfigurationChange and layout has to be changed in most case.
1570 mContainerView.requestLayout();
1575 * @see View#onSizeChanged(int, int, int, int)
1577 @SuppressWarnings("javadoc")
1578 public void onSizeChanged(int wPix, int hPix, int owPix, int ohPix) {
1579 if (getViewportWidthPix() == wPix && getViewportHeightPix() == hPix) return;
1581 mViewportWidthPix = wPix;
1582 mViewportHeightPix = hPix;
1583 if (mNativeContentViewCore != 0) {
1584 nativeWasResized(mNativeContentViewCore);
1587 updateAfterSizeChanged();
1591 * Called when the ContentView's position in the activity window changed. This information is
1592 * used for cropping screenshots.
1594 public void onLocationInWindowChanged(int x, int y) {
1595 mLocationInWindowX = x;
1596 mLocationInWindowY = y;
1600 * Called when the underlying surface the compositor draws to changes size.
1601 * This may be larger than the viewport size.
1603 public void onPhysicalBackingSizeChanged(int wPix, int hPix) {
1604 if (mPhysicalBackingWidthPix == wPix && mPhysicalBackingHeightPix == hPix) return;
1606 mPhysicalBackingWidthPix = wPix;
1607 mPhysicalBackingHeightPix = hPix;
1609 if (mNativeContentViewCore != 0) {
1610 nativeWasResized(mNativeContentViewCore);
1615 * Called when the amount the surface is overdrawing off the bottom has changed.
1616 * @param overdrawHeightPix The overdraw height.
1618 public void onOverdrawBottomHeightChanged(int overdrawHeightPix) {
1619 if (mOverdrawBottomHeightPix == overdrawHeightPix) return;
1621 mOverdrawBottomHeightPix = overdrawHeightPix;
1623 if (mNativeContentViewCore != 0) {
1624 nativeWasResized(mNativeContentViewCore);
1628 private void updateAfterSizeChanged() {
1629 mPopupZoomer.hide(false);
1631 // Execute a delayed form focus operation because the OSK was brought
1633 if (!mFocusPreOSKViewportRect.isEmpty()) {
1634 Rect rect = new Rect();
1635 getContainerView().getWindowVisibleDisplayFrame(rect);
1636 if (!rect.equals(mFocusPreOSKViewportRect)) {
1637 // Only assume the OSK triggered the onSizeChanged if width was preserved.
1638 if (rect.width() == mFocusPreOSKViewportRect.width()) {
1639 scrollFocusedEditableNodeIntoView();
1641 cancelRequestToScrollFocusedEditableNodeIntoView();
1646 private void cancelRequestToScrollFocusedEditableNodeIntoView() {
1647 // Zero-ing the rect will prevent |updateAfterSizeChanged()| from
1648 // issuing the delayed form focus event.
1649 mFocusPreOSKViewportRect.setEmpty();
1652 private void scrollFocusedEditableNodeIntoView() {
1653 if (mNativeContentViewCore == 0) return;
1654 // The native side keeps track of whether the zoom and scroll actually occurred. It is
1655 // more efficient to do it this way and sometimes fire an unnecessary message rather
1656 // than synchronize with the renderer and always have an additional message.
1657 nativeScrollFocusedEditableNodeIntoView(mNativeContentViewCore);
1661 * @see View#onWindowFocusChanged(boolean)
1663 public void onWindowFocusChanged(boolean hasWindowFocus) {
1664 if (!hasWindowFocus) {
1665 if (mNativeContentViewCore == 0) return;
1666 nativeOnWindowFocusLost(mNativeContentViewCore);
1670 public void onFocusChanged(boolean gainFocus) {
1674 if (mNativeContentViewCore != 0) nativeSetFocus(mNativeContentViewCore, gainFocus);
1678 * @see View#onKeyUp(int, KeyEvent)
1680 public boolean onKeyUp(int keyCode, KeyEvent event) {
1681 if (mPopupZoomer.isShowing() && keyCode == KeyEvent.KEYCODE_BACK) {
1682 mPopupZoomer.hide(true);
1685 return mContainerViewInternals.super_onKeyUp(keyCode, event);
1689 * @see View#dispatchKeyEventPreIme(KeyEvent)
1691 public boolean dispatchKeyEventPreIme(KeyEvent event) {
1694 return mContainerViewInternals.super_dispatchKeyEventPreIme(event);
1701 * @see View#dispatchKeyEvent(KeyEvent)
1703 public boolean dispatchKeyEvent(KeyEvent event) {
1704 if (getContentViewClient().shouldOverrideKeyEvent(event)) {
1705 return mContainerViewInternals.super_dispatchKeyEvent(event);
1708 if (mImeAdapter.dispatchKeyEvent(event)) return true;
1710 return mContainerViewInternals.super_dispatchKeyEvent(event);
1714 * @see View#onHoverEvent(MotionEvent)
1715 * Mouse move events are sent on hover enter, hover move and hover exit.
1716 * They are sent on hover exit because sometimes it acts as both a hover
1717 * move and hover exit.
1719 public boolean onHoverEvent(MotionEvent event) {
1720 TraceEvent.begin("onHoverEvent");
1722 if (mBrowserAccessibilityManager != null) {
1723 return mBrowserAccessibilityManager.onHoverEvent(event);
1726 // Work around Android bug where the x, y coordinates of a hover exit
1727 // event are incorrect when touch exploration is on.
1728 if (mTouchExplorationEnabled && event.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
1732 mContainerView.removeCallbacks(mFakeMouseMoveRunnable);
1733 if (mNativeContentViewCore != 0) {
1734 nativeSendMouseMoveEvent(mNativeContentViewCore, event.getEventTime(),
1735 event.getX(), event.getY());
1737 TraceEvent.end("onHoverEvent");
1742 * @see View#onGenericMotionEvent(MotionEvent)
1744 public boolean onGenericMotionEvent(MotionEvent event) {
1745 if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
1746 switch (event.getAction()) {
1747 case MotionEvent.ACTION_SCROLL:
1748 nativeSendMouseWheelEvent(mNativeContentViewCore, event.getEventTime(),
1749 event.getX(), event.getY(),
1750 event.getAxisValue(MotionEvent.AXIS_VSCROLL));
1752 mContainerView.removeCallbacks(mFakeMouseMoveRunnable);
1753 // Send a delayed onMouseMove event so that we end
1754 // up hovering over the right position after the scroll.
1755 final MotionEvent eventFakeMouseMove = MotionEvent.obtain(event);
1756 mFakeMouseMoveRunnable = new Runnable() {
1759 onHoverEvent(eventFakeMouseMove);
1762 mContainerView.postDelayed(mFakeMouseMoveRunnable, 250);
1766 return mContainerViewInternals.super_onGenericMotionEvent(event);
1770 * @see View#scrollBy(int, int)
1771 * Currently the ContentView scrolling happens in the native side. In
1772 * the Java view system, it is always pinned at (0, 0). scrollBy() and scrollTo()
1773 * are overridden, so that View's mScrollX and mScrollY will be unchanged at
1774 * (0, 0). This is critical for drawing ContentView correctly.
1776 public void scrollBy(int xPix, int yPix) {
1777 if (mNativeContentViewCore != 0) {
1778 nativeScrollBy(mNativeContentViewCore,
1779 SystemClock.uptimeMillis(), 0, 0, xPix, yPix);
1784 * @see View#scrollTo(int, int)
1786 public void scrollTo(int xPix, int yPix) {
1787 if (mNativeContentViewCore == 0) return;
1788 final float xCurrentPix = mRenderCoordinates.getScrollXPix();
1789 final float yCurrentPix = mRenderCoordinates.getScrollYPix();
1790 final float dxPix = xPix - xCurrentPix;
1791 final float dyPix = yPix - yCurrentPix;
1792 if (dxPix != 0 || dyPix != 0) {
1793 long time = SystemClock.uptimeMillis();
1794 nativeScrollBegin(mNativeContentViewCore, time,
1795 xCurrentPix, yCurrentPix, -dxPix, -dyPix);
1796 nativeScrollBy(mNativeContentViewCore,
1797 time, xCurrentPix, yCurrentPix, dxPix, dyPix);
1798 nativeScrollEnd(mNativeContentViewCore, time);
1802 // NOTE: this can go away once ContentView.getScrollX() reports correct values.
1804 public int getNativeScrollXForTest() {
1805 return mRenderCoordinates.getScrollXPixInt();
1808 // NOTE: this can go away once ContentView.getScrollY() reports correct values.
1810 public int getNativeScrollYForTest() {
1811 return mRenderCoordinates.getScrollYPixInt();
1815 * @see View#computeHorizontalScrollExtent()
1817 @SuppressWarnings("javadoc")
1818 public int computeHorizontalScrollExtent() {
1819 return mRenderCoordinates.getLastFrameViewportWidthPixInt();
1823 * @see View#computeHorizontalScrollOffset()
1825 @SuppressWarnings("javadoc")
1826 public int computeHorizontalScrollOffset() {
1827 return mRenderCoordinates.getScrollXPixInt();
1831 * @see View#computeHorizontalScrollRange()
1833 @SuppressWarnings("javadoc")
1834 public int computeHorizontalScrollRange() {
1835 return mRenderCoordinates.getContentWidthPixInt();
1839 * @see View#computeVerticalScrollExtent()
1841 @SuppressWarnings("javadoc")
1842 public int computeVerticalScrollExtent() {
1843 return mRenderCoordinates.getLastFrameViewportHeightPixInt();
1847 * @see View#computeVerticalScrollOffset()
1849 @SuppressWarnings("javadoc")
1850 public int computeVerticalScrollOffset() {
1851 return mRenderCoordinates.getScrollYPixInt();
1855 * @see View#computeVerticalScrollRange()
1857 @SuppressWarnings("javadoc")
1858 public int computeVerticalScrollRange() {
1859 return mRenderCoordinates.getContentHeightPixInt();
1862 // End FrameLayout overrides.
1865 * @see View#awakenScrollBars(int, boolean)
1867 @SuppressWarnings("javadoc")
1868 public boolean awakenScrollBars(int startDelay, boolean invalidate) {
1869 // For the default implementation of ContentView which draws the scrollBars on the native
1870 // side, calling this function may get us into a bad state where we keep drawing the
1871 // scrollBars, so disable it by always returning false.
1872 if (mContainerView.getScrollBarStyle() == View.SCROLLBARS_INSIDE_OVERLAY) {
1875 return mContainerViewInternals.super_awakenScrollBars(startDelay, invalidate);
1879 private void updateForTapOrPress(int type, float xPix, float yPix) {
1880 if (type != GestureEventType.SINGLE_TAP_CONFIRMED
1881 && type != GestureEventType.SINGLE_TAP_UP
1882 && type != GestureEventType.LONG_PRESS
1883 && type != GestureEventType.LONG_TAP) {
1887 if (mContainerView.isFocusable() && mContainerView.isFocusableInTouchMode()
1888 && !mContainerView.isFocused()) {
1889 mContainerView.requestFocus();
1892 if (!mPopupZoomer.isShowing()) mPopupZoomer.setLastTouch(xPix, yPix);
1894 if (type == GestureEventType.LONG_PRESS
1895 || type == GestureEventType.LONG_TAP) {
1896 getInsertionHandleController().allowAutomaticShowing();
1897 getSelectionHandleController().allowAutomaticShowing();
1899 setClickXAndY((int) xPix, (int) yPix);
1900 if (mSelectionEditable) getInsertionHandleController().allowAutomaticShowing();
1904 private void setClickXAndY(int x, int y) {
1910 * @return The x coordinate for the last point that a singleTap gesture was initiated from.
1912 public int getSingleTapX() {
1917 * @return The y coordinate for the last point that a singleTap gesture was initiated from.
1919 public int getSingleTapY() {
1923 public void setZoomControlsDelegate(ZoomControlsDelegate zoomControlsDelegate) {
1924 mZoomControlsDelegate = zoomControlsDelegate;
1927 public void updateMultiTouchZoomSupport(boolean supportsMultiTouchZoom) {
1928 if (mNativeContentViewCore == 0) return;
1929 nativeSetMultiTouchZoomSupportEnabled(mNativeContentViewCore, supportsMultiTouchZoom);
1932 public void updateDoubleTapSupport(boolean supportsDoubleTap) {
1933 if (mNativeContentViewCore == 0) return;
1934 nativeSetDoubleTapSupportEnabled(mNativeContentViewCore, supportsDoubleTap);
1937 public void selectPopupMenuItems(int[] indices) {
1938 if (mNativeContentViewCore != 0) {
1939 nativeSelectPopupMenuItems(mNativeContentViewCore, indices);
1941 mSelectPopupDialog = null;
1945 * Send the screen orientation value to the renderer.
1948 void sendOrientationChangeEvent(int orientation) {
1949 if (mNativeContentViewCore == 0) return;
1951 nativeSendOrientationChangeEvent(mNativeContentViewCore, orientation);
1955 * Register the delegate to be used when content can not be handled by
1956 * the rendering engine, and should be downloaded instead. This will replace
1957 * the current delegate, if any.
1958 * @param delegate An implementation of ContentViewDownloadDelegate.
1960 public void setDownloadDelegate(ContentViewDownloadDelegate delegate) {
1961 mDownloadDelegate = delegate;
1964 // Called by DownloadController.
1965 ContentViewDownloadDelegate getDownloadDelegate() {
1966 return mDownloadDelegate;
1969 private SelectionHandleController getSelectionHandleController() {
1970 if (mSelectionHandleController == null) {
1971 mSelectionHandleController = new SelectionHandleController(
1972 getContainerView(), mPositionObserver) {
1974 public void selectBetweenCoordinates(int x1, int y1, int x2, int y2) {
1975 if (mNativeContentViewCore != 0 && !(x1 == x2 && y1 == y2)) {
1976 nativeSelectBetweenCoordinates(mNativeContentViewCore,
1977 x1, y1 - mRenderCoordinates.getContentOffsetYPix(),
1978 x2, y2 - mRenderCoordinates.getContentOffsetYPix());
1983 public void showHandles(int startDir, int endDir) {
1984 super.showHandles(startDir, endDir);
1985 showSelectActionBar();
1990 mSelectionHandleController.hideAndDisallowAutomaticShowing();
1991 updateInsertionSelectionVisibleBounds();
1994 return mSelectionHandleController;
1997 private InsertionHandleController getInsertionHandleController() {
1998 if (mInsertionHandleController == null) {
1999 mInsertionHandleController = new InsertionHandleController(
2000 getContainerView(), mPositionObserver) {
2001 private static final int AVERAGE_LINE_HEIGHT = 14;
2004 public void setCursorPosition(int x, int y) {
2005 if (mNativeContentViewCore != 0) {
2006 nativeMoveCaret(mNativeContentViewCore,
2007 x, y - mRenderCoordinates.getContentOffsetYPix());
2012 public void paste() {
2013 mImeAdapter.paste();
2018 public int getLineHeight() {
2019 return (int) Math.ceil(
2020 mRenderCoordinates.fromLocalCssToPix(AVERAGE_LINE_HEIGHT));
2024 public void showHandle() {
2029 mInsertionHandleController.hideAndDisallowAutomaticShowing();
2030 updateInsertionSelectionVisibleBounds();
2033 return mInsertionHandleController;
2037 public InsertionHandleController getInsertionHandleControllerForTest() {
2038 return mInsertionHandleController;
2042 public SelectionHandleController getSelectionHandleControllerForTest() {
2043 return mSelectionHandleController;
2046 private void updateHandleScreenPositions() {
2047 if (isSelectionHandleShowing()) {
2048 mSelectionHandleController.setStartHandlePosition(
2049 mStartHandlePoint.getXPix(), mStartHandlePoint.getYPix());
2050 mSelectionHandleController.setEndHandlePosition(
2051 mEndHandlePoint.getXPix(), mEndHandlePoint.getYPix());
2054 if (isInsertionHandleShowing()) {
2055 mInsertionHandleController.setHandlePosition(
2056 mInsertionHandlePoint.getXPix(), mInsertionHandlePoint.getYPix());
2060 private void hideHandles() {
2061 if (mSelectionHandleController != null) {
2062 mSelectionHandleController.hideAndDisallowAutomaticShowing();
2064 if (mInsertionHandleController != null) {
2065 mInsertionHandleController.hideAndDisallowAutomaticShowing();
2067 mPositionObserver.removeListener(mPositionListener);
2070 private void showSelectActionBar() {
2071 if (mActionMode != null) {
2072 mActionMode.invalidate();
2076 // Start a new action mode with a SelectActionModeCallback.
2077 SelectActionModeCallback.ActionHandler actionHandler =
2078 new SelectActionModeCallback.ActionHandler() {
2080 public void selectAll() {
2081 mImeAdapter.selectAll();
2090 public void copy() {
2095 public void paste() {
2096 mImeAdapter.paste();
2100 public void share() {
2101 final String query = getSelectedText();
2102 if (TextUtils.isEmpty(query)) return;
2104 Intent send = new Intent(Intent.ACTION_SEND);
2105 send.setType("text/plain");
2106 send.putExtra(Intent.EXTRA_TEXT, query);
2108 Intent i = Intent.createChooser(send, getContext().getString(
2109 R.string.actionbar_share));
2110 i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2111 getContext().startActivity(i);
2112 } catch (android.content.ActivityNotFoundException ex) {
2113 // If no app handles it, do nothing.
2118 public void search() {
2119 final String query = getSelectedText();
2120 if (TextUtils.isEmpty(query)) return;
2122 // See if ContentViewClient wants to override
2123 if (getContentViewClient().doesPerformWebSearch()) {
2124 getContentViewClient().performWebSearch(query);
2128 Intent i = new Intent(Intent.ACTION_WEB_SEARCH);
2129 i.putExtra(SearchManager.EXTRA_NEW_SEARCH, true);
2130 i.putExtra(SearchManager.QUERY, query);
2131 i.putExtra(Browser.EXTRA_APPLICATION_ID, getContext().getPackageName());
2132 if (!(getContext() instanceof Activity)) {
2133 i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2136 getContext().startActivity(i);
2137 } catch (android.content.ActivityNotFoundException ex) {
2138 // If no app handles it, do nothing.
2143 public boolean isSelectionEditable() {
2144 return mSelectionEditable;
2148 public void onDestroyActionMode() {
2150 if (mUnselectAllOnActionModeDismiss) mImeAdapter.unselect();
2151 getContentViewClient().onContextualActionBarHidden();
2155 public boolean isShareAvailable() {
2156 Intent intent = new Intent(Intent.ACTION_SEND);
2157 intent.setType("text/plain");
2158 return getContext().getPackageManager().queryIntentActivities(intent,
2159 PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
2163 public boolean isWebSearchAvailable() {
2164 if (getContentViewClient().doesPerformWebSearch()) return true;
2165 Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
2166 intent.putExtra(SearchManager.EXTRA_NEW_SEARCH, true);
2167 return getContext().getPackageManager().queryIntentActivities(intent,
2168 PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
2172 // On ICS, startActionMode throws an NPE when getParent() is null.
2173 if (mContainerView.getParent() != null) {
2174 mActionMode = mContainerView.startActionMode(
2175 getContentViewClient().getSelectActionModeCallback(getContext(), actionHandler,
2176 nativeIsIncognito(mNativeContentViewCore)));
2178 mUnselectAllOnActionModeDismiss = true;
2179 if (mActionMode == null) {
2180 // There is no ActionMode, so remove the selection.
2181 mImeAdapter.unselect();
2183 getContentViewClient().onContextualActionBarShown();
2187 public boolean getUseDesktopUserAgent() {
2188 if (mNativeContentViewCore != 0) {
2189 return nativeGetUseDesktopUserAgent(mNativeContentViewCore);
2195 * Set whether or not we're using a desktop user agent for the currently loaded page.
2196 * @param override If true, use a desktop user agent. Use a mobile one otherwise.
2197 * @param reloadOnChange Reload the page if the UA has changed.
2199 public void setUseDesktopUserAgent(boolean override, boolean reloadOnChange) {
2200 if (mNativeContentViewCore != 0) {
2201 nativeSetUseDesktopUserAgent(mNativeContentViewCore, override, reloadOnChange);
2205 public void clearSslPreferences() {
2206 nativeClearSslPreferences(mNativeContentViewCore);
2209 private boolean isSelectionHandleShowing() {
2210 return mSelectionHandleController != null && mSelectionHandleController.isShowing();
2213 private boolean isInsertionHandleShowing() {
2214 return mInsertionHandleController != null && mInsertionHandleController.isShowing();
2217 // Makes the insertion/selection handles invisible. They will fade back in shortly after the
2218 // last call to scheduleTextHandleFadeIn (or temporarilyHideTextHandles).
2219 private void temporarilyHideTextHandles() {
2220 if (isSelectionHandleShowing() && !mSelectionHandleController.isDragging()) {
2221 mSelectionHandleController.setHandleVisibility(HandleView.INVISIBLE);
2223 if (isInsertionHandleShowing() && !mInsertionHandleController.isDragging()) {
2224 mInsertionHandleController.setHandleVisibility(HandleView.INVISIBLE);
2226 scheduleTextHandleFadeIn();
2229 private boolean allowTextHandleFadeIn() {
2230 if (mTouchScrollInProgress) return false;
2232 if (mPopupZoomer.isShowing()) return false;
2237 // Cancels any pending fade in and schedules a new one.
2238 private void scheduleTextHandleFadeIn() {
2239 if (!isInsertionHandleShowing() && !isSelectionHandleShowing()) return;
2241 if (mDeferredHandleFadeInRunnable == null) {
2242 mDeferredHandleFadeInRunnable = new Runnable() {
2245 if (!allowTextHandleFadeIn()) {
2246 // Delay fade in until it is allowed.
2247 scheduleTextHandleFadeIn();
2249 if (isSelectionHandleShowing()) {
2250 mSelectionHandleController.beginHandleFadeIn();
2252 if (isInsertionHandleShowing()) {
2253 mInsertionHandleController.beginHandleFadeIn();
2260 mContainerView.removeCallbacks(mDeferredHandleFadeInRunnable);
2261 mContainerView.postDelayed(mDeferredHandleFadeInRunnable, TEXT_HANDLE_FADE_IN_DELAY);
2265 * Shows the IME if the focused widget could accept text input.
2267 public void showImeIfNeeded() {
2268 if (mNativeContentViewCore != 0) nativeShowImeIfNeeded(mNativeContentViewCore);
2272 * Hides the IME if the containerView is the active view for IME.
2274 public void hideImeIfNeeded() {
2275 // Hide input method window from the current view synchronously
2276 // because ImeAdapter does so asynchronouly with a delay, and
2277 // by the time when ImeAdapter dismisses the input, the
2278 // containerView may have lost focus.
2279 // We cannot trust ContentViewClient#onImeStateChangeRequested to
2280 // hide the input window because it has an empty default implementation.
2281 // So we need to explicitly hide the input method window here.
2282 if (mInputMethodManagerWrapper.isActive(mContainerView)) {
2283 mInputMethodManagerWrapper.hideSoftInputFromWindow(
2284 mContainerView.getWindowToken(), 0, null);
2286 getContentViewClient().onImeStateChangeRequested(false);
2289 @SuppressWarnings("unused")
2291 private void updateFrameInfo(
2292 float scrollOffsetX, float scrollOffsetY,
2293 float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor,
2294 float contentWidth, float contentHeight,
2295 float viewportWidth, float viewportHeight,
2296 float controlsOffsetYCss, float contentOffsetYCss,
2297 float overdrawBottomHeightCss) {
2298 TraceEvent.instant("ContentViewCore:updateFrameInfo");
2299 // Adjust contentWidth/Height to be always at least as big as
2300 // the actual viewport (as set by onSizeChanged).
2301 contentWidth = Math.max(contentWidth,
2302 mRenderCoordinates.fromPixToLocalCss(mViewportWidthPix));
2303 contentHeight = Math.max(contentHeight,
2304 mRenderCoordinates.fromPixToLocalCss(mViewportHeightPix));
2306 final float contentOffsetYPix = mRenderCoordinates.fromDipToPix(contentOffsetYCss);
2308 final boolean contentSizeChanged =
2309 contentWidth != mRenderCoordinates.getContentWidthCss()
2310 || contentHeight != mRenderCoordinates.getContentHeightCss();
2311 final boolean scaleLimitsChanged =
2312 minPageScaleFactor != mRenderCoordinates.getMinPageScaleFactor()
2313 || maxPageScaleFactor != mRenderCoordinates.getMaxPageScaleFactor();
2314 final boolean pageScaleChanged =
2315 pageScaleFactor != mRenderCoordinates.getPageScaleFactor();
2316 final boolean scrollChanged =
2318 || scrollOffsetX != mRenderCoordinates.getScrollX()
2319 || scrollOffsetY != mRenderCoordinates.getScrollY();
2320 final boolean contentOffsetChanged =
2321 contentOffsetYPix != mRenderCoordinates.getContentOffsetYPix();
2323 final boolean needHidePopupZoomer = contentSizeChanged || scrollChanged;
2324 final boolean needUpdateZoomControls = scaleLimitsChanged || scrollChanged;
2325 final boolean needTemporarilyHideHandles = scrollChanged;
2327 if (needHidePopupZoomer) mPopupZoomer.hide(true);
2329 if (scrollChanged) {
2330 mContainerViewInternals.onScrollChanged(
2331 (int) mRenderCoordinates.fromLocalCssToPix(scrollOffsetX),
2332 (int) mRenderCoordinates.fromLocalCssToPix(scrollOffsetY),
2333 (int) mRenderCoordinates.getScrollXPix(),
2334 (int) mRenderCoordinates.getScrollYPix());
2337 mRenderCoordinates.updateFrameInfo(
2338 scrollOffsetX, scrollOffsetY,
2339 contentWidth, contentHeight,
2340 viewportWidth, viewportHeight,
2341 pageScaleFactor, minPageScaleFactor, maxPageScaleFactor,
2343 onRenderCoordinatesUpdated();
2345 if (scrollChanged || contentOffsetChanged) {
2346 for (mGestureStateListenersIterator.rewind();
2347 mGestureStateListenersIterator.hasNext();) {
2348 mGestureStateListenersIterator.next().onScrollOffsetOrExtentChanged(
2349 computeVerticalScrollOffset(),
2350 computeVerticalScrollExtent());
2354 if (needTemporarilyHideHandles) temporarilyHideTextHandles();
2355 if (needUpdateZoomControls) mZoomControlsDelegate.updateZoomControls();
2356 if (contentOffsetChanged) updateHandleScreenPositions();
2358 // Update offsets for fullscreen.
2359 final float deviceScale = mRenderCoordinates.getDeviceScaleFactor();
2360 final float controlsOffsetPix = controlsOffsetYCss * deviceScale;
2361 final float overdrawBottomHeightPix = overdrawBottomHeightCss * deviceScale;
2362 getContentViewClient().onOffsetsForFullscreenChanged(
2363 controlsOffsetPix, contentOffsetYPix, overdrawBottomHeightPix);
2365 mPendingRendererFrame = true;
2366 if (mBrowserAccessibilityManager != null) {
2367 mBrowserAccessibilityManager.notifyFrameInfoInitialized();
2372 private void updateImeAdapter(long nativeImeAdapterAndroid, int textInputType,
2373 String text, int selectionStart, int selectionEnd,
2374 int compositionStart, int compositionEnd, boolean showImeIfNeeded, boolean requireAck) {
2376 mSelectionEditable = (textInputType != ImeAdapter.getTextInputTypeNone());
2378 if (mActionMode != null) mActionMode.invalidate();
2380 mImeAdapter.attachAndShowIfNeeded(nativeImeAdapterAndroid, textInputType, showImeIfNeeded);
2382 if (mInputConnection != null) {
2383 mInputConnection.updateState(text, selectionStart, selectionEnd, compositionStart,
2384 compositionEnd, requireAck);
2389 @SuppressWarnings("unused")
2391 private void setTitle(String title) {
2392 getContentViewClient().onUpdateTitle(title);
2396 * Called (from native) when the <select> popup needs to be shown.
2397 * @param items Items to show.
2398 * @param enabled POPUP_ITEM_TYPEs for items.
2399 * @param multiple Whether the popup menu should support multi-select.
2400 * @param selectedIndices Indices of selected items.
2402 @SuppressWarnings("unused")
2404 private void showSelectPopup(String[] items, int[] enabled, boolean multiple,
2405 int[] selectedIndices) {
2406 if (mContainerView.getParent() == null || mContainerView.getVisibility() != View.VISIBLE) {
2407 selectPopupMenuItems(null);
2411 if (mSelectPopupDialog != null) {
2412 mSelectPopupDialog.hide();
2413 mSelectPopupDialog = null;
2415 assert items.length == enabled.length;
2416 List<SelectPopupItem> popupItems = new ArrayList<SelectPopupItem>();
2417 for (int i = 0; i < items.length; i++) {
2418 popupItems.add(new SelectPopupItem(items[i], enabled[i]));
2420 mSelectPopupDialog = SelectPopupDialog.show(this, popupItems, multiple, selectedIndices);
2424 * @return The visible select popup dialog being shown.
2426 public SelectPopupDialog getSelectPopupForTest() {
2427 return mSelectPopupDialog;
2430 @SuppressWarnings("unused")
2432 private void showDisambiguationPopup(Rect targetRect, Bitmap zoomedBitmap) {
2433 mPopupZoomer.setBitmap(zoomedBitmap);
2434 mPopupZoomer.show(targetRect);
2435 temporarilyHideTextHandles();
2438 @SuppressWarnings("unused")
2440 private TouchEventSynthesizer createTouchEventSynthesizer() {
2441 return new TouchEventSynthesizer(this);
2444 @SuppressWarnings("unused")
2446 private void onSelectionChanged(String text) {
2447 mLastSelectedText = text;
2448 getContentViewClient().onSelectionChanged(text);
2451 @SuppressWarnings("unused")
2453 private void onSelectionBoundsChanged(Rect anchorRectDip, int anchorDir, Rect focusRectDip,
2454 int focusDir, boolean isAnchorFirst) {
2455 // All coordinates are in DIP.
2456 int x1 = anchorRectDip.left;
2457 int y1 = anchorRectDip.bottom;
2458 int x2 = focusRectDip.left;
2459 int y2 = focusRectDip.bottom;
2461 if (x1 != x2 || y1 != y2 ||
2462 (mSelectionHandleController != null && mSelectionHandleController.isDragging())) {
2463 if (mInsertionHandleController != null) {
2464 mInsertionHandleController.hide();
2466 if (isAnchorFirst) {
2467 mStartHandlePoint.setLocalDip(x1, y1);
2468 mEndHandlePoint.setLocalDip(x2, y2);
2470 mStartHandlePoint.setLocalDip(x2, y2);
2471 mEndHandlePoint.setLocalDip(x1, y1);
2474 boolean wereSelectionHandlesShowing = getSelectionHandleController().isShowing();
2476 getSelectionHandleController().onSelectionChanged(anchorDir, focusDir);
2477 updateHandleScreenPositions();
2478 mHasSelection = true;
2480 if (!wereSelectionHandlesShowing && getSelectionHandleController().isShowing()) {
2481 // TODO(cjhopman): Remove this when there is a better signal that long press caused
2482 // a selection. See http://crbug.com/150151.
2483 mContainerView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
2487 mUnselectAllOnActionModeDismiss = false;
2488 hideSelectActionBar();
2489 if (x1 != 0 && y1 != 0 && mSelectionEditable) {
2490 // Selection is a caret, and a text field is focused.
2491 if (mSelectionHandleController != null) {
2492 mSelectionHandleController.hide();
2494 mInsertionHandlePoint.setLocalDip(x1, y1);
2496 getInsertionHandleController().onCursorPositionChanged();
2497 updateHandleScreenPositions();
2498 if (mInputMethodManagerWrapper.isWatchingCursor(mContainerView)) {
2499 final int xPix = (int) mInsertionHandlePoint.getXPix();
2500 final int yPix = (int) mInsertionHandlePoint.getYPix();
2501 mInputMethodManagerWrapper.updateCursor(
2502 mContainerView, xPix, yPix, xPix, yPix);
2506 if (mSelectionHandleController != null) {
2507 mSelectionHandleController.hideAndDisallowAutomaticShowing();
2509 if (mInsertionHandleController != null) {
2510 mInsertionHandleController.hideAndDisallowAutomaticShowing();
2513 mHasSelection = false;
2515 if (isSelectionHandleShowing() || isInsertionHandleShowing()) {
2516 mPositionObserver.addListener(mPositionListener);
2521 private void setSelectionRootBounds(Rect bounds) {
2522 mTopLeftVisibilityClippingPoint.setLocalDip(bounds.left, bounds.top);
2523 mBottomRightVisibilityClippingPoint.setLocalDip(bounds.right, bounds.bottom);
2524 updateInsertionSelectionVisibleBounds();
2527 private void updateInsertionSelectionVisibleBounds() {
2528 if (mSelectionHandleController == null && mInsertionHandleController == null) {
2532 int x1 = Math.round(mTopLeftVisibilityClippingPoint.getXPix());
2533 int y1 = Math.round(mTopLeftVisibilityClippingPoint.getYPix());
2534 int x2 = Math.round(mBottomRightVisibilityClippingPoint.getXPix());
2535 int y2 = Math.round(mBottomRightVisibilityClippingPoint.getYPix());
2537 if (mSelectionHandleController != null) {
2538 mSelectionHandleController.setVisibleClippingRectangle(x1, y1, x2, y2);
2541 if (mInsertionHandleController != null) {
2542 mInsertionHandleController.setVisibleClippingRectangle(x1, y1, x2, y2);
2546 @SuppressWarnings("unused")
2548 private static void onEvaluateJavaScriptResult(
2549 String jsonResult, JavaScriptCallback callback) {
2550 callback.handleJavaScriptResult(jsonResult);
2553 @SuppressWarnings("unused")
2555 private void showPastePopup(int xDip, int yDip) {
2556 mInsertionHandlePoint.setLocalDip(xDip, yDip);
2557 getInsertionHandleController().showHandle();
2558 updateHandleScreenPositions();
2559 getInsertionHandleController().showHandleWithPastePopup();
2562 @SuppressWarnings("unused")
2564 private void onRenderProcessSwap(int oldPid, int newPid) {
2565 if (!mInForeground) {
2566 ChildProcessLauncher.getBindingManager().setInForeground(newPid, false);
2567 } else if (oldPid != newPid) {
2568 ChildProcessLauncher.getBindingManager().setInForeground(oldPid, false);
2569 ChildProcessLauncher.getBindingManager().setInForeground(newPid, true);
2575 @SuppressWarnings("unused")
2577 private void onWebContentsConnected() {
2582 * Attaches the native ImeAdapter object to the java ImeAdapter to allow communication via JNI.
2584 public void attachImeAdapter() {
2585 if (mImeAdapter != null && mNativeContentViewCore != 0) {
2586 mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore));
2591 * @see View#hasFocus()
2594 public boolean hasFocus() {
2595 return mContainerView.hasFocus();
2599 * Checks whether the ContentViewCore can be zoomed in.
2601 * @return True if the ContentViewCore can be zoomed in.
2603 // This method uses the term 'zoom' for legacy reasons, but relates
2604 // to what chrome calls the 'page scale factor'.
2605 public boolean canZoomIn() {
2606 final float zoomInExtent = mRenderCoordinates.getMaxPageScaleFactor()
2607 - mRenderCoordinates.getPageScaleFactor();
2608 return zoomInExtent > ZOOM_CONTROLS_EPSILON;
2612 * Checks whether the ContentViewCore can be zoomed out.
2614 * @return True if the ContentViewCore can be zoomed out.
2616 // This method uses the term 'zoom' for legacy reasons, but relates
2617 // to what chrome calls the 'page scale factor'.
2618 public boolean canZoomOut() {
2619 final float zoomOutExtent = mRenderCoordinates.getPageScaleFactor()
2620 - mRenderCoordinates.getMinPageScaleFactor();
2621 return zoomOutExtent > ZOOM_CONTROLS_EPSILON;
2625 * Zooms in the ContentViewCore by 25% (or less if that would result in
2626 * zooming in more than possible).
2628 * @return True if there was a zoom change, false otherwise.
2630 // This method uses the term 'zoom' for legacy reasons, but relates
2631 // to what chrome calls the 'page scale factor'.
2632 public boolean zoomIn() {
2636 return pinchByDelta(1.25f);
2640 * Zooms out the ContentViewCore by 20% (or less if that would result in
2641 * zooming out more than possible).
2643 * @return True if there was a zoom change, false otherwise.
2645 // This method uses the term 'zoom' for legacy reasons, but relates
2646 // to what chrome calls the 'page scale factor'.
2647 public boolean zoomOut() {
2648 if (!canZoomOut()) {
2651 return pinchByDelta(0.8f);
2655 * Resets the zoom factor of the ContentViewCore.
2657 * @return True if there was a zoom change, false otherwise.
2659 // This method uses the term 'zoom' for legacy reasons, but relates
2660 // to what chrome calls the 'page scale factor'.
2661 public boolean zoomReset() {
2662 // The page scale factor is initialized to mNativeMinimumScale when
2663 // the page finishes loading. Thus sets it back to mNativeMinimumScale.
2664 if (!canZoomOut()) return false;
2665 return pinchByDelta(
2666 mRenderCoordinates.getMinPageScaleFactor()
2667 / mRenderCoordinates.getPageScaleFactor());
2671 * Simulate a pinch zoom gesture.
2673 * @param delta the factor by which the current page scale should be multiplied by.
2674 * @return whether the gesture was sent.
2676 public boolean pinchByDelta(float delta) {
2677 if (mNativeContentViewCore == 0) return false;
2679 long timeMs = SystemClock.uptimeMillis();
2680 int xPix = getViewportWidthPix() / 2;
2681 int yPix = getViewportHeightPix() / 2;
2683 nativePinchBegin(mNativeContentViewCore, timeMs, xPix, yPix);
2684 nativePinchBy(mNativeContentViewCore, timeMs, xPix, yPix, delta);
2685 nativePinchEnd(mNativeContentViewCore, timeMs);
2691 * Invokes the graphical zoom picker widget for this ContentView.
2693 public void invokeZoomPicker() {
2694 mZoomControlsDelegate.invokeZoomPicker();
2698 * Enables or disables inspection of JavaScript objects added via
2699 * {@link #addJavascriptInterface(Object, String)} by means of Object.keys() method and
2700 * "for .. in" loop. Being able to inspect JavaScript objects is useful
2701 * when debugging hybrid Android apps, but can't be enabled for legacy applications due
2702 * to compatibility risks.
2704 * @param allow Whether to allow JavaScript objects inspection.
2706 public void setAllowJavascriptInterfacesInspection(boolean allow) {
2707 nativeSetAllowJavascriptInterfacesInspection(mNativeContentViewCore, allow);
2711 * This will mimic {@link #addPossiblyUnsafeJavascriptInterface(Object, String, Class)}
2712 * and automatically pass in {@link JavascriptInterface} as the required annotation.
2714 * @param object The Java object to inject into the ContentViewCore's JavaScript context. Null
2715 * values are ignored.
2716 * @param name The name used to expose the instance in JavaScript.
2718 public void addJavascriptInterface(Object object, String name) {
2719 addPossiblyUnsafeJavascriptInterface(object, name, JavascriptInterface.class);
2723 * This method injects the supplied Java object into the ContentViewCore.
2724 * The object is injected into the JavaScript context of the main frame,
2725 * using the supplied name. This allows the Java object to be accessed from
2726 * JavaScript. Note that that injected objects will not appear in
2727 * JavaScript until the page is next (re)loaded. For example:
2728 * <pre> view.addJavascriptInterface(new Object(), "injectedObject");
2729 * view.loadData("<!DOCTYPE html><title></title>", "text/html", null);
2730 * view.loadUrl("javascript:alert(injectedObject.toString())");</pre>
2731 * <p><strong>IMPORTANT:</strong>
2733 * <li> addJavascriptInterface() can be used to allow JavaScript to control
2734 * the host application. This is a powerful feature, but also presents a
2735 * security risk. Use of this method in a ContentViewCore containing
2736 * untrusted content could allow an attacker to manipulate the host
2737 * application in unintended ways, executing Java code with the permissions
2738 * of the host application. Use extreme care when using this method in a
2739 * ContentViewCore which could contain untrusted content. Particular care
2740 * should be taken to avoid unintentional access to inherited methods, such
2741 * as {@link Object#getClass()}. To prevent access to inherited methods,
2742 * pass an annotation for {@code requiredAnnotation}. This will ensure
2743 * that only methods with {@code requiredAnnotation} are exposed to the
2744 * Javascript layer. {@code requiredAnnotation} will be passed to all
2745 * subsequently injected Java objects if any methods return an object. This
2746 * means the same restrictions (or lack thereof) will apply. Alternatively,
2747 * {@link #addJavascriptInterface(Object, String)} can be called, which
2748 * automatically uses the {@link JavascriptInterface} annotation.
2749 * <li> JavaScript interacts with Java objects on a private, background
2750 * thread of the ContentViewCore. Care is therefore required to maintain
2751 * thread safety.</li>
2754 * @param object The Java object to inject into the
2755 * ContentViewCore's JavaScript context. Null
2756 * values are ignored.
2757 * @param name The name used to expose the instance in
2759 * @param requiredAnnotation Restrict exposed methods to ones with this
2760 * annotation. If {@code null} all methods are
2764 public void addPossiblyUnsafeJavascriptInterface(Object object, String name,
2765 Class<? extends Annotation> requiredAnnotation) {
2766 if (mNativeContentViewCore != 0 && object != null) {
2767 mJavaScriptInterfaces.put(name, object);
2768 nativeAddJavascriptInterface(mNativeContentViewCore, object, name, requiredAnnotation,
2769 mRetainedJavaScriptObjects);
2774 * Removes a previously added JavaScript interface with the given name.
2776 * @param name The name of the interface to remove.
2778 public void removeJavascriptInterface(String name) {
2779 mJavaScriptInterfaces.remove(name);
2780 if (mNativeContentViewCore != 0) {
2781 nativeRemoveJavascriptInterface(mNativeContentViewCore, name);
2786 * Return the current scale of the ContentView.
2787 * @return The current page scale factor.
2789 public float getScale() {
2790 return mRenderCoordinates.getPageScaleFactor();
2794 * If the view is ready to draw contents to the screen. In hardware mode,
2795 * the initialization of the surface texture may not occur until after the
2796 * view has been added to the layout. This method will return {@code true}
2797 * once the texture is actually ready.
2799 public boolean isReady() {
2800 if (mNativeContentViewCore == 0) return false;
2801 return nativeIsRenderWidgetHostViewReady(mNativeContentViewCore);
2805 private void startContentIntent(String contentUrl) {
2806 getContentViewClient().onStartContentIntent(getContext(), contentUrl);
2810 public void onAccessibilityStateChanged(boolean enabled) {
2811 setAccessibilityState(enabled);
2815 * Determines whether or not this ContentViewCore can handle this accessibility action.
2816 * @param action The action to perform.
2817 * @return Whether or not this action is supported.
2819 public boolean supportsAccessibilityAction(int action) {
2820 return mAccessibilityInjector.supportsAccessibilityAction(action);
2824 * Attempts to perform an accessibility action on the web content. If the accessibility action
2825 * cannot be processed, it returns {@code null}, allowing the caller to know to call the
2826 * super {@link View#performAccessibilityAction(int, Bundle)} method and use that return value.
2827 * Otherwise the return value from this method should be used.
2828 * @param action The action to perform.
2829 * @param arguments Optional action arguments.
2830 * @return Whether the action was performed or {@code null} if the call should be delegated to
2831 * the super {@link View} class.
2833 public boolean performAccessibilityAction(int action, Bundle arguments) {
2834 if (mAccessibilityInjector.supportsAccessibilityAction(action)) {
2835 return mAccessibilityInjector.performAccessibilityAction(action, arguments);
2842 * Set the BrowserAccessibilityManager, used for native accessibility
2843 * (not script injection). This is only set when system accessibility
2845 * @param manager The new BrowserAccessibilityManager.
2847 public void setBrowserAccessibilityManager(BrowserAccessibilityManager manager) {
2848 mBrowserAccessibilityManager = manager;
2852 * Get the BrowserAccessibilityManager, used for native accessibility
2853 * (not script injection). This will return null when system accessibility
2855 * @return This view's BrowserAccessibilityManager.
2857 public BrowserAccessibilityManager getBrowserAccessibilityManager() {
2858 return mBrowserAccessibilityManager;
2862 * If native accessibility (not script injection) is enabled, and if this is
2863 * running on JellyBean or later, returns an AccessibilityNodeProvider that
2864 * implements native accessibility for this view. Returns null otherwise.
2865 * Lazily initializes native accessibility here if it's allowed.
2866 * @return The AccessibilityNodeProvider, if available, or null otherwise.
2868 public AccessibilityNodeProvider getAccessibilityNodeProvider() {
2869 if (mBrowserAccessibilityManager != null) {
2870 return mBrowserAccessibilityManager.getAccessibilityNodeProvider();
2873 if (mNativeAccessibilityAllowed &&
2874 !mNativeAccessibilityEnabled &&
2875 mNativeContentViewCore != 0 &&
2876 Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
2877 mNativeAccessibilityEnabled = true;
2878 nativeSetAccessibilityEnabled(mNativeContentViewCore, true);
2885 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
2887 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
2888 // Note: this is only used by the script-injecting accessibility code.
2889 mAccessibilityInjector.onInitializeAccessibilityNodeInfo(info);
2893 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent)
2895 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
2896 // Note: this is only used by the script-injecting accessibility code.
2897 event.setClassName(this.getClass().getName());
2899 // Identify where the top-left of the screen currently points to.
2900 event.setScrollX(mRenderCoordinates.getScrollXPixInt());
2901 event.setScrollY(mRenderCoordinates.getScrollYPixInt());
2903 // The maximum scroll values are determined by taking the content dimensions and
2904 // subtracting off the actual dimensions of the ChromeView.
2905 int maxScrollXPix = Math.max(0, mRenderCoordinates.getMaxHorizontalScrollPixInt());
2906 int maxScrollYPix = Math.max(0, mRenderCoordinates.getMaxVerticalScrollPixInt());
2907 event.setScrollable(maxScrollXPix > 0 || maxScrollYPix > 0);
2909 // Setting the maximum scroll values requires API level 15 or higher.
2910 final int SDK_VERSION_REQUIRED_TO_SET_SCROLL = 15;
2911 if (Build.VERSION.SDK_INT >= SDK_VERSION_REQUIRED_TO_SET_SCROLL) {
2912 event.setMaxScrollX(maxScrollXPix);
2913 event.setMaxScrollY(maxScrollYPix);
2918 * Returns whether accessibility script injection is enabled on the device
2920 public boolean isDeviceAccessibilityScriptInjectionEnabled() {
2922 if (!CommandLine.getInstance().hasSwitch(
2923 ContentSwitches.ENABLE_ACCESSIBILITY_SCRIPT_INJECTION)) {
2927 if (!mContentSettings.getJavaScriptEnabled()) {
2931 int result = getContext().checkCallingOrSelfPermission(
2932 android.Manifest.permission.INTERNET);
2933 if (result != PackageManager.PERMISSION_GRANTED) {
2937 Field field = Settings.Secure.class.getField("ACCESSIBILITY_SCRIPT_INJECTION");
2938 field.setAccessible(true);
2939 String accessibilityScriptInjection = (String) field.get(null);
2940 ContentResolver contentResolver = getContext().getContentResolver();
2942 if (mAccessibilityScriptInjectionObserver == null) {
2943 ContentObserver contentObserver = new ContentObserver(new Handler()) {
2945 public void onChange(boolean selfChange, Uri uri) {
2946 setAccessibilityState(mAccessibilityManager.isEnabled());
2949 contentResolver.registerContentObserver(
2950 Settings.Secure.getUriFor(accessibilityScriptInjection),
2953 mAccessibilityScriptInjectionObserver = contentObserver;
2956 return Settings.Secure.getInt(contentResolver, accessibilityScriptInjection, 0) == 1;
2957 } catch (NoSuchFieldException e) {
2958 // Do nothing, default to false.
2959 } catch (IllegalAccessException e) {
2960 // Do nothing, default to false.
2966 * Returns whether or not accessibility injection is being used.
2968 public boolean isInjectingAccessibilityScript() {
2969 return mAccessibilityInjector.accessibilityIsAvailable();
2973 * Turns browser accessibility on or off.
2974 * If |state| is |false|, this turns off both native and injected accessibility.
2975 * Otherwise, if accessibility script injection is enabled, this will enable the injected
2976 * accessibility scripts. Native accessibility is enabled on demand.
2978 public void setAccessibilityState(boolean state) {
2980 setInjectedAccessibility(false);
2981 mNativeAccessibilityAllowed = false;
2982 mTouchExplorationEnabled = false;
2984 boolean useScriptInjection = isDeviceAccessibilityScriptInjectionEnabled();
2985 setInjectedAccessibility(useScriptInjection);
2986 mNativeAccessibilityAllowed = !useScriptInjection;
2987 mTouchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled();
2992 * Enable or disable injected accessibility features
2994 public void setInjectedAccessibility(boolean enabled) {
2995 mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary();
2996 mAccessibilityInjector.setScriptEnabled(enabled);
3000 * Stop any TTS notifications that are currently going on.
3002 public void stopCurrentAccessibilityNotifications() {
3003 mAccessibilityInjector.onPageLostFocus();
3007 * Inform WebKit that Fullscreen mode has been exited by the user.
3009 public void exitFullscreen() {
3010 if (mNativeContentViewCore != 0) nativeExitFullscreen(mNativeContentViewCore);
3014 * Changes whether hiding the top controls is enabled.
3016 * @param enableHiding Whether hiding the top controls should be enabled or not.
3017 * @param enableShowing Whether showing the top controls should be enabled or not.
3018 * @param animate Whether the transition should be animated or not.
3020 public void updateTopControlsState(boolean enableHiding, boolean enableShowing,
3022 if (mNativeContentViewCore != 0) {
3023 nativeUpdateTopControlsState(
3024 mNativeContentViewCore, enableHiding, enableShowing, animate);
3029 * Callback factory method for nativeGetNavigationHistory().
3032 private void addToNavigationHistory(Object history, int index, String url, String virtualUrl,
3033 String originalUrl, String title, Bitmap favicon) {
3034 NavigationEntry entry = new NavigationEntry(
3035 index, url, virtualUrl, originalUrl, title, favicon);
3036 ((NavigationHistory) history).addEntry(entry);
3040 * Get a copy of the navigation history of the view.
3042 public NavigationHistory getNavigationHistory() {
3043 NavigationHistory history = new NavigationHistory();
3044 if (mNativeContentViewCore != 0) {
3045 int currentIndex = nativeGetNavigationHistory(mNativeContentViewCore, history);
3046 history.setCurrentEntryIndex(currentIndex);
3052 public NavigationHistory getDirectedNavigationHistory(boolean isForward, int itemLimit) {
3053 NavigationHistory history = new NavigationHistory();
3054 if (mNativeContentViewCore != 0) {
3055 nativeGetDirectedNavigationHistory(
3056 mNativeContentViewCore, history, isForward, itemLimit);
3062 * @return The original request URL for the current navigation entry, or null if there is no
3065 public String getOriginalUrlForActiveNavigationEntry() {
3066 if (mNativeContentViewCore != 0) {
3067 return nativeGetOriginalUrlForActiveNavigationEntry(mNativeContentViewCore);
3073 * @return The cached copy of render positions and scales.
3075 public RenderCoordinates getRenderCoordinates() {
3076 return mRenderCoordinates;
3080 private int getLocationInWindowX() {
3081 return mLocationInWindowX;
3085 private int getLocationInWindowY() {
3086 return mLocationInWindowY;
3090 private static Rect createRect(int x, int y, int right, int bottom) {
3091 return new Rect(x, y, right, bottom);
3094 private boolean onAnimate(long frameTimeMicros) {
3095 if (mNativeContentViewCore == 0) return false;
3096 return nativeOnAnimate(mNativeContentViewCore, frameTimeMicros);
3099 private void animateIfNecessary(long frameTimeMicros) {
3101 mNeedAnimate = onAnimate(frameTimeMicros);
3102 if (!mNeedAnimate) removeVSyncSubscriber();
3106 public void extractSmartClipData(int x, int y, int width, int height) {
3107 if (mNativeContentViewCore != 0) {
3108 nativeExtractSmartClipData(mNativeContentViewCore, x, y, width, height);
3113 private void onSmartClipDataExtracted(String result) {
3114 if (mSmartClipDataListener != null ) {
3115 mSmartClipDataListener.onSmartClipDataExtracted(result);
3119 public void setSmartClipDataListener(SmartClipDataListener listener) {
3120 mSmartClipDataListener = listener;
3124 * Offer a long press gesture to the embedding View, primarily for WebView compatibility.
3126 * @return true if the embedder handled the event.
3128 private boolean offerLongPressToEmbedder() {
3129 return mContainerView.performLongClick();
3132 private native long nativeInit(long webContentsPtr,
3133 long viewAndroidPtr, long windowAndroidPtr);
3136 private ContentVideoViewClient getContentVideoViewClient() {
3137 return getContentViewClient().getContentVideoViewClient();
3141 private boolean shouldBlockMediaRequest(String url) {
3142 return getContentViewClient().shouldBlockMediaRequest(url);
3146 private void onNativeFlingStopped() {
3147 // Note that mTouchScrollInProgress should normally be false at this
3148 // point, but we reset it anyway as another failsafe.
3149 mTouchScrollInProgress = false;
3150 if (mPotentiallyActiveFlingCount > 0) mPotentiallyActiveFlingCount--;
3151 updateGestureStateListener(GestureEventType.FLING_END);
3155 public void onScreenOrientationChanged(int orientation) {
3156 sendOrientationChangeEvent(orientation);
3159 private native WebContents nativeGetWebContentsAndroid(long nativeContentViewCoreImpl);
3161 private native void nativeOnJavaContentViewCoreDestroyed(long nativeContentViewCoreImpl);
3163 private native void nativeLoadUrl(
3164 long nativeContentViewCoreImpl,
3168 int uaOverrideOption,
3169 String extraHeaders,
3171 String baseUrlForDataUrl,
3172 String virtualUrlForDataUrl,
3173 boolean canLoadLocalResources);
3175 private native String nativeGetURL(long nativeContentViewCoreImpl);
3177 private native String nativeGetTitle(long nativeContentViewCoreImpl);
3179 private native void nativeShowInterstitialPage(
3180 long nativeContentViewCoreImpl, String url, long nativeInterstitialPageDelegateAndroid);
3181 private native boolean nativeIsShowingInterstitialPage(long nativeContentViewCoreImpl);
3183 private native boolean nativeIsIncognito(long nativeContentViewCoreImpl);
3185 private native void nativeSetFocus(long nativeContentViewCoreImpl, boolean focused);
3187 private native void nativeSendOrientationChangeEvent(
3188 long nativeContentViewCoreImpl, int orientation);
3190 // All touch events (including flings, scrolls etc) accept coordinates in physical pixels.
3191 private native boolean nativeOnTouchEvent(
3192 long nativeContentViewCoreImpl, MotionEvent event,
3193 long timeMs, int action, int pointerCount, int historySize, int actionIndex,
3194 float x0, float y0, float x1, float y1,
3195 int pointerId0, int pointerId1,
3196 float touchMajor0, float touchMajor1);
3198 private native int nativeSendMouseMoveEvent(
3199 long nativeContentViewCoreImpl, long timeMs, float x, float y);
3201 private native int nativeSendMouseWheelEvent(
3202 long nativeContentViewCoreImpl, long timeMs, float x, float y, float verticalAxis);
3204 private native void nativeScrollBegin(
3205 long nativeContentViewCoreImpl, long timeMs, float x, float y, float hintX,
3208 private native void nativeScrollEnd(long nativeContentViewCoreImpl, long timeMs);
3210 private native void nativeScrollBy(
3211 long nativeContentViewCoreImpl, long timeMs, float x, float y,
3212 float deltaX, float deltaY);
3214 private native void nativeFlingStart(
3215 long nativeContentViewCoreImpl, long timeMs, float x, float y, float vx, float vy);
3217 private native void nativeFlingCancel(long nativeContentViewCoreImpl, long timeMs);
3219 private native void nativeSingleTap(
3220 long nativeContentViewCoreImpl, long timeMs, float x, float y);
3222 private native void nativeDoubleTap(
3223 long nativeContentViewCoreImpl, long timeMs, float x, float y);
3225 private native void nativeLongPress(
3226 long nativeContentViewCoreImpl, long timeMs, float x, float y);
3228 private native void nativePinchBegin(
3229 long nativeContentViewCoreImpl, long timeMs, float x, float y);
3231 private native void nativePinchEnd(long nativeContentViewCoreImpl, long timeMs);
3233 private native void nativePinchBy(long nativeContentViewCoreImpl, long timeMs,
3234 float anchorX, float anchorY, float deltaScale);
3236 private native void nativeSelectBetweenCoordinates(
3237 long nativeContentViewCoreImpl, float x1, float y1, float x2, float y2);
3239 private native void nativeMoveCaret(long nativeContentViewCoreImpl, float x, float y);
3241 private native void nativeResetGestureDetectors(long nativeContentViewCoreImpl);
3243 private native void nativeIgnoreRemainingTouchEvents(long nativeContentViewCoreImpl);
3245 private native void nativeOnWindowFocusLost(long nativeContentViewCoreImpl);
3247 private native void nativeSetDoubleTapSupportForPageEnabled(
3248 long nativeContentViewCoreImpl, boolean enabled);
3249 private native void nativeSetDoubleTapSupportEnabled(
3250 long nativeContentViewCoreImpl, boolean enabled);
3251 private native void nativeSetMultiTouchZoomSupportEnabled(
3252 long nativeContentViewCoreImpl, boolean enabled);
3254 private native void nativeLoadIfNecessary(long nativeContentViewCoreImpl);
3255 private native void nativeRequestRestoreLoad(long nativeContentViewCoreImpl);
3257 private native void nativeStopLoading(long nativeContentViewCoreImpl);
3259 private native void nativeReload(long nativeContentViewCoreImpl, boolean checkForRepost);
3260 private native void nativeReloadIgnoringCache(
3261 long nativeContentViewCoreImpl, boolean checkForRepost);
3263 private native void nativeCancelPendingReload(long nativeContentViewCoreImpl);
3265 private native void nativeContinuePendingReload(long nativeContentViewCoreImpl);
3267 private native void nativeSelectPopupMenuItems(long nativeContentViewCoreImpl, int[] indices);
3269 private native void nativeScrollFocusedEditableNodeIntoView(long nativeContentViewCoreImpl);
3271 private native void nativeClearHistory(long nativeContentViewCoreImpl);
3273 private native void nativeEvaluateJavaScript(long nativeContentViewCoreImpl,
3274 String script, JavaScriptCallback callback, boolean startRenderer);
3276 private native long nativeGetNativeImeAdapter(long nativeContentViewCoreImpl);
3278 private native int nativeGetCurrentRenderProcessId(long nativeContentViewCoreImpl);
3280 private native int nativeGetBackgroundColor(long nativeContentViewCoreImpl);
3282 private native void nativeOnShow(long nativeContentViewCoreImpl);
3283 private native void nativeOnHide(long nativeContentViewCoreImpl);
3285 private native void nativeSetUseDesktopUserAgent(long nativeContentViewCoreImpl,
3286 boolean enabled, boolean reloadOnChange);
3287 private native boolean nativeGetUseDesktopUserAgent(long nativeContentViewCoreImpl);
3289 private native void nativeClearSslPreferences(long nativeContentViewCoreImpl);
3291 private native void nativeSetAllowJavascriptInterfacesInspection(
3292 long nativeContentViewCoreImpl, boolean allow);
3294 private native void nativeAddJavascriptInterface(long nativeContentViewCoreImpl, Object object,
3295 String name, Class requiredAnnotation, HashSet<Object> retainedObjectSet);
3297 private native void nativeRemoveJavascriptInterface(long nativeContentViewCoreImpl,
3300 private native int nativeGetNavigationHistory(long nativeContentViewCoreImpl, Object context);
3301 private native void nativeGetDirectedNavigationHistory(long nativeContentViewCoreImpl,
3302 Object context, boolean isForward, int maxEntries);
3303 private native String nativeGetOriginalUrlForActiveNavigationEntry(
3304 long nativeContentViewCoreImpl);
3306 private native void nativeUpdateVSyncParameters(long nativeContentViewCoreImpl,
3307 long timebaseMicros, long intervalMicros);
3309 private native void nativeOnVSync(long nativeContentViewCoreImpl, long frameTimeMicros);
3311 private native boolean nativeOnAnimate(long nativeContentViewCoreImpl, long frameTimeMicros);
3313 private native void nativeWasResized(long nativeContentViewCoreImpl);
3315 private native boolean nativeIsRenderWidgetHostViewReady(long nativeContentViewCoreImpl);
3317 private native void nativeExitFullscreen(long nativeContentViewCoreImpl);
3318 private native void nativeUpdateTopControlsState(long nativeContentViewCoreImpl,
3319 boolean enableHiding, boolean enableShowing, boolean animate);
3321 private native void nativeShowImeIfNeeded(long nativeContentViewCoreImpl);
3323 private native void nativeSetAccessibilityEnabled(
3324 long nativeContentViewCoreImpl, boolean enabled);
3326 private native void nativeExtractSmartClipData(long nativeContentViewCoreImpl,
3327 int x, int y, int w, int h);