Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / content / public / android / java / src / org / chromium / content / browser / ContentViewCore.java
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.content.browser;
6
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;
48
49 import com.google.common.annotations.VisibleForTesting;
50
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;
77
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;
84 import java.util.Map;
85
86 /**
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.
90  */
91 @JNINamespace("content")
92 public class ContentViewCore
93         implements NavigationClient, AccessibilityStateChangeListener, ScreenOrientationObserver {
94
95     private static final String TAG = "ContentViewCore";
96
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;
100
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;
104
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;
107
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>();
119
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>();
127
128     /**
129      * Interface that consumers of {@link ContentViewCore} must implement to allow the proper
130      * dispatching of view methods through the containing view.
131      *
132      * <p>
133      * All methods with the "super_" prefix should be routed to the parent of the
134      * implementing container view.
135      */
136     @SuppressWarnings("javadoc")
137     public interface InternalAccessDelegate {
138         /**
139          * @see View#drawChild(Canvas, View, long)
140          */
141         boolean drawChild(Canvas canvas, View child, long drawingTime);
142
143         /**
144          * @see View#onKeyUp(keyCode, KeyEvent)
145          */
146         boolean super_onKeyUp(int keyCode, KeyEvent event);
147
148         /**
149          * @see View#dispatchKeyEventPreIme(KeyEvent)
150          */
151         boolean super_dispatchKeyEventPreIme(KeyEvent event);
152
153         /**
154          * @see View#dispatchKeyEvent(KeyEvent)
155          */
156         boolean super_dispatchKeyEvent(KeyEvent event);
157
158         /**
159          * @see View#onGenericMotionEvent(MotionEvent)
160          */
161         boolean super_onGenericMotionEvent(MotionEvent event);
162
163         /**
164          * @see View#onConfigurationChanged(Configuration)
165          */
166         void super_onConfigurationChanged(Configuration newConfig);
167
168         /**
169          * @see View#onScrollChanged(int, int, int, int)
170          */
171         void onScrollChanged(int lPix, int tPix, int oldlPix, int oldtPix);
172
173         /**
174          * @see View#awakenScrollBars()
175          */
176         boolean awakenScrollBars();
177
178         /**
179          * @see View#awakenScrollBars(int, boolean)
180          */
181         boolean super_awakenScrollBars(int startDelay, boolean invalidate);
182     }
183
184     /**
185      * An interface for controlling visibility and state of embedder-provided zoom controls.
186      */
187     public interface ZoomControlsDelegate {
188         /**
189          * Called when it's reasonable to show zoom controls.
190          */
191         void invokeZoomPicker();
192
193         /**
194          * Called when zoom controls need to be hidden (e.g. when the view hides).
195          */
196         void dismissZoomPicker();
197
198         /**
199          * Called when page scale has been changed, so the controls can update their state.
200          */
201         void updateZoomControls();
202     }
203
204     /**
205      * An interface that allows the embedder to be notified when the results of
206      * extractSmartClipData are available.
207      */
208     public interface SmartClipDataListener {
209         public void onSmartClipDataExtracted(String result);
210     }
211
212     private VSyncManager.Provider mVSyncProvider;
213     private VSyncManager.Listener mVSyncListener;
214     private int mVSyncSubscriberCount;
215     private boolean mVSyncListenerRegistered;
216
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;
221
222     public VSyncManager.Listener getVSyncListener(VSyncManager.Provider vsyncProvider) {
223         if (mVSyncProvider != null && mVSyncListenerRegistered) {
224             mVSyncProvider.unregisterVSyncListener(mVSyncListener);
225             mVSyncListenerRegistered = false;
226         }
227
228         mVSyncProvider = vsyncProvider;
229         mVSyncListener = new VSyncManager.Listener() {
230             @Override
231             public void updateVSync(long tickTimeMicros, long intervalMicros) {
232                 if (mNativeContentViewCore != 0) {
233                     nativeUpdateVSyncParameters(mNativeContentViewCore, tickTimeMicros,
234                             intervalMicros);
235                 }
236             }
237
238             @Override
239             public void onVSync(long frameTimeMicros) {
240                 animateIfNecessary(frameTimeMicros);
241
242                 if (mRequestedVSyncForInput) {
243                     mRequestedVSyncForInput = false;
244                     removeVSyncSubscriber();
245                 }
246                 if (mNativeContentViewCore != 0) {
247                     nativeOnVSync(mNativeContentViewCore, frameTimeMicros);
248                 }
249             }
250         };
251
252         if (mVSyncSubscriberCount > 0) {
253             // addVSyncSubscriber() is called before getVSyncListener.
254             vsyncProvider.registerVSyncListener(mVSyncListener);
255             mVSyncListenerRegistered = true;
256         }
257
258         return mVSyncListener;
259     }
260
261     @CalledByNative
262     void addVSyncSubscriber() {
263         if (!isVSyncNotificationEnabled()) {
264             mDidSignalVSyncUsingInputEvent = false;
265         }
266         if (mVSyncProvider != null && !mVSyncListenerRegistered) {
267             mVSyncProvider.registerVSyncListener(mVSyncListener);
268             mVSyncListenerRegistered = true;
269         }
270         mVSyncSubscriberCount++;
271     }
272
273     @CalledByNative
274     void removeVSyncSubscriber() {
275         if (mVSyncProvider != null && mVSyncSubscriberCount == 1) {
276             assert mVSyncListenerRegistered;
277             mVSyncProvider.unregisterVSyncListener(mVSyncListener);
278             mVSyncListenerRegistered = false;
279         }
280         mVSyncSubscriberCount--;
281         assert mVSyncSubscriberCount >= 0;
282     }
283
284     @CalledByNative
285     private void resetVSyncNotification() {
286         while (isVSyncNotificationEnabled()) removeVSyncSubscriber();
287         mVSyncSubscriberCount = 0;
288         mVSyncListenerRegistered = false;
289         mNeedAnimate = false;
290     }
291
292     private boolean isVSyncNotificationEnabled() {
293         return mVSyncProvider != null && mVSyncListenerRegistered;
294     }
295
296     @CalledByNative
297     private void setNeedsAnimate() {
298         if (!mNeedAnimate) {
299             mNeedAnimate = true;
300             addVSyncSubscriber();
301         }
302     }
303
304     private final Context mContext;
305     private ViewGroup mContainerView;
306     private InternalAccessDelegate mContainerViewInternals;
307     private WebContents mWebContents;
308     private WebContentsObserverAndroid mWebContentsObserver;
309
310     private ContentViewClient mContentViewClient;
311
312     private ContentSettings mContentSettings;
313
314     // Native pointer to C++ ContentViewCoreImpl object which will be set by nativeInit().
315     private long mNativeContentViewCore = 0;
316
317     private boolean mInForeground = false;
318
319     private final ObserverList<GestureStateListener> mGestureStateListeners;
320     private final RewindableIterator<GestureStateListener> mGestureStateListenersIterator;
321     private ZoomControlsDelegate mZoomControlsDelegate;
322
323     private PopupZoomer mPopupZoomer;
324     private SelectPopupDialog mSelectPopupDialog;
325
326     private Runnable mFakeMouseMoveRunnable = null;
327
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;
333
334     private SelectionHandleController mSelectionHandleController;
335     private InsertionHandleController mInsertionHandleController;
336
337     private Runnable mDeferredHandleFadeInRunnable;
338
339     private PositionObserver mPositionObserver;
340     private PositionObserver.Listener mPositionListener;
341
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;
352
353     // Cached copy of all positions and scales as reported by the renderer.
354     private final RenderCoordinates mRenderCoordinates;
355
356     private final RenderCoordinates.NormalizedPoint mStartHandlePoint;
357     private final RenderCoordinates.NormalizedPoint mEndHandlePoint;
358     private final RenderCoordinates.NormalizedPoint mInsertionHandlePoint;
359
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;
364
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;
372
373     // Delegate that will handle GET downloads, and be notified of completion of POST downloads.
374     private ContentViewDownloadDelegate mDownloadDelegate;
375
376     // The AccessibilityInjector that handles loading Accessibility scripts into the web page.
377     private AccessibilityInjector mAccessibilityInjector;
378
379     // Whether native accessibility, i.e. without any script injection, is allowed.
380     private boolean mNativeAccessibilityAllowed;
381
382     // Whether native accessibility, i.e. without any script injection, has been enabled.
383     private boolean mNativeAccessibilityEnabled;
384
385     // Handles native accessibility, i.e. without any script injection.
386     private BrowserAccessibilityManager mBrowserAccessibilityManager;
387
388     // System accessibility service.
389     private final AccessibilityManager mAccessibilityManager;
390
391     // Accessibility touch exploration state.
392     private boolean mTouchExplorationEnabled;
393
394     // Allows us to dynamically respond when the accessibility script injection flag changes.
395     private ContentObserver mAccessibilityScriptInjectionObserver;
396
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();
400
401     // Whether we received a new frame since consumePendingRendererFrame() was last called.
402     private boolean mPendingRendererFrame = false;
403
404     // Whether we should animate at the next vsync tick.
405     private boolean mNeedAnimate = false;
406
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
411     // vsync.
412     private boolean mRequestedVSyncForInput = false;
413
414     // On single tap this will store the x, y coordinates of the touch.
415     private int mSingleTapX;
416     private int mSingleTapY;
417
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;
422
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;
426
427     private ViewAndroid mViewAndroid;
428
429     private SmartClipDataListener mSmartClipDataListener = null;
430
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;
436
437     /**
438      * PID used to indicate an invalid render process.
439      */
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;
443
444     /**
445      * Constructs a new ContentViewCore. Embedders must call initialize() after constructing
446      * a ContentViewCore and before using it.
447      *
448      * @param context The context used to create this.
449      */
450     public ContentViewCore(Context context) {
451         mContext = context;
452
453         mAdapterInputConnectionFactory = new AdapterInputConnectionFactory();
454         mInputMethodManagerWrapper = new InputMethodManagerWrapper(mContext);
455
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);
462         }
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();
473
474         mEditable = Editable.Factory.getInstance().newEditable("");
475         Selection.setSelection(mEditable, 0);
476     }
477
478     /**
479      * @return The context used for creating this ContentViewCore.
480      */
481     @CalledByNative
482     public Context getContext() {
483         return mContext;
484     }
485
486     /**
487      * @return The ViewGroup that all view actions of this ContentViewCore should interact with.
488      */
489     public ViewGroup getContainerView() {
490         return mContainerView;
491     }
492
493     /**
494      * @return The WebContents currently being rendered.
495      */
496     public WebContents getWebContents() {
497         return mWebContents;
498     }
499
500     /**
501      * Specifies how much smaller the WebKit layout size should be relative to the size of this
502      * view.
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.
505      */
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);
512         }
513     }
514
515     /**
516      * Returns a delegate that can be used to add and remove views from the ContainerView.
517      *
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
523      *
524      * @return A ViewAndroidDelegate that can be used to add and remove views.
525      */
526     @VisibleForTesting
527     public ViewAndroidDelegate getViewAndroidDelegate() {
528         return new ViewAndroidDelegate() {
529             @Override
530             public View acquireAnchorView() {
531                 View anchorView = new View(getContext());
532                 mContainerView.addView(anchorView);
533                 return anchorView;
534             }
535
536             @Override
537             @SuppressWarnings("deprecation")  // AbsoluteLayout
538             public void setAnchorViewPosition(
539                     View view, float x, float y, float width, float height) {
540                 assert view.getParent() == mContainerView;
541
542                 float scale = (float) DeviceDisplayInfo.create(getContext()).getDIPScale();
543
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;
552                     }
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
563                     // these models.
564                     leftMargin += mRenderCoordinates.getScrollXPixInt();
565                     topMargin += mRenderCoordinates.getScrollYPixInt();
566
567                     android.widget.AbsoluteLayout.LayoutParams lp =
568                             new android.widget.AbsoluteLayout.LayoutParams(
569                                 scaledWidth, (int) (height * scale), leftMargin, topMargin);
570                     view.setLayoutParams(lp);
571                 } else {
572                     Log.e(TAG, "Unknown layout " + mContainerView.getClass().getName());
573                 }
574             }
575
576             @Override
577             public void releaseAnchorView(View anchorView) {
578                 mContainerView.removeView(anchorView);
579             }
580         };
581     }
582
583     @VisibleForTesting
584     public void setImeAdapterForTest(ImeAdapter imeAdapter) {
585         mImeAdapter = imeAdapter;
586     }
587
588     @VisibleForTesting
589     public ImeAdapter getImeAdapterForTest() {
590         return mImeAdapter;
591     }
592
593     @VisibleForTesting
594     public void setAdapterInputConnectionFactory(AdapterInputConnectionFactory factory) {
595         mAdapterInputConnectionFactory = factory;
596     }
597
598     @VisibleForTesting
599     public void setInputMethodManagerWrapperForTest(InputMethodManagerWrapper immw) {
600         mInputMethodManagerWrapper = immw;
601     }
602
603     @VisibleForTesting
604     public AdapterInputConnection getInputConnectionForTest() {
605         return mInputConnection;
606     }
607
608     @VisibleForTesting
609     public void setContainerViewForTest(ViewGroup view) {
610         mContainerView = view;
611     }
612
613     private ImeAdapter createImeAdapter(Context context) {
614         return new ImeAdapter(mInputMethodManagerWrapper,
615                 new ImeAdapter.ImeAdapterDelegate() {
616                     @Override
617                     public void onImeEvent(boolean isFinish) {
618                         getContentViewClient().onImeEvent();
619                         if (!isFinish) {
620                             hideHandles();
621                         }
622                     }
623
624                     @Override
625                     public void onSetFieldValue() {
626                         scrollFocusedEditableNodeIntoView();
627                     }
628
629                     @Override
630                     public void onDismissInput() {
631                         getContentViewClient().onImeStateChangeRequested(false);
632                     }
633
634                     @Override
635                     public View getAttachedView() {
636                         return mContainerView;
637                     }
638
639                     @Override
640                     public ResultReceiver getNewShowKeyboardReceiver() {
641                         return new ResultReceiver(new Handler()) {
642                             @Override
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
650                                     // new size).
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();
659                                 }
660                             }
661                         };
662                     }
663                 }
664         );
665     }
666
667     /**
668      *
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
671      *                           containerView.
672      * @param nativeWebContents A pointer to the native web contents.
673      * @param windowAndroid An instance of the WindowAndroid.
674      */
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() {
689             @Override
690             public void onPositionChanged(int x, int y) {
691                 if (isSelectionHandleShowing() || isInsertionHandleShowing()) {
692                     temporarilyHideTextHandles();
693                 }
694             }
695         };
696
697         long windowNativePointer = windowAndroid != null ? windowAndroid.getNativePointer() : 0;
698
699         long viewAndroidNativePointer = 0;
700         if (windowNativePointer != 0) {
701             mViewAndroid = new ViewAndroid(windowAndroid, getViewAndroidDelegate());
702             viewAndroidNativePointer = mViewAndroid.getNativePointer();
703         }
704
705         mZoomControlsDelegate = new ZoomControlsDelegate() {
706             @Override
707             public void invokeZoomPicker() {}
708             @Override
709             public void dismissZoomPicker() {}
710             @Override
711             public void updateZoomControls() {}
712         };
713
714         mNativeContentViewCore = nativeInit(
715                 nativeWebContents, viewAndroidNativePointer, windowNativePointer);
716         mWebContents = nativeGetWebContentsAndroid(mNativeContentViewCore);
717         mContentSettings = new ContentSettings(this, mNativeContentViewCore);
718         initializeContainerView(internalDispatcher);
719
720         mAccessibilityInjector = AccessibilityInjector.newInstance(this);
721
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.");
725         } else {
726             contentDescription = mContext.getResources().getString(
727                     R.string.accessibility_content_view);
728         }
729         mContainerView.setContentDescription(contentDescription);
730         mWebContentsObserver = new WebContentsObserverAndroid(this) {
731             @Override
732             public void didStartLoading(String url) {
733                 hidePopupDialog();
734                 resetGestureDetectors();
735             }
736         };
737     }
738
739     @CalledByNative
740     void onNativeContentViewCoreDestroyed(long nativeContentViewCore) {
741         assert nativeContentViewCore == mNativeContentViewCore;
742         mNativeContentViewCore = 0;
743     }
744
745     /**
746      * Set the Container view Internals.
747      * @param internalDispatcher Handles dispatching all hidden or super methods to the
748      *                           containerView.
749      */
750     public void setContainerViewInternals(InternalAccessDelegate internalDispatcher) {
751         mContainerViewInternals = internalDispatcher;
752     }
753
754     /**
755      * Initializes the View that will contain all Views created by the ContentViewCore.
756      *
757      * @param internalDispatcher Handles dispatching all hidden or super methods to the
758      *                           containerView.
759      */
760     private void initializeContainerView(InternalAccessDelegate internalDispatcher) {
761         TraceEvent.begin();
762         mContainerViewInternals = internalDispatcher;
763
764         mContainerView.setWillNotDraw(false);
765         mContainerView.setClickable(true);
766
767         mRenderCoordinates.reset();
768         onRenderCoordinatesUpdated();
769
770         initPopupZoomer(mContext);
771         mImeAdapter = createImeAdapter(mContext);
772         TraceEvent.end();
773     }
774
775     private void initPopupZoomer(Context context) {
776         mPopupZoomer = new PopupZoomer(context);
777         mPopupZoomer.setOnVisibilityChangedListener(new PopupZoomer.OnVisibilityChangedListener() {
778             @Override
779             public void onPopupZoomerShown(final PopupZoomer zoomer) {
780                 mContainerView.post(new Runnable() {
781                     @Override
782                     public void run() {
783                         if (mContainerView.indexOfChild(zoomer) == -1) {
784                             mContainerView.addView(zoomer);
785                         } else {
786                             assert false : "PopupZoomer should never be shown without being hidden";
787                         }
788                     }
789                 });
790             }
791
792             @Override
793             public void onPopupZoomerHidden(final PopupZoomer zoomer) {
794                 mContainerView.post(new Runnable() {
795                     @Override
796                     public void run() {
797                         if (mContainerView.indexOfChild(zoomer) != -1) {
798                             mContainerView.removeView(zoomer);
799                             mContainerView.invalidate();
800                         } else {
801                             assert false : "PopupZoomer should never be hidden without being shown";
802                         }
803                     }
804                 });
805             }
806         });
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() {
810             @Override
811             public boolean onSingleTap(View v, MotionEvent e) {
812                 mContainerView.requestFocus();
813                 if (mNativeContentViewCore != 0) {
814                     nativeSingleTap(mNativeContentViewCore, e.getEventTime(), e.getX(), e.getY());
815                 }
816                 return true;
817             }
818
819             @Override
820             public boolean onLongPress(View v, MotionEvent e) {
821                 if (mNativeContentViewCore != 0) {
822                     nativeLongPress(mNativeContentViewCore, e.getEventTime(), e.getX(), e.getY());
823                 }
824                 return true;
825             }
826         };
827         mPopupZoomer.setOnTapListener(listener);
828     }
829
830     /**
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
834      * been called.
835      */
836     public void destroy() {
837         if (mNativeContentViewCore != 0) {
838             nativeOnJavaContentViewCoreDestroyed(mNativeContentViewCore);
839         }
840         mWebContents = null;
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);
851     }
852
853     private void unregisterAccessibilityContentObserver() {
854         if (mAccessibilityScriptInjectionObserver == null) {
855             return;
856         }
857         getContext().getContentResolver().unregisterContentObserver(
858                 mAccessibilityScriptInjectionObserver);
859         mAccessibilityScriptInjectionObserver = null;
860     }
861
862     /**
863      * Returns true initially, false after destroy() has been called.
864      * It is illegal to call any other public method after destroy().
865      */
866     public boolean isAlive() {
867         return mNativeContentViewCore != 0;
868     }
869
870     /**
871      * This is only useful for passing over JNI to native code that requires ContentViewCore*.
872      * @return native ContentViewCore pointer.
873      */
874     @CalledByNative
875     public long getNativeContentViewCore() {
876         return mNativeContentViewCore;
877     }
878
879     public void setContentViewClient(ContentViewClient client) {
880         if (client == null) {
881             throw new IllegalArgumentException("The client can't be null.");
882         }
883         mContentViewClient = client;
884     }
885
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.
895         }
896         return mContentViewClient;
897     }
898
899     public int getBackgroundColor() {
900         if (mNativeContentViewCore != 0) {
901             return nativeGetBackgroundColor(mNativeContentViewCore);
902         }
903         return Color.WHITE;
904     }
905
906     @CalledByNative
907     private void onBackgroundColorChanged(int color) {
908         getContentViewClient().onBackgroundColorChanged(color);
909     }
910
911     /**
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).
915      *
916      * @param params Parameters for this load.
917      */
918     public void loadUrl(LoadUrlParams params) {
919         if (mNativeContentViewCore == 0) return;
920
921         nativeLoadUrl(mNativeContentViewCore,
922                 params.mUrl,
923                 params.mLoadUrlType,
924                 params.mTransitionType,
925                 params.mUaOverrideOption,
926                 params.getExtraHeadersString(),
927                 params.mPostData,
928                 params.mBaseUrlForDataUrl,
929                 params.mVirtualUrlForDataUrl,
930                 params.mCanLoadLocalResources);
931     }
932
933     /**
934      * Stops loading the current web contents.
935      */
936     public void stopLoading() {
937         if (mNativeContentViewCore != 0) nativeStopLoading(mNativeContentViewCore);
938     }
939
940     /**
941      * Get the URL of the current page.
942      *
943      * @return The URL of the current page.
944      */
945     public String getUrl() {
946         if (mNativeContentViewCore != 0) return nativeGetURL(mNativeContentViewCore);
947         return null;
948     }
949
950     /**
951      * Get the title of the current page.
952      *
953      * @return The title of the current page.
954      */
955     public String getTitle() {
956         if (mNativeContentViewCore != 0) return nativeGetTitle(mNativeContentViewCore);
957         return null;
958     }
959
960     /**
961      * Shows an interstitial page driven by the passed in delegate.
962      *
963      * @param url The URL being blocked by the interstitial.
964      * @param delegate The delegate handling the interstitial.
965      */
966     @VisibleForTesting
967     public void showInterstitialPage(
968             String url, InterstitialPageDelegateAndroid delegate) {
969         if (mNativeContentViewCore == 0) return;
970         nativeShowInterstitialPage(mNativeContentViewCore, url, delegate.getNative());
971     }
972
973     /**
974      * @return Whether the page is currently showing an interstitial, such as a bad HTTPS page.
975      */
976     public boolean isShowingInterstitialPage() {
977         return mNativeContentViewCore == 0 ?
978                 false : nativeIsShowingInterstitialPage(mNativeContentViewCore);
979     }
980
981     /**
982      * Mark any new frames that have arrived since this function was last called as non-pending.
983      *
984      * @return Whether there was a pending frame from the renderer.
985      */
986     public boolean consumePendingRendererFrame() {
987         boolean hadPendingFrame = mPendingRendererFrame;
988         mPendingRendererFrame = false;
989         return hadPendingFrame;
990     }
991
992     /**
993      * @return Viewport width in physical pixels as set from onSizeChanged.
994      */
995     @CalledByNative
996     public int getViewportWidthPix() { return mViewportWidthPix; }
997
998     /**
999      * @return Viewport height in physical pixels as set from onSizeChanged.
1000      */
1001     @CalledByNative
1002     public int getViewportHeightPix() { return mViewportHeightPix; }
1003
1004     /**
1005      * @return Width of underlying physical surface.
1006      */
1007     @CalledByNative
1008     public int getPhysicalBackingWidthPix() { return mPhysicalBackingWidthPix; }
1009
1010     /**
1011      * @return Height of underlying physical surface.
1012      */
1013     @CalledByNative
1014     public int getPhysicalBackingHeightPix() { return mPhysicalBackingHeightPix; }
1015
1016     /**
1017      * @return Amount the output surface extends past the bottom of the window viewport.
1018      */
1019     @CalledByNative
1020     public int getOverdrawBottomHeightPix() { return mOverdrawBottomHeightPix; }
1021
1022     /**
1023      * @return The amount to shrink the viewport relative to {@link #getViewportWidthPix()}.
1024      */
1025     @CalledByNative
1026     public int getViewportSizeOffsetWidthPix() { return mViewportSizeOffsetWidthPix; }
1027
1028     /**
1029      * @return The amount to shrink the viewport relative to {@link #getViewportHeightPix()}.
1030      */
1031     @CalledByNative
1032     public int getViewportSizeOffsetHeightPix() { return mViewportSizeOffsetHeightPix; }
1033
1034     /**
1035      * @see android.webkit.WebView#getContentHeight()
1036      */
1037     public float getContentHeightCss() {
1038         return mRenderCoordinates.getContentHeightCss();
1039     }
1040
1041     /**
1042      * @see android.webkit.WebView#getContentWidth()
1043      */
1044     public float getContentWidthCss() {
1045         return mRenderCoordinates.getContentWidthCss();
1046     }
1047
1048     // TODO(teddchoc): Remove all these navigation controller methods from here and have the
1049     //                 embedders manage it.
1050     /**
1051      * @return Whether the current WebContents has a previous navigation entry.
1052      */
1053     public boolean canGoBack() {
1054         return mWebContents != null && mWebContents.getNavigationController().canGoBack();
1055     }
1056
1057     /**
1058      * @return Whether the current WebContents has a navigation entry after the current one.
1059      */
1060     public boolean canGoForward() {
1061         return mWebContents != null && mWebContents.getNavigationController().canGoForward();
1062     }
1063
1064     /**
1065      * @param offset The offset into the navigation history.
1066      * @return Whether we can move in history by given offset
1067      */
1068     public boolean canGoToOffset(int offset) {
1069         return mWebContents != null &&
1070                 mWebContents.getNavigationController().canGoToOffset(offset);
1071     }
1072
1073     /**
1074      * Navigates to the specified offset from the "current entry". Does nothing if the offset is out
1075      * of bounds.
1076      * @param offset The offset into the navigation history.
1077      */
1078     public void goToOffset(int offset) {
1079         if (mWebContents != null) mWebContents.getNavigationController().goToOffset(offset);
1080     }
1081
1082     @Override
1083     public void goToNavigationIndex(int index) {
1084         if (mWebContents != null) {
1085             mWebContents.getNavigationController().goToNavigationIndex(index);
1086         }
1087     }
1088
1089     /**
1090      * Goes to the navigation entry before the current one.
1091      */
1092     public void goBack() {
1093         if (mWebContents != null) mWebContents.getNavigationController().goBack();
1094     }
1095
1096     /**
1097      * Goes to the navigation entry following the current one.
1098      */
1099     public void goForward() {
1100         if (mWebContents != null) mWebContents.getNavigationController().goForward();
1101     }
1102
1103     /**
1104      * Loads the current navigation if there is a pending lazy load (after tab restore).
1105      */
1106     public void loadIfNecessary() {
1107         if (mNativeContentViewCore != 0) nativeLoadIfNecessary(mNativeContentViewCore);
1108     }
1109
1110     /**
1111      * Requests the current navigation to be loaded upon the next call to loadIfNecessary().
1112      */
1113     public void requestRestoreLoad() {
1114         if (mNativeContentViewCore != 0) nativeRequestRestoreLoad(mNativeContentViewCore);
1115     }
1116
1117     /**
1118      * Reload the current page.
1119      */
1120     public void reload(boolean checkForRepost) {
1121         mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary();
1122         if (mNativeContentViewCore != 0) {
1123             nativeReload(mNativeContentViewCore, checkForRepost);
1124         }
1125     }
1126
1127     /**
1128      * Reload the current page, ignoring the contents of the cache.
1129      */
1130     public void reloadIgnoringCache(boolean checkForRepost) {
1131         mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary();
1132         if (mNativeContentViewCore != 0) {
1133             nativeReloadIgnoringCache(mNativeContentViewCore, checkForRepost);
1134         }
1135     }
1136
1137     /**
1138      * Cancel the pending reload.
1139      */
1140     public void cancelPendingReload() {
1141         if (mNativeContentViewCore != 0) nativeCancelPendingReload(mNativeContentViewCore);
1142     }
1143
1144     /**
1145      * Continue the pending reload.
1146      */
1147     public void continuePendingReload() {
1148         if (mNativeContentViewCore != 0) nativeContinuePendingReload(mNativeContentViewCore);
1149     }
1150
1151     /**
1152      * Clears the ContentViewCore's page history in both the backwards and
1153      * forwards directions.
1154      */
1155     public void clearHistory() {
1156         if (mNativeContentViewCore != 0) nativeClearHistory(mNativeContentViewCore);
1157     }
1158
1159     /**
1160      * @return The selected text (empty if no text selected).
1161      */
1162     public String getSelectedText() {
1163         return mHasSelection ? mLastSelectedText : "";
1164     }
1165
1166     /**
1167      * @return Whether the current selection is editable (false if no text selected).
1168      */
1169     public boolean isSelectionEditable() {
1170         return mHasSelection ? mSelectionEditable : false;
1171     }
1172
1173     // End FrameLayout overrides.
1174
1175     /**
1176      * @see View#onTouchEvent(MotionEvent)
1177      */
1178     public boolean onTouchEvent(MotionEvent event) {
1179         cancelRequestToScrollFocusedEditableNodeIntoView();
1180
1181         if (!mRequestedVSyncForInput) {
1182             mRequestedVSyncForInput = true;
1183             addVSyncSubscriber();
1184         }
1185
1186         final int eventAction = event.getActionMasked();
1187
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) {
1197             return false;
1198         }
1199
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);
1210     }
1211
1212     public void setIgnoreRemainingTouchEvents() {
1213         if (mNativeContentViewCore == 0) return;
1214         nativeIgnoreRemainingTouchEvents(mNativeContentViewCore);
1215     }
1216
1217     public boolean isScrollInProgress() {
1218         return mTouchScrollInProgress || mPotentiallyActiveFlingCount > 0;
1219     }
1220
1221     @SuppressWarnings("unused")
1222     @CalledByNative
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());
1231         }
1232     }
1233
1234     @SuppressWarnings("unused")
1235     @CalledByNative
1236     private void onFlingStartEventHadNoConsumer(int vx, int vy) {
1237         mTouchScrollInProgress = false;
1238         for (mGestureStateListenersIterator.rewind();
1239                     mGestureStateListenersIterator.hasNext();) {
1240             mGestureStateListenersIterator.next().onUnhandledFlingStartEvent(vx, vy);
1241         }
1242     }
1243
1244     @SuppressWarnings("unused")
1245     @CalledByNative
1246     private void onFlingCancelEventAck() {
1247         updateGestureStateListener(GestureEventType.FLING_CANCEL);
1248     }
1249
1250     @SuppressWarnings("unused")
1251     @CalledByNative
1252     private void onScrollBeginEventAck() {
1253         mTouchScrollInProgress = true;
1254         temporarilyHideTextHandles();
1255         mZoomControlsDelegate.invokeZoomPicker();
1256         updateGestureStateListener(GestureEventType.SCROLL_START);
1257     }
1258
1259     @SuppressWarnings("unused")
1260     @CalledByNative
1261     private void onScrollUpdateGestureConsumed() {
1262         mZoomControlsDelegate.invokeZoomPicker();
1263         for (mGestureStateListenersIterator.rewind();
1264                 mGestureStateListenersIterator.hasNext();) {
1265             mGestureStateListenersIterator.next().onScrollUpdateGestureConsumed();
1266         }
1267     }
1268
1269     @SuppressWarnings("unused")
1270     @CalledByNative
1271     private void onScrollEndEventAck() {
1272         mTouchScrollInProgress = false;
1273         updateGestureStateListener(GestureEventType.SCROLL_END);
1274     }
1275
1276     @SuppressWarnings("unused")
1277     @CalledByNative
1278     private void onPinchBeginEventAck() {
1279         temporarilyHideTextHandles();
1280         updateGestureStateListener(GestureEventType.PINCH_BEGIN);
1281     }
1282
1283     @SuppressWarnings("unused")
1284     @CalledByNative
1285     private void onPinchEndEventAck() {
1286         updateGestureStateListener(GestureEventType.PINCH_END);
1287     }
1288
1289     @SuppressWarnings("unused")
1290     @CalledByNative
1291     private void onDoubleTapEventAck() {
1292         temporarilyHideTextHandles();
1293     }
1294
1295     /**
1296      * Called just prior to a tap or press gesture being forwarded to the renderer.
1297      */
1298     @SuppressWarnings("unused")
1299     @CalledByNative
1300     private boolean filterTapOrPressEvent(int type, int x, int y) {
1301         if (type == GestureEventType.LONG_PRESS && offerLongPressToEmbedder()) {
1302             return true;
1303         }
1304         updateForTapOrPress(type, x, y);
1305         return false;
1306     }
1307
1308     @VisibleForTesting
1309     public void sendDoubleTapForTest(long timeMs, int x, int y) {
1310         if (mNativeContentViewCore == 0) return;
1311         nativeDoubleTap(mNativeContentViewCore, timeMs, x, y);
1312     }
1313
1314     @VisibleForTesting
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);
1320     }
1321
1322     /**
1323      * Add a listener that gets alerted on gesture state changes.
1324      * @param listener Listener to add.
1325      */
1326     public void addGestureStateListener(GestureStateListener listener) {
1327         mGestureStateListeners.addObserver(listener);
1328     }
1329
1330     /**
1331      * Removes a listener that was added to watch for gesture state changes.
1332      * @param listener Listener to remove.
1333      */
1334     public void removeGestureStateListener(GestureStateListener listener) {
1335         mGestureStateListeners.removeObserver(listener);
1336     }
1337
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();
1345                     break;
1346                 case GestureEventType.PINCH_END:
1347                     listener.onPinchEnded();
1348                     break;
1349                 case GestureEventType.FLING_END:
1350                     listener.onFlingEndGesture(
1351                             computeVerticalScrollOffset(),
1352                             computeVerticalScrollExtent());
1353                     break;
1354                 case GestureEventType.FLING_CANCEL:
1355                     listener.onFlingCancelGesture();
1356                     break;
1357                 case GestureEventType.SCROLL_START:
1358                     listener.onScrollStarted(
1359                             computeVerticalScrollOffset(),
1360                             computeVerticalScrollExtent());
1361                     break;
1362                 case GestureEventType.SCROLL_END:
1363                     listener.onScrollEnded(
1364                             computeVerticalScrollOffset(),
1365                             computeVerticalScrollExtent());
1366                     break;
1367                 default:
1368                     break;
1369             }
1370         }
1371     }
1372
1373     /** Callback interface for evaluateJavaScript(). */
1374     public interface JavaScriptCallback {
1375         void handleJavaScriptResult(String jsonResult);
1376     }
1377
1378     /**
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.
1382      *
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.
1388      */
1389     public void evaluateJavaScript(String script, JavaScriptCallback callback) {
1390         if (mNativeContentViewCore == 0) return;
1391         nativeEvaluateJavaScript(mNativeContentViewCore, script, callback, false);
1392     }
1393
1394     /**
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.
1397      *
1398      * @param script The Javascript to execute.
1399      */
1400     public void evaluateJavaScriptEvenIfNotYetNavigated(String script) {
1401         if (mNativeContentViewCore == 0) return;
1402         nativeEvaluateJavaScript(mNativeContentViewCore, script, null, true);
1403     }
1404
1405     /**
1406      * To be called when the ContentView is shown.
1407      */
1408     public void onShow() {
1409         assert mNativeContentViewCore != 0;
1410         if (!mInForeground) {
1411             ChildProcessLauncher.getBindingManager().setInForeground(getCurrentRenderProcessId(),
1412                     true);
1413         }
1414         mInForeground = true;
1415         nativeOnShow(mNativeContentViewCore);
1416         setAccessibilityState(mAccessibilityManager.isEnabled());
1417     }
1418
1419     /**
1420      * @return The ID of the renderer process that backs this tab or
1421      *         {@link #INVALID_RENDER_PROCESS_PID} if there is none.
1422      */
1423     public int getCurrentRenderProcessId() {
1424         return nativeGetCurrentRenderProcessId(mNativeContentViewCore);
1425     }
1426
1427     /**
1428      * To be called when the ContentView is hidden.
1429      */
1430     public void onHide() {
1431         assert mNativeContentViewCore != 0;
1432         if (mInForeground) {
1433             ChildProcessLauncher.getBindingManager().setInForeground(getCurrentRenderProcessId(),
1434                     false);
1435         }
1436         mInForeground = false;
1437         hidePopupDialog();
1438         setInjectedAccessibility(false);
1439         nativeOnHide(mNativeContentViewCore);
1440     }
1441
1442     /**
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.
1447      */
1448     public ContentSettings getContentSettings() {
1449         return mContentSettings;
1450     }
1451
1452     private void onRenderCoordinatesUpdated() {
1453         if (mNativeContentViewCore == 0) return;
1454
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());
1462     }
1463
1464     private void hidePopupDialog() {
1465         if (mSelectPopupDialog != null) {
1466             mSelectPopupDialog.hide();
1467             mSelectPopupDialog = null;
1468         }
1469         hideHandles();
1470         hideSelectActionBar();
1471     }
1472
1473     void hideSelectActionBar() {
1474         if (mActionMode != null) {
1475             mActionMode.finish();
1476             mActionMode = null;
1477         }
1478     }
1479
1480     public boolean isSelectActionBarShowing() {
1481         return mActionMode != null;
1482     }
1483
1484     private void resetGestureDetectors() {
1485         if (mNativeContentViewCore == 0) return;
1486         nativeResetGestureDetectors(mNativeContentViewCore);
1487     }
1488
1489     /**
1490      * @see View#onAttachedToWindow()
1491      */
1492     @SuppressWarnings("javadoc")
1493     public void onAttachedToWindow() {
1494         setAccessibilityState(mAccessibilityManager.isEnabled());
1495
1496         ScreenOrientationListener.getInstance().addObserver(this, mContext);
1497     }
1498
1499     /**
1500      * @see View#onDetachedFromWindow()
1501      */
1502     @SuppressWarnings("javadoc")
1503     @SuppressLint("MissingSuperCall")
1504     public void onDetachedFromWindow() {
1505         setInjectedAccessibility(false);
1506         hidePopupDialog();
1507         mZoomControlsDelegate.dismissZoomPicker();
1508         unregisterAccessibilityContentObserver();
1509
1510         ScreenOrientationListener.getInstance().removeObserver(this);
1511     }
1512
1513     /**
1514      * @see View#onVisibilityChanged(android.view.View, int)
1515      */
1516     public void onVisibilityChanged(View changedView, int visibility) {
1517         if (visibility != View.VISIBLE) {
1518             mZoomControlsDelegate.dismissZoomPicker();
1519         }
1520     }
1521
1522     /**
1523      * @see View#onCreateInputConnection(EditorInfo)
1524      */
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;
1531         }
1532         mInputConnection = mAdapterInputConnectionFactory.get(mContainerView, mImeAdapter,
1533                 mEditable, outAttrs);
1534         return mInputConnection;
1535     }
1536
1537     @VisibleForTesting
1538     public AdapterInputConnection getAdapterInputConnectionForTest() {
1539         return mInputConnection;
1540     }
1541
1542     @VisibleForTesting
1543     public Editable getEditableForTest() {
1544         return mEditable;
1545     }
1546
1547     /**
1548      * @see View#onCheckIsTextEditor()
1549      */
1550     public boolean onCheckIsTextEditor() {
1551         return mImeAdapter.hasTextInputType();
1552     }
1553
1554     /**
1555      * @see View#onConfigurationChanged(Configuration)
1556      */
1557     @SuppressWarnings("javadoc")
1558     public void onConfigurationChanged(Configuration newConfig) {
1559         TraceEvent.begin();
1560
1561         if (newConfig.keyboard != Configuration.KEYBOARD_NOKEYS) {
1562             mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore),
1563                     ImeAdapter.getTextInputTypeNone());
1564             mInputMethodManagerWrapper.restartInput(mContainerView);
1565         }
1566         mContainerViewInternals.super_onConfigurationChanged(newConfig);
1567
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();
1571         TraceEvent.end();
1572     }
1573
1574     /**
1575      * @see View#onSizeChanged(int, int, int, int)
1576      */
1577     @SuppressWarnings("javadoc")
1578     public void onSizeChanged(int wPix, int hPix, int owPix, int ohPix) {
1579         if (getViewportWidthPix() == wPix && getViewportHeightPix() == hPix) return;
1580
1581         mViewportWidthPix = wPix;
1582         mViewportHeightPix = hPix;
1583         if (mNativeContentViewCore != 0) {
1584             nativeWasResized(mNativeContentViewCore);
1585         }
1586
1587         updateAfterSizeChanged();
1588     }
1589
1590     /**
1591      * Called when the ContentView's position in the activity window changed. This information is
1592      * used for cropping screenshots.
1593      */
1594     public void onLocationInWindowChanged(int x, int y) {
1595         mLocationInWindowX = x;
1596         mLocationInWindowY = y;
1597     }
1598
1599     /**
1600      * Called when the underlying surface the compositor draws to changes size.
1601      * This may be larger than the viewport size.
1602      */
1603     public void onPhysicalBackingSizeChanged(int wPix, int hPix) {
1604         if (mPhysicalBackingWidthPix == wPix && mPhysicalBackingHeightPix == hPix) return;
1605
1606         mPhysicalBackingWidthPix = wPix;
1607         mPhysicalBackingHeightPix = hPix;
1608
1609         if (mNativeContentViewCore != 0) {
1610             nativeWasResized(mNativeContentViewCore);
1611         }
1612     }
1613
1614     /**
1615      * Called when the amount the surface is overdrawing off the bottom has changed.
1616      * @param overdrawHeightPix The overdraw height.
1617      */
1618     public void onOverdrawBottomHeightChanged(int overdrawHeightPix) {
1619         if (mOverdrawBottomHeightPix == overdrawHeightPix) return;
1620
1621         mOverdrawBottomHeightPix = overdrawHeightPix;
1622
1623         if (mNativeContentViewCore != 0) {
1624             nativeWasResized(mNativeContentViewCore);
1625         }
1626     }
1627
1628     private void updateAfterSizeChanged() {
1629         mPopupZoomer.hide(false);
1630
1631         // Execute a delayed form focus operation because the OSK was brought
1632         // up earlier.
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();
1640                 }
1641                 cancelRequestToScrollFocusedEditableNodeIntoView();
1642             }
1643         }
1644     }
1645
1646     private void cancelRequestToScrollFocusedEditableNodeIntoView() {
1647         // Zero-ing the rect will prevent |updateAfterSizeChanged()| from
1648         // issuing the delayed form focus event.
1649         mFocusPreOSKViewportRect.setEmpty();
1650     }
1651
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);
1658     }
1659
1660     /**
1661      * @see View#onWindowFocusChanged(boolean)
1662      */
1663     public void onWindowFocusChanged(boolean hasWindowFocus) {
1664         if (!hasWindowFocus) {
1665             if (mNativeContentViewCore == 0) return;
1666             nativeOnWindowFocusLost(mNativeContentViewCore);
1667         }
1668     }
1669
1670     public void onFocusChanged(boolean gainFocus) {
1671         if (!gainFocus) {
1672             hideImeIfNeeded();
1673         }
1674         if (mNativeContentViewCore != 0) nativeSetFocus(mNativeContentViewCore, gainFocus);
1675     }
1676
1677     /**
1678      * @see View#onKeyUp(int, KeyEvent)
1679      */
1680     public boolean onKeyUp(int keyCode, KeyEvent event) {
1681         if (mPopupZoomer.isShowing() && keyCode == KeyEvent.KEYCODE_BACK) {
1682             mPopupZoomer.hide(true);
1683             return true;
1684         }
1685         return mContainerViewInternals.super_onKeyUp(keyCode, event);
1686     }
1687
1688     /**
1689      * @see View#dispatchKeyEventPreIme(KeyEvent)
1690      */
1691     public boolean dispatchKeyEventPreIme(KeyEvent event) {
1692         try {
1693             TraceEvent.begin();
1694             return mContainerViewInternals.super_dispatchKeyEventPreIme(event);
1695         } finally {
1696             TraceEvent.end();
1697         }
1698     }
1699
1700     /**
1701      * @see View#dispatchKeyEvent(KeyEvent)
1702      */
1703     public boolean dispatchKeyEvent(KeyEvent event) {
1704         if (getContentViewClient().shouldOverrideKeyEvent(event)) {
1705             return mContainerViewInternals.super_dispatchKeyEvent(event);
1706         }
1707
1708         if (mImeAdapter.dispatchKeyEvent(event)) return true;
1709
1710         return mContainerViewInternals.super_dispatchKeyEvent(event);
1711     }
1712
1713     /**
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.
1718      */
1719     public boolean onHoverEvent(MotionEvent event) {
1720         TraceEvent.begin("onHoverEvent");
1721
1722         if (mBrowserAccessibilityManager != null) {
1723             return mBrowserAccessibilityManager.onHoverEvent(event);
1724         }
1725
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) {
1729             return true;
1730         }
1731
1732         mContainerView.removeCallbacks(mFakeMouseMoveRunnable);
1733         if (mNativeContentViewCore != 0) {
1734             nativeSendMouseMoveEvent(mNativeContentViewCore, event.getEventTime(),
1735                     event.getX(), event.getY());
1736         }
1737         TraceEvent.end("onHoverEvent");
1738         return true;
1739     }
1740
1741     /**
1742      * @see View#onGenericMotionEvent(MotionEvent)
1743      */
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));
1751
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() {
1757                         @Override
1758                         public void run() {
1759                             onHoverEvent(eventFakeMouseMove);
1760                         }
1761                     };
1762                     mContainerView.postDelayed(mFakeMouseMoveRunnable, 250);
1763                     return true;
1764             }
1765         }
1766         return mContainerViewInternals.super_onGenericMotionEvent(event);
1767     }
1768
1769     /**
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.
1775      */
1776     public void scrollBy(int xPix, int yPix) {
1777         if (mNativeContentViewCore != 0) {
1778             nativeScrollBy(mNativeContentViewCore,
1779                     SystemClock.uptimeMillis(), 0, 0, xPix, yPix);
1780         }
1781     }
1782
1783     /**
1784      * @see View#scrollTo(int, int)
1785      */
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);
1799         }
1800     }
1801
1802     // NOTE: this can go away once ContentView.getScrollX() reports correct values.
1803     //       see: b/6029133
1804     public int getNativeScrollXForTest() {
1805         return mRenderCoordinates.getScrollXPixInt();
1806     }
1807
1808     // NOTE: this can go away once ContentView.getScrollY() reports correct values.
1809     //       see: b/6029133
1810     public int getNativeScrollYForTest() {
1811         return mRenderCoordinates.getScrollYPixInt();
1812     }
1813
1814     /**
1815      * @see View#computeHorizontalScrollExtent()
1816      */
1817     @SuppressWarnings("javadoc")
1818     public int computeHorizontalScrollExtent() {
1819         return mRenderCoordinates.getLastFrameViewportWidthPixInt();
1820     }
1821
1822     /**
1823      * @see View#computeHorizontalScrollOffset()
1824      */
1825     @SuppressWarnings("javadoc")
1826     public int computeHorizontalScrollOffset() {
1827         return mRenderCoordinates.getScrollXPixInt();
1828     }
1829
1830     /**
1831      * @see View#computeHorizontalScrollRange()
1832      */
1833     @SuppressWarnings("javadoc")
1834     public int computeHorizontalScrollRange() {
1835         return mRenderCoordinates.getContentWidthPixInt();
1836     }
1837
1838     /**
1839      * @see View#computeVerticalScrollExtent()
1840      */
1841     @SuppressWarnings("javadoc")
1842     public int computeVerticalScrollExtent() {
1843         return mRenderCoordinates.getLastFrameViewportHeightPixInt();
1844     }
1845
1846     /**
1847      * @see View#computeVerticalScrollOffset()
1848      */
1849     @SuppressWarnings("javadoc")
1850     public int computeVerticalScrollOffset() {
1851         return mRenderCoordinates.getScrollYPixInt();
1852     }
1853
1854     /**
1855      * @see View#computeVerticalScrollRange()
1856      */
1857     @SuppressWarnings("javadoc")
1858     public int computeVerticalScrollRange() {
1859         return mRenderCoordinates.getContentHeightPixInt();
1860     }
1861
1862     // End FrameLayout overrides.
1863
1864     /**
1865      * @see View#awakenScrollBars(int, boolean)
1866      */
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) {
1873             return false;
1874         } else {
1875             return mContainerViewInternals.super_awakenScrollBars(startDelay, invalidate);
1876         }
1877     }
1878
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) {
1884             return;
1885         }
1886
1887         if (mContainerView.isFocusable() && mContainerView.isFocusableInTouchMode()
1888                 && !mContainerView.isFocused())  {
1889             mContainerView.requestFocus();
1890         }
1891
1892         if (!mPopupZoomer.isShowing()) mPopupZoomer.setLastTouch(xPix, yPix);
1893
1894         if (type == GestureEventType.LONG_PRESS
1895                 || type == GestureEventType.LONG_TAP) {
1896             getInsertionHandleController().allowAutomaticShowing();
1897             getSelectionHandleController().allowAutomaticShowing();
1898         } else {
1899             setClickXAndY((int) xPix, (int) yPix);
1900             if (mSelectionEditable) getInsertionHandleController().allowAutomaticShowing();
1901         }
1902     }
1903
1904     private void setClickXAndY(int x, int y) {
1905         mSingleTapX = x;
1906         mSingleTapY = y;
1907     }
1908
1909     /**
1910      * @return The x coordinate for the last point that a singleTap gesture was initiated from.
1911      */
1912     public int getSingleTapX()  {
1913         return mSingleTapX;
1914     }
1915
1916     /**
1917      * @return The y coordinate for the last point that a singleTap gesture was initiated from.
1918      */
1919     public int getSingleTapY()  {
1920         return mSingleTapY;
1921     }
1922
1923     public void setZoomControlsDelegate(ZoomControlsDelegate zoomControlsDelegate) {
1924         mZoomControlsDelegate = zoomControlsDelegate;
1925     }
1926
1927     public void updateMultiTouchZoomSupport(boolean supportsMultiTouchZoom) {
1928         if (mNativeContentViewCore == 0) return;
1929         nativeSetMultiTouchZoomSupportEnabled(mNativeContentViewCore, supportsMultiTouchZoom);
1930     }
1931
1932     public void updateDoubleTapSupport(boolean supportsDoubleTap) {
1933         if (mNativeContentViewCore == 0) return;
1934         nativeSetDoubleTapSupportEnabled(mNativeContentViewCore, supportsDoubleTap);
1935     }
1936
1937     public void selectPopupMenuItems(int[] indices) {
1938         if (mNativeContentViewCore != 0) {
1939             nativeSelectPopupMenuItems(mNativeContentViewCore, indices);
1940         }
1941         mSelectPopupDialog = null;
1942     }
1943
1944     /**
1945      * Send the screen orientation value to the renderer.
1946      */
1947     @VisibleForTesting
1948     void sendOrientationChangeEvent(int orientation) {
1949         if (mNativeContentViewCore == 0) return;
1950
1951         nativeSendOrientationChangeEvent(mNativeContentViewCore, orientation);
1952     }
1953
1954     /**
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.
1959      */
1960     public void setDownloadDelegate(ContentViewDownloadDelegate delegate) {
1961         mDownloadDelegate = delegate;
1962     }
1963
1964     // Called by DownloadController.
1965     ContentViewDownloadDelegate getDownloadDelegate() {
1966         return mDownloadDelegate;
1967     }
1968
1969     private SelectionHandleController getSelectionHandleController() {
1970         if (mSelectionHandleController == null) {
1971             mSelectionHandleController = new SelectionHandleController(
1972                     getContainerView(), mPositionObserver) {
1973                 @Override
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());
1979                     }
1980                 }
1981
1982                 @Override
1983                 public void showHandles(int startDir, int endDir) {
1984                     super.showHandles(startDir, endDir);
1985                     showSelectActionBar();
1986                 }
1987
1988             };
1989
1990             mSelectionHandleController.hideAndDisallowAutomaticShowing();
1991             updateInsertionSelectionVisibleBounds();
1992         }
1993
1994         return mSelectionHandleController;
1995     }
1996
1997     private InsertionHandleController getInsertionHandleController() {
1998         if (mInsertionHandleController == null) {
1999             mInsertionHandleController = new InsertionHandleController(
2000                     getContainerView(), mPositionObserver) {
2001                 private static final int AVERAGE_LINE_HEIGHT = 14;
2002
2003                 @Override
2004                 public void setCursorPosition(int x, int y) {
2005                     if (mNativeContentViewCore != 0) {
2006                         nativeMoveCaret(mNativeContentViewCore,
2007                                 x, y - mRenderCoordinates.getContentOffsetYPix());
2008                     }
2009                 }
2010
2011                 @Override
2012                 public void paste() {
2013                     mImeAdapter.paste();
2014                     hideHandles();
2015                 }
2016
2017                 @Override
2018                 public int getLineHeight() {
2019                     return (int) Math.ceil(
2020                             mRenderCoordinates.fromLocalCssToPix(AVERAGE_LINE_HEIGHT));
2021                 }
2022
2023                 @Override
2024                 public void showHandle() {
2025                     super.showHandle();
2026                 }
2027             };
2028
2029             mInsertionHandleController.hideAndDisallowAutomaticShowing();
2030             updateInsertionSelectionVisibleBounds();
2031         }
2032
2033         return mInsertionHandleController;
2034     }
2035
2036     @VisibleForTesting
2037     public InsertionHandleController getInsertionHandleControllerForTest() {
2038         return mInsertionHandleController;
2039     }
2040
2041     @VisibleForTesting
2042     public SelectionHandleController getSelectionHandleControllerForTest() {
2043         return mSelectionHandleController;
2044     }
2045
2046     private void updateHandleScreenPositions() {
2047         if (isSelectionHandleShowing()) {
2048             mSelectionHandleController.setStartHandlePosition(
2049                     mStartHandlePoint.getXPix(), mStartHandlePoint.getYPix());
2050             mSelectionHandleController.setEndHandlePosition(
2051                     mEndHandlePoint.getXPix(), mEndHandlePoint.getYPix());
2052         }
2053
2054         if (isInsertionHandleShowing()) {
2055             mInsertionHandleController.setHandlePosition(
2056                     mInsertionHandlePoint.getXPix(), mInsertionHandlePoint.getYPix());
2057         }
2058     }
2059
2060     private void hideHandles() {
2061         if (mSelectionHandleController != null) {
2062             mSelectionHandleController.hideAndDisallowAutomaticShowing();
2063         }
2064         if (mInsertionHandleController != null) {
2065             mInsertionHandleController.hideAndDisallowAutomaticShowing();
2066         }
2067         mPositionObserver.removeListener(mPositionListener);
2068     }
2069
2070     private void showSelectActionBar() {
2071         if (mActionMode != null) {
2072             mActionMode.invalidate();
2073             return;
2074         }
2075
2076         // Start a new action mode with a SelectActionModeCallback.
2077         SelectActionModeCallback.ActionHandler actionHandler =
2078                 new SelectActionModeCallback.ActionHandler() {
2079             @Override
2080             public void selectAll() {
2081                 mImeAdapter.selectAll();
2082             }
2083
2084             @Override
2085             public void cut() {
2086                 mImeAdapter.cut();
2087             }
2088
2089             @Override
2090             public void copy() {
2091                 mImeAdapter.copy();
2092             }
2093
2094             @Override
2095             public void paste() {
2096                 mImeAdapter.paste();
2097             }
2098
2099             @Override
2100             public void share() {
2101                 final String query = getSelectedText();
2102                 if (TextUtils.isEmpty(query)) return;
2103
2104                 Intent send = new Intent(Intent.ACTION_SEND);
2105                 send.setType("text/plain");
2106                 send.putExtra(Intent.EXTRA_TEXT, query);
2107                 try {
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.
2114                 }
2115             }
2116
2117             @Override
2118             public void search() {
2119                 final String query = getSelectedText();
2120                 if (TextUtils.isEmpty(query)) return;
2121
2122                 // See if ContentViewClient wants to override
2123                 if (getContentViewClient().doesPerformWebSearch()) {
2124                     getContentViewClient().performWebSearch(query);
2125                     return;
2126                 }
2127
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);
2134                 }
2135                 try {
2136                     getContext().startActivity(i);
2137                 } catch (android.content.ActivityNotFoundException ex) {
2138                     // If no app handles it, do nothing.
2139                 }
2140             }
2141
2142             @Override
2143             public boolean isSelectionEditable() {
2144                 return mSelectionEditable;
2145             }
2146
2147             @Override
2148             public void onDestroyActionMode() {
2149                 mActionMode = null;
2150                 if (mUnselectAllOnActionModeDismiss) mImeAdapter.unselect();
2151                 getContentViewClient().onContextualActionBarHidden();
2152             }
2153
2154             @Override
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;
2160             }
2161
2162             @Override
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;
2169             }
2170         };
2171         mActionMode = null;
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)));
2177         }
2178         mUnselectAllOnActionModeDismiss = true;
2179         if (mActionMode == null) {
2180             // There is no ActionMode, so remove the selection.
2181             mImeAdapter.unselect();
2182         } else {
2183             getContentViewClient().onContextualActionBarShown();
2184         }
2185     }
2186
2187     public boolean getUseDesktopUserAgent() {
2188         if (mNativeContentViewCore != 0) {
2189             return nativeGetUseDesktopUserAgent(mNativeContentViewCore);
2190         }
2191         return false;
2192     }
2193
2194     /**
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.
2198      */
2199     public void setUseDesktopUserAgent(boolean override, boolean reloadOnChange) {
2200         if (mNativeContentViewCore != 0) {
2201             nativeSetUseDesktopUserAgent(mNativeContentViewCore, override, reloadOnChange);
2202         }
2203     }
2204
2205     public void clearSslPreferences() {
2206         nativeClearSslPreferences(mNativeContentViewCore);
2207     }
2208
2209     private boolean isSelectionHandleShowing() {
2210         return mSelectionHandleController != null && mSelectionHandleController.isShowing();
2211     }
2212
2213     private boolean isInsertionHandleShowing() {
2214         return mInsertionHandleController != null && mInsertionHandleController.isShowing();
2215     }
2216
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);
2222         }
2223         if (isInsertionHandleShowing() && !mInsertionHandleController.isDragging()) {
2224             mInsertionHandleController.setHandleVisibility(HandleView.INVISIBLE);
2225         }
2226         scheduleTextHandleFadeIn();
2227     }
2228
2229     private boolean allowTextHandleFadeIn() {
2230         if (mTouchScrollInProgress) return false;
2231
2232         if (mPopupZoomer.isShowing()) return false;
2233
2234         return true;
2235     }
2236
2237     // Cancels any pending fade in and schedules a new one.
2238     private void scheduleTextHandleFadeIn() {
2239         if (!isInsertionHandleShowing() && !isSelectionHandleShowing()) return;
2240
2241         if (mDeferredHandleFadeInRunnable == null) {
2242             mDeferredHandleFadeInRunnable = new Runnable() {
2243                 @Override
2244                 public void run() {
2245                     if (!allowTextHandleFadeIn()) {
2246                         // Delay fade in until it is allowed.
2247                         scheduleTextHandleFadeIn();
2248                     } else {
2249                         if (isSelectionHandleShowing()) {
2250                             mSelectionHandleController.beginHandleFadeIn();
2251                         }
2252                         if (isInsertionHandleShowing()) {
2253                             mInsertionHandleController.beginHandleFadeIn();
2254                         }
2255                     }
2256                 }
2257             };
2258         }
2259
2260         mContainerView.removeCallbacks(mDeferredHandleFadeInRunnable);
2261         mContainerView.postDelayed(mDeferredHandleFadeInRunnable, TEXT_HANDLE_FADE_IN_DELAY);
2262     }
2263
2264     /**
2265      * Shows the IME if the focused widget could accept text input.
2266      */
2267     public void showImeIfNeeded() {
2268         if (mNativeContentViewCore != 0) nativeShowImeIfNeeded(mNativeContentViewCore);
2269     }
2270
2271     /**
2272      * Hides the IME if the containerView is the active view for IME.
2273      */
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);
2285         }
2286         getContentViewClient().onImeStateChangeRequested(false);
2287     }
2288
2289     @SuppressWarnings("unused")
2290     @CalledByNative
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));
2305
2306         final float contentOffsetYPix = mRenderCoordinates.fromDipToPix(contentOffsetYCss);
2307
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 =
2317                 pageScaleChanged
2318                 || scrollOffsetX != mRenderCoordinates.getScrollX()
2319                 || scrollOffsetY != mRenderCoordinates.getScrollY();
2320         final boolean contentOffsetChanged =
2321                 contentOffsetYPix != mRenderCoordinates.getContentOffsetYPix();
2322
2323         final boolean needHidePopupZoomer = contentSizeChanged || scrollChanged;
2324         final boolean needUpdateZoomControls = scaleLimitsChanged || scrollChanged;
2325         final boolean needTemporarilyHideHandles = scrollChanged;
2326
2327         if (needHidePopupZoomer) mPopupZoomer.hide(true);
2328
2329         if (scrollChanged) {
2330             mContainerViewInternals.onScrollChanged(
2331                     (int) mRenderCoordinates.fromLocalCssToPix(scrollOffsetX),
2332                     (int) mRenderCoordinates.fromLocalCssToPix(scrollOffsetY),
2333                     (int) mRenderCoordinates.getScrollXPix(),
2334                     (int) mRenderCoordinates.getScrollYPix());
2335         }
2336
2337         mRenderCoordinates.updateFrameInfo(
2338                 scrollOffsetX, scrollOffsetY,
2339                 contentWidth, contentHeight,
2340                 viewportWidth, viewportHeight,
2341                 pageScaleFactor, minPageScaleFactor, maxPageScaleFactor,
2342                 contentOffsetYPix);
2343         onRenderCoordinatesUpdated();
2344
2345         if (scrollChanged || contentOffsetChanged) {
2346             for (mGestureStateListenersIterator.rewind();
2347                     mGestureStateListenersIterator.hasNext();) {
2348                 mGestureStateListenersIterator.next().onScrollOffsetOrExtentChanged(
2349                         computeVerticalScrollOffset(),
2350                         computeVerticalScrollExtent());
2351             }
2352         }
2353
2354         if (needTemporarilyHideHandles) temporarilyHideTextHandles();
2355         if (needUpdateZoomControls) mZoomControlsDelegate.updateZoomControls();
2356         if (contentOffsetChanged) updateHandleScreenPositions();
2357
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);
2364
2365         mPendingRendererFrame = true;
2366         if (mBrowserAccessibilityManager != null) {
2367             mBrowserAccessibilityManager.notifyFrameInfoInitialized();
2368         }
2369     }
2370
2371     @CalledByNative
2372     private void updateImeAdapter(long nativeImeAdapterAndroid, int textInputType,
2373             String text, int selectionStart, int selectionEnd,
2374             int compositionStart, int compositionEnd, boolean showImeIfNeeded, boolean requireAck) {
2375         TraceEvent.begin();
2376         mSelectionEditable = (textInputType != ImeAdapter.getTextInputTypeNone());
2377
2378         if (mActionMode != null) mActionMode.invalidate();
2379
2380         mImeAdapter.attachAndShowIfNeeded(nativeImeAdapterAndroid, textInputType, showImeIfNeeded);
2381
2382         if (mInputConnection != null) {
2383             mInputConnection.updateState(text, selectionStart, selectionEnd, compositionStart,
2384                     compositionEnd, requireAck);
2385         }
2386         TraceEvent.end();
2387     }
2388
2389     @SuppressWarnings("unused")
2390     @CalledByNative
2391     private void setTitle(String title) {
2392         getContentViewClient().onUpdateTitle(title);
2393     }
2394
2395     /**
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.
2401      */
2402     @SuppressWarnings("unused")
2403     @CalledByNative
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);
2408             return;
2409         }
2410
2411         if (mSelectPopupDialog != null) {
2412             mSelectPopupDialog.hide();
2413             mSelectPopupDialog = null;
2414         }
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]));
2419         }
2420         mSelectPopupDialog = SelectPopupDialog.show(this, popupItems, multiple, selectedIndices);
2421     }
2422
2423     /**
2424      * @return The visible select popup dialog being shown.
2425      */
2426     public SelectPopupDialog getSelectPopupForTest() {
2427         return mSelectPopupDialog;
2428     }
2429
2430     @SuppressWarnings("unused")
2431     @CalledByNative
2432     private void showDisambiguationPopup(Rect targetRect, Bitmap zoomedBitmap) {
2433         mPopupZoomer.setBitmap(zoomedBitmap);
2434         mPopupZoomer.show(targetRect);
2435         temporarilyHideTextHandles();
2436     }
2437
2438     @SuppressWarnings("unused")
2439     @CalledByNative
2440     private TouchEventSynthesizer createTouchEventSynthesizer() {
2441         return new TouchEventSynthesizer(this);
2442     }
2443
2444     @SuppressWarnings("unused")
2445     @CalledByNative
2446     private void onSelectionChanged(String text) {
2447         mLastSelectedText = text;
2448         getContentViewClient().onSelectionChanged(text);
2449     }
2450
2451     @SuppressWarnings("unused")
2452     @CalledByNative
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;
2460
2461         if (x1 != x2 || y1 != y2 ||
2462                 (mSelectionHandleController != null && mSelectionHandleController.isDragging())) {
2463             if (mInsertionHandleController != null) {
2464                 mInsertionHandleController.hide();
2465             }
2466             if (isAnchorFirst) {
2467                 mStartHandlePoint.setLocalDip(x1, y1);
2468                 mEndHandlePoint.setLocalDip(x2, y2);
2469             } else {
2470                 mStartHandlePoint.setLocalDip(x2, y2);
2471                 mEndHandlePoint.setLocalDip(x1, y1);
2472             }
2473
2474             boolean wereSelectionHandlesShowing = getSelectionHandleController().isShowing();
2475
2476             getSelectionHandleController().onSelectionChanged(anchorDir, focusDir);
2477             updateHandleScreenPositions();
2478             mHasSelection = true;
2479
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);
2484             }
2485
2486         } else {
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();
2493                 }
2494                 mInsertionHandlePoint.setLocalDip(x1, y1);
2495
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);
2503                 }
2504             } else {
2505                 // Deselection
2506                 if (mSelectionHandleController != null) {
2507                     mSelectionHandleController.hideAndDisallowAutomaticShowing();
2508                 }
2509                 if (mInsertionHandleController != null) {
2510                     mInsertionHandleController.hideAndDisallowAutomaticShowing();
2511                 }
2512             }
2513             mHasSelection = false;
2514         }
2515         if (isSelectionHandleShowing() || isInsertionHandleShowing()) {
2516             mPositionObserver.addListener(mPositionListener);
2517         }
2518     }
2519
2520     @CalledByNative
2521     private void setSelectionRootBounds(Rect bounds) {
2522         mTopLeftVisibilityClippingPoint.setLocalDip(bounds.left, bounds.top);
2523         mBottomRightVisibilityClippingPoint.setLocalDip(bounds.right, bounds.bottom);
2524         updateInsertionSelectionVisibleBounds();
2525     }
2526
2527     private void updateInsertionSelectionVisibleBounds() {
2528         if (mSelectionHandleController == null && mInsertionHandleController == null) {
2529             return;
2530         }
2531
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());
2536
2537         if (mSelectionHandleController != null) {
2538             mSelectionHandleController.setVisibleClippingRectangle(x1, y1, x2, y2);
2539         }
2540
2541         if (mInsertionHandleController != null) {
2542             mInsertionHandleController.setVisibleClippingRectangle(x1, y1, x2, y2);
2543         }
2544     }
2545
2546     @SuppressWarnings("unused")
2547     @CalledByNative
2548     private static void onEvaluateJavaScriptResult(
2549             String jsonResult, JavaScriptCallback callback) {
2550         callback.handleJavaScriptResult(jsonResult);
2551     }
2552
2553     @SuppressWarnings("unused")
2554     @CalledByNative
2555     private void showPastePopup(int xDip, int yDip) {
2556         mInsertionHandlePoint.setLocalDip(xDip, yDip);
2557         getInsertionHandleController().showHandle();
2558         updateHandleScreenPositions();
2559         getInsertionHandleController().showHandleWithPastePopup();
2560     }
2561
2562     @SuppressWarnings("unused")
2563     @CalledByNative
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);
2570         }
2571
2572         attachImeAdapter();
2573     }
2574
2575     @SuppressWarnings("unused")
2576     @CalledByNative
2577     private void onWebContentsConnected() {
2578         attachImeAdapter();
2579     }
2580
2581     /**
2582      * Attaches the native ImeAdapter object to the java ImeAdapter to allow communication via JNI.
2583      */
2584     public void attachImeAdapter() {
2585         if (mImeAdapter != null && mNativeContentViewCore != 0) {
2586             mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore));
2587         }
2588     }
2589
2590     /**
2591      * @see View#hasFocus()
2592      */
2593     @CalledByNative
2594     public boolean hasFocus() {
2595         return mContainerView.hasFocus();
2596     }
2597
2598     /**
2599      * Checks whether the ContentViewCore can be zoomed in.
2600      *
2601      * @return True if the ContentViewCore can be zoomed in.
2602      */
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;
2609     }
2610
2611     /**
2612      * Checks whether the ContentViewCore can be zoomed out.
2613      *
2614      * @return True if the ContentViewCore can be zoomed out.
2615      */
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;
2622     }
2623
2624     /**
2625      * Zooms in the ContentViewCore by 25% (or less if that would result in
2626      * zooming in more than possible).
2627      *
2628      * @return True if there was a zoom change, false otherwise.
2629      */
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() {
2633         if (!canZoomIn()) {
2634             return false;
2635         }
2636         return pinchByDelta(1.25f);
2637     }
2638
2639     /**
2640      * Zooms out the ContentViewCore by 20% (or less if that would result in
2641      * zooming out more than possible).
2642      *
2643      * @return True if there was a zoom change, false otherwise.
2644      */
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()) {
2649             return false;
2650         }
2651         return pinchByDelta(0.8f);
2652     }
2653
2654     /**
2655      * Resets the zoom factor of the ContentViewCore.
2656      *
2657      * @return True if there was a zoom change, false otherwise.
2658      */
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());
2668     }
2669
2670     /**
2671      * Simulate a pinch zoom gesture.
2672      *
2673      * @param delta the factor by which the current page scale should be multiplied by.
2674      * @return whether the gesture was sent.
2675      */
2676     public boolean pinchByDelta(float delta) {
2677         if (mNativeContentViewCore == 0) return false;
2678
2679         long timeMs = SystemClock.uptimeMillis();
2680         int xPix = getViewportWidthPix() / 2;
2681         int yPix = getViewportHeightPix() / 2;
2682
2683         nativePinchBegin(mNativeContentViewCore, timeMs, xPix, yPix);
2684         nativePinchBy(mNativeContentViewCore, timeMs, xPix, yPix, delta);
2685         nativePinchEnd(mNativeContentViewCore, timeMs);
2686
2687         return true;
2688     }
2689
2690     /**
2691      * Invokes the graphical zoom picker widget for this ContentView.
2692      */
2693     public void invokeZoomPicker() {
2694         mZoomControlsDelegate.invokeZoomPicker();
2695     }
2696
2697     /**
2698      * Enables or disables inspection of JavaScript objects added via
2699      * {@link #addJavascriptInterface(Object, String)} by means of Object.keys() method and
2700      * &quot;for .. in&quot; 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.
2703      *
2704      * @param allow Whether to allow JavaScript objects inspection.
2705      */
2706     public void setAllowJavascriptInterfacesInspection(boolean allow) {
2707         nativeSetAllowJavascriptInterfacesInspection(mNativeContentViewCore, allow);
2708     }
2709
2710     /**
2711      * This will mimic {@link #addPossiblyUnsafeJavascriptInterface(Object, String, Class)}
2712      * and automatically pass in {@link JavascriptInterface} as the required annotation.
2713      *
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.
2717      */
2718     public void addJavascriptInterface(Object object, String name) {
2719         addPossiblyUnsafeJavascriptInterface(object, name, JavascriptInterface.class);
2720     }
2721
2722     /**
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>
2732      * <ul>
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>
2752      * </ul></p>
2753      *
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
2758      *                           JavaScript.
2759      * @param requiredAnnotation Restrict exposed methods to ones with this
2760      *                           annotation.  If {@code null} all methods are
2761      *                           exposed.
2762      *
2763      */
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);
2770         }
2771     }
2772
2773     /**
2774      * Removes a previously added JavaScript interface with the given name.
2775      *
2776      * @param name The name of the interface to remove.
2777      */
2778     public void removeJavascriptInterface(String name) {
2779         mJavaScriptInterfaces.remove(name);
2780         if (mNativeContentViewCore != 0) {
2781             nativeRemoveJavascriptInterface(mNativeContentViewCore, name);
2782         }
2783     }
2784
2785     /**
2786      * Return the current scale of the ContentView.
2787      * @return The current page scale factor.
2788      */
2789     public float getScale() {
2790         return mRenderCoordinates.getPageScaleFactor();
2791     }
2792
2793     /**
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.
2798      */
2799     public boolean isReady() {
2800         if (mNativeContentViewCore == 0) return false;
2801         return nativeIsRenderWidgetHostViewReady(mNativeContentViewCore);
2802     }
2803
2804     @CalledByNative
2805     private void startContentIntent(String contentUrl) {
2806         getContentViewClient().onStartContentIntent(getContext(), contentUrl);
2807     }
2808
2809     @Override
2810     public void onAccessibilityStateChanged(boolean enabled) {
2811         setAccessibilityState(enabled);
2812     }
2813
2814     /**
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.
2818      */
2819     public boolean supportsAccessibilityAction(int action) {
2820         return mAccessibilityInjector.supportsAccessibilityAction(action);
2821     }
2822
2823     /**
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.
2832      */
2833     public boolean performAccessibilityAction(int action, Bundle arguments) {
2834         if (mAccessibilityInjector.supportsAccessibilityAction(action)) {
2835             return mAccessibilityInjector.performAccessibilityAction(action, arguments);
2836         }
2837
2838         return false;
2839     }
2840
2841     /**
2842      * Set the BrowserAccessibilityManager, used for native accessibility
2843      * (not script injection). This is only set when system accessibility
2844      * has been enabled.
2845      * @param manager The new BrowserAccessibilityManager.
2846      */
2847     public void setBrowserAccessibilityManager(BrowserAccessibilityManager manager) {
2848         mBrowserAccessibilityManager = manager;
2849     }
2850
2851     /**
2852      * Get the BrowserAccessibilityManager, used for native accessibility
2853      * (not script injection). This will return null when system accessibility
2854      * is not enabled.
2855      * @return This view's BrowserAccessibilityManager.
2856      */
2857     public BrowserAccessibilityManager getBrowserAccessibilityManager() {
2858         return mBrowserAccessibilityManager;
2859     }
2860
2861     /**
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.
2867      */
2868     public AccessibilityNodeProvider getAccessibilityNodeProvider() {
2869         if (mBrowserAccessibilityManager != null) {
2870             return mBrowserAccessibilityManager.getAccessibilityNodeProvider();
2871         }
2872
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);
2879         }
2880
2881         return null;
2882     }
2883
2884     /**
2885      * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
2886      */
2887     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
2888         // Note: this is only used by the script-injecting accessibility code.
2889         mAccessibilityInjector.onInitializeAccessibilityNodeInfo(info);
2890     }
2891
2892     /**
2893      * @see View#onInitializeAccessibilityEvent(AccessibilityEvent)
2894      */
2895     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
2896         // Note: this is only used by the script-injecting accessibility code.
2897         event.setClassName(this.getClass().getName());
2898
2899         // Identify where the top-left of the screen currently points to.
2900         event.setScrollX(mRenderCoordinates.getScrollXPixInt());
2901         event.setScrollY(mRenderCoordinates.getScrollYPixInt());
2902
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);
2908
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);
2914         }
2915     }
2916
2917     /**
2918      * Returns whether accessibility script injection is enabled on the device
2919      */
2920     public boolean isDeviceAccessibilityScriptInjectionEnabled() {
2921         try {
2922             if (!CommandLine.getInstance().hasSwitch(
2923                     ContentSwitches.ENABLE_ACCESSIBILITY_SCRIPT_INJECTION)) {
2924                 return false;
2925             }
2926
2927             if (!mContentSettings.getJavaScriptEnabled()) {
2928                 return false;
2929             }
2930
2931             int result = getContext().checkCallingOrSelfPermission(
2932                     android.Manifest.permission.INTERNET);
2933             if (result != PackageManager.PERMISSION_GRANTED) {
2934                 return false;
2935             }
2936
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();
2941
2942             if (mAccessibilityScriptInjectionObserver == null) {
2943                 ContentObserver contentObserver = new ContentObserver(new Handler()) {
2944                     @Override
2945                     public void onChange(boolean selfChange, Uri uri) {
2946                         setAccessibilityState(mAccessibilityManager.isEnabled());
2947                     }
2948                 };
2949                 contentResolver.registerContentObserver(
2950                     Settings.Secure.getUriFor(accessibilityScriptInjection),
2951                     false,
2952                     contentObserver);
2953                 mAccessibilityScriptInjectionObserver = contentObserver;
2954             }
2955
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.
2961         }
2962         return false;
2963     }
2964
2965     /**
2966      * Returns whether or not accessibility injection is being used.
2967      */
2968     public boolean isInjectingAccessibilityScript() {
2969         return mAccessibilityInjector.accessibilityIsAvailable();
2970     }
2971
2972     /**
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.
2977      */
2978     public void setAccessibilityState(boolean state) {
2979         if (!state) {
2980             setInjectedAccessibility(false);
2981             mNativeAccessibilityAllowed = false;
2982             mTouchExplorationEnabled = false;
2983         } else {
2984             boolean useScriptInjection = isDeviceAccessibilityScriptInjectionEnabled();
2985             setInjectedAccessibility(useScriptInjection);
2986             mNativeAccessibilityAllowed = !useScriptInjection;
2987             mTouchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled();
2988         }
2989     }
2990
2991     /**
2992      * Enable or disable injected accessibility features
2993      */
2994     public void setInjectedAccessibility(boolean enabled) {
2995         mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary();
2996         mAccessibilityInjector.setScriptEnabled(enabled);
2997     }
2998
2999     /**
3000      * Stop any TTS notifications that are currently going on.
3001      */
3002     public void stopCurrentAccessibilityNotifications() {
3003         mAccessibilityInjector.onPageLostFocus();
3004     }
3005
3006     /**
3007      * Inform WebKit that Fullscreen mode has been exited by the user.
3008      */
3009     public void exitFullscreen() {
3010         if (mNativeContentViewCore != 0) nativeExitFullscreen(mNativeContentViewCore);
3011     }
3012
3013     /**
3014      * Changes whether hiding the top controls is enabled.
3015      *
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.
3019      */
3020     public void updateTopControlsState(boolean enableHiding, boolean enableShowing,
3021             boolean animate) {
3022         if (mNativeContentViewCore != 0) {
3023             nativeUpdateTopControlsState(
3024                     mNativeContentViewCore, enableHiding, enableShowing, animate);
3025         }
3026     }
3027
3028     /**
3029      * Callback factory method for nativeGetNavigationHistory().
3030      */
3031     @CalledByNative
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);
3037     }
3038
3039     /**
3040      * Get a copy of the navigation history of the view.
3041      */
3042     public NavigationHistory getNavigationHistory() {
3043         NavigationHistory history = new NavigationHistory();
3044         if (mNativeContentViewCore != 0) {
3045             int currentIndex = nativeGetNavigationHistory(mNativeContentViewCore, history);
3046             history.setCurrentEntryIndex(currentIndex);
3047         }
3048         return history;
3049     }
3050
3051     @Override
3052     public NavigationHistory getDirectedNavigationHistory(boolean isForward, int itemLimit) {
3053         NavigationHistory history = new NavigationHistory();
3054         if (mNativeContentViewCore != 0) {
3055             nativeGetDirectedNavigationHistory(
3056                 mNativeContentViewCore, history, isForward, itemLimit);
3057         }
3058         return history;
3059     }
3060
3061     /**
3062      * @return The original request URL for the current navigation entry, or null if there is no
3063      *         current entry.
3064      */
3065     public String getOriginalUrlForActiveNavigationEntry() {
3066         if (mNativeContentViewCore != 0) {
3067             return nativeGetOriginalUrlForActiveNavigationEntry(mNativeContentViewCore);
3068         }
3069         return "";
3070     }
3071
3072     /**
3073      * @return The cached copy of render positions and scales.
3074      */
3075     public RenderCoordinates getRenderCoordinates() {
3076         return mRenderCoordinates;
3077     }
3078
3079     @CalledByNative
3080     private int getLocationInWindowX() {
3081         return mLocationInWindowX;
3082     }
3083
3084     @CalledByNative
3085     private int getLocationInWindowY() {
3086         return mLocationInWindowY;
3087     }
3088
3089     @CalledByNative
3090     private static Rect createRect(int x, int y, int right, int bottom) {
3091         return new Rect(x, y, right, bottom);
3092     }
3093
3094     private boolean onAnimate(long frameTimeMicros) {
3095         if (mNativeContentViewCore == 0) return false;
3096         return nativeOnAnimate(mNativeContentViewCore, frameTimeMicros);
3097     }
3098
3099     private void animateIfNecessary(long frameTimeMicros) {
3100         if (mNeedAnimate) {
3101             mNeedAnimate = onAnimate(frameTimeMicros);
3102             if (!mNeedAnimate) removeVSyncSubscriber();
3103         }
3104     }
3105
3106     public void extractSmartClipData(int x, int y, int width, int height) {
3107         if (mNativeContentViewCore != 0) {
3108             nativeExtractSmartClipData(mNativeContentViewCore, x, y, width, height);
3109         }
3110     }
3111
3112     @CalledByNative
3113     private void onSmartClipDataExtracted(String result) {
3114         if (mSmartClipDataListener != null ) {
3115             mSmartClipDataListener.onSmartClipDataExtracted(result);
3116         }
3117     }
3118
3119     public void setSmartClipDataListener(SmartClipDataListener listener) {
3120         mSmartClipDataListener = listener;
3121     }
3122
3123     /**
3124      * Offer a long press gesture to the embedding View, primarily for WebView compatibility.
3125      *
3126      * @return true if the embedder handled the event.
3127      */
3128     private boolean offerLongPressToEmbedder() {
3129         return mContainerView.performLongClick();
3130     }
3131
3132     private native long nativeInit(long webContentsPtr,
3133             long viewAndroidPtr, long windowAndroidPtr);
3134
3135     @CalledByNative
3136     private ContentVideoViewClient getContentVideoViewClient() {
3137         return getContentViewClient().getContentVideoViewClient();
3138     }
3139
3140     @CalledByNative
3141     private boolean shouldBlockMediaRequest(String url) {
3142         return getContentViewClient().shouldBlockMediaRequest(url);
3143     }
3144
3145     @CalledByNative
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);
3152     }
3153
3154     @Override
3155     public void onScreenOrientationChanged(int orientation) {
3156         sendOrientationChangeEvent(orientation);
3157     }
3158
3159     private native WebContents nativeGetWebContentsAndroid(long nativeContentViewCoreImpl);
3160
3161     private native void nativeOnJavaContentViewCoreDestroyed(long nativeContentViewCoreImpl);
3162
3163     private native void nativeLoadUrl(
3164             long nativeContentViewCoreImpl,
3165             String url,
3166             int loadUrlType,
3167             int transitionType,
3168             int uaOverrideOption,
3169             String extraHeaders,
3170             byte[] postData,
3171             String baseUrlForDataUrl,
3172             String virtualUrlForDataUrl,
3173             boolean canLoadLocalResources);
3174
3175     private native String nativeGetURL(long nativeContentViewCoreImpl);
3176
3177     private native String nativeGetTitle(long nativeContentViewCoreImpl);
3178
3179     private native void nativeShowInterstitialPage(
3180             long nativeContentViewCoreImpl, String url, long nativeInterstitialPageDelegateAndroid);
3181     private native boolean nativeIsShowingInterstitialPage(long nativeContentViewCoreImpl);
3182
3183     private native boolean nativeIsIncognito(long nativeContentViewCoreImpl);
3184
3185     private native void nativeSetFocus(long nativeContentViewCoreImpl, boolean focused);
3186
3187     private native void nativeSendOrientationChangeEvent(
3188             long nativeContentViewCoreImpl, int orientation);
3189
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);
3197
3198     private native int nativeSendMouseMoveEvent(
3199             long nativeContentViewCoreImpl, long timeMs, float x, float y);
3200
3201     private native int nativeSendMouseWheelEvent(
3202             long nativeContentViewCoreImpl, long timeMs, float x, float y, float verticalAxis);
3203
3204     private native void nativeScrollBegin(
3205             long nativeContentViewCoreImpl, long timeMs, float x, float y, float hintX,
3206             float hintY);
3207
3208     private native void nativeScrollEnd(long nativeContentViewCoreImpl, long timeMs);
3209
3210     private native void nativeScrollBy(
3211             long nativeContentViewCoreImpl, long timeMs, float x, float y,
3212             float deltaX, float deltaY);
3213
3214     private native void nativeFlingStart(
3215             long nativeContentViewCoreImpl, long timeMs, float x, float y, float vx, float vy);
3216
3217     private native void nativeFlingCancel(long nativeContentViewCoreImpl, long timeMs);
3218
3219     private native void nativeSingleTap(
3220             long nativeContentViewCoreImpl, long timeMs, float x, float y);
3221
3222     private native void nativeDoubleTap(
3223             long nativeContentViewCoreImpl, long timeMs, float x, float y);
3224
3225     private native void nativeLongPress(
3226             long nativeContentViewCoreImpl, long timeMs, float x, float y);
3227
3228     private native void nativePinchBegin(
3229             long nativeContentViewCoreImpl, long timeMs, float x, float y);
3230
3231     private native void nativePinchEnd(long nativeContentViewCoreImpl, long timeMs);
3232
3233     private native void nativePinchBy(long nativeContentViewCoreImpl, long timeMs,
3234             float anchorX, float anchorY, float deltaScale);
3235
3236     private native void nativeSelectBetweenCoordinates(
3237             long nativeContentViewCoreImpl, float x1, float y1, float x2, float y2);
3238
3239     private native void nativeMoveCaret(long nativeContentViewCoreImpl, float x, float y);
3240
3241     private native void nativeResetGestureDetectors(long nativeContentViewCoreImpl);
3242
3243     private native void nativeIgnoreRemainingTouchEvents(long nativeContentViewCoreImpl);
3244
3245     private native void nativeOnWindowFocusLost(long nativeContentViewCoreImpl);
3246
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);
3253
3254     private native void nativeLoadIfNecessary(long nativeContentViewCoreImpl);
3255     private native void nativeRequestRestoreLoad(long nativeContentViewCoreImpl);
3256
3257     private native void nativeStopLoading(long nativeContentViewCoreImpl);
3258
3259     private native void nativeReload(long nativeContentViewCoreImpl, boolean checkForRepost);
3260     private native void nativeReloadIgnoringCache(
3261             long nativeContentViewCoreImpl, boolean checkForRepost);
3262
3263     private native void nativeCancelPendingReload(long nativeContentViewCoreImpl);
3264
3265     private native void nativeContinuePendingReload(long nativeContentViewCoreImpl);
3266
3267     private native void nativeSelectPopupMenuItems(long nativeContentViewCoreImpl, int[] indices);
3268
3269     private native void nativeScrollFocusedEditableNodeIntoView(long nativeContentViewCoreImpl);
3270
3271     private native void nativeClearHistory(long nativeContentViewCoreImpl);
3272
3273     private native void nativeEvaluateJavaScript(long nativeContentViewCoreImpl,
3274             String script, JavaScriptCallback callback, boolean startRenderer);
3275
3276     private native long nativeGetNativeImeAdapter(long nativeContentViewCoreImpl);
3277
3278     private native int nativeGetCurrentRenderProcessId(long nativeContentViewCoreImpl);
3279
3280     private native int nativeGetBackgroundColor(long nativeContentViewCoreImpl);
3281
3282     private native void nativeOnShow(long nativeContentViewCoreImpl);
3283     private native void nativeOnHide(long nativeContentViewCoreImpl);
3284
3285     private native void nativeSetUseDesktopUserAgent(long nativeContentViewCoreImpl,
3286             boolean enabled, boolean reloadOnChange);
3287     private native boolean nativeGetUseDesktopUserAgent(long nativeContentViewCoreImpl);
3288
3289     private native void nativeClearSslPreferences(long nativeContentViewCoreImpl);
3290
3291     private native void nativeSetAllowJavascriptInterfacesInspection(
3292             long nativeContentViewCoreImpl, boolean allow);
3293
3294     private native void nativeAddJavascriptInterface(long nativeContentViewCoreImpl, Object object,
3295             String name, Class requiredAnnotation, HashSet<Object> retainedObjectSet);
3296
3297     private native void nativeRemoveJavascriptInterface(long nativeContentViewCoreImpl,
3298             String name);
3299
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);
3305
3306     private native void nativeUpdateVSyncParameters(long nativeContentViewCoreImpl,
3307             long timebaseMicros, long intervalMicros);
3308
3309     private native void nativeOnVSync(long nativeContentViewCoreImpl, long frameTimeMicros);
3310
3311     private native boolean nativeOnAnimate(long nativeContentViewCoreImpl, long frameTimeMicros);
3312
3313     private native void nativeWasResized(long nativeContentViewCoreImpl);
3314
3315     private native boolean nativeIsRenderWidgetHostViewReady(long nativeContentViewCoreImpl);
3316
3317     private native void nativeExitFullscreen(long nativeContentViewCoreImpl);
3318     private native void nativeUpdateTopControlsState(long nativeContentViewCoreImpl,
3319             boolean enableHiding, boolean enableShowing, boolean animate);
3320
3321     private native void nativeShowImeIfNeeded(long nativeContentViewCoreImpl);
3322
3323     private native void nativeSetAccessibilityEnabled(
3324             long nativeContentViewCoreImpl, boolean enabled);
3325
3326     private native void nativeExtractSmartClipData(long nativeContentViewCoreImpl,
3327             int x, int y, int w, int h);
3328 }