ContentViewCore.java revision f2477e01787aa58f445919b809d89e252beef54f
15d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner// Copyright 2012 The Chromium Authors. All rights reserved.
25d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner// Use of this source code is governed by a BSD-style license that can be
35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner// found in the LICENSE file.
45d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
55d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerpackage org.chromium.content.browser;
65d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
75d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.app.Activity;
85d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.app.SearchManager;
95d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.content.ContentResolver;
105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.content.Context;
115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.content.Intent;
125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.content.pm.ActivityInfo;
135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.content.pm.PackageManager;
145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.content.res.Configuration;
155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.database.ContentObserver;
165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.graphics.Bitmap;
175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.graphics.Canvas;
185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.graphics.Color;
195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.graphics.Rect;
205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.graphics.RectF;
215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.net.Uri;
225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.os.Build;
235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.os.Bundle;
245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.os.Handler;
255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.os.ResultReceiver;
265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.provider.Browser;
275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.provider.Settings;
285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.text.Editable;
29cc330d4169441727fecf1da08aee806fc021c4e2David 'Digit' Turnerimport android.text.TextUtils;
302ec695af7284adbedcdbc08a22d818b6bdd8990cDavid 'Digit' Turnerimport android.util.Log;
3134c48ff1e3ad5cd2084ca40188754d45f423750bDavid 'Digit' Turnerimport android.util.Pair;
326af6765e2f3bc930d0dce21d752bea570a1b1362David 'Digit' Turnerimport android.view.ActionMode;
3334c48ff1e3ad5cd2084ca40188754d45f423750bDavid 'Digit' Turnerimport android.view.HapticFeedbackConstants;
345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.view.InputDevice;
355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.view.KeyEvent;
365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.view.MotionEvent;
375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.view.Surface;
385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.view.View;
395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.view.ViewGroup;
405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.view.Window;
415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.view.WindowManager;
425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.view.accessibility.AccessibilityEvent;
435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.view.accessibility.AccessibilityManager;
445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.view.accessibility.AccessibilityNodeInfo;
465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.view.accessibility.AccessibilityNodeProvider;
475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.view.inputmethod.EditorInfo;
485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.view.inputmethod.InputConnection;
495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.view.inputmethod.InputMethodManager;
505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.widget.AbsoluteLayout;
515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport android.widget.FrameLayout;
525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport com.google.common.annotations.VisibleForTesting;
545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.base.CalledByNative;
565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.base.JNINamespace;
575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.base.WeakContext;
585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.content.R;
595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.content.browser.ContentViewGestureHandler.MotionEventDelegate;
605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.content.browser.accessibility.AccessibilityInjector;
615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.content.browser.accessibility.BrowserAccessibilityManager;
62aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turnerimport org.chromium.content.browser.input.AdapterInputConnection;
635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.content.browser.input.HandleView;
645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.content.browser.input.ImeAdapter;
655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.content.browser.input.ImeAdapter.AdapterInputConnectionFactory;
665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.content.browser.input.InputMethodManagerWrapper;
675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.content.browser.input.InsertionHandleController;
685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.content.browser.input.SelectPopupDialog;
695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.content.browser.input.SelectionHandleController;
705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.content.common.TraceEvent;
715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.ui.base.ViewAndroid;
725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.ui.base.ViewAndroidDelegate;
735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.ui.base.WindowAndroid;
745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport org.chromium.ui.gfx.DeviceDisplayInfo;
755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport java.lang.annotation.Annotation;
775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport java.lang.reflect.Field;
785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport java.util.HashMap;
795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport java.util.HashSet;
805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerimport java.util.Map;
815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/**
835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Provides a Java-side 'wrapper' around a WebContent (native) instance.
845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Contains all the major functionality necessary to manage the lifecycle of a ContentView without
85aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner * being tied to the view system.
865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner@JNINamespace("content")
885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerpublic class ContentViewCore
895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        implements MotionEventDelegate, NavigationClient, AccessibilityStateChangeListener {
905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private static final String TAG = "ContentViewCore";
925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // Used to avoid enabling zooming in / out if resulting zooming will
945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // produce little visible difference.
955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private static final float ZOOM_CONTROLS_EPSILON = 0.007f;
965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // Used to represent gestures for long press and long tap.
985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private static final int IS_LONG_PRESS = 1;
995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private static final int IS_LONG_TAP = 2;
1005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // Length of the delay (in ms) before fading in handles after the last page movement.
102a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner    private static final int TEXT_HANDLE_FADE_IN_DELAY = 300;
1035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // If the embedder adds a JavaScript interface object that contains an indirect reference to
1055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // the ContentViewCore, then storing a strong ref to the interface object on the native
106cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    // side would prevent garbage collection of the ContentViewCore (as that strong ref would
107cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    // create a new GC root).
108cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    // For that reason, we store only a weak reference to the interface object on the
109cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    // native side. However we still need a strong reference on the Java side to
110cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    // prevent garbage collection if the embedder doesn't maintain their own ref to the
111cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    // interface object - the Java side ref won't create a new GC root.
112cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    // This map stores those refernces. We put into the map on addJavaScriptInterface()
113cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    // and remove from it in removeJavaScriptInterface().
114cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    private final Map<String, Object> mJavaScriptInterfaces = new HashMap<String, Object>();
115cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
116cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    // Additionally, we keep track of all Java bound JS objects that are in use on the
117cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    // current page to ensure that they are not garbage collected until the page is
118cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    // navigated. This includes interface objects that have been removed
119cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    // via the removeJavaScriptInterface API and transient objects returned from methods
120cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    // on the interface object. Note we use HashSet rather than Set as the native side
121cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    // expects HashSet (no bindings for interfaces).
122cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    private final HashSet<Object> mRetainedJavaScriptObjects = new HashSet<Object>();
123cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
124cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    /**
125cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner     * Interface that consumers of {@link ContentViewCore} must implement to allow the proper
126cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner     * dispatching of view methods through the containing view.
127cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner     *
128cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner     * <p>
129cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner     * All methods with the "super_" prefix should be routed to the parent of the
130cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner     * implementing container view.
131cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner     */
132cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    @SuppressWarnings("javadoc")
133cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    public interface InternalAccessDelegate {
134cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /**
135cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         * @see View#drawChild(Canvas, View, long)
136cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         */
137cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        boolean drawChild(Canvas canvas, View child, long drawingTime);
138cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
139cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /**
140cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         * @see View#onKeyUp(keyCode, KeyEvent)
141cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         */
142cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        boolean super_onKeyUp(int keyCode, KeyEvent event);
143cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
144cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /**
145cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         * @see View#dispatchKeyEventPreIme(KeyEvent)
146cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         */
147cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        boolean super_dispatchKeyEventPreIme(KeyEvent event);
148cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
149cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /**
150cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         * @see View#dispatchKeyEvent(KeyEvent)
151cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         */
152cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        boolean super_dispatchKeyEvent(KeyEvent event);
153cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
154cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /**
155cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         * @see View#onGenericMotionEvent(MotionEvent)
156cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         */
157cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        boolean super_onGenericMotionEvent(MotionEvent event);
158cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
159cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /**
160cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         * @see View#onConfigurationChanged(Configuration)
161cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         */
162cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        void super_onConfigurationChanged(Configuration newConfig);
163cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
164cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /**
165cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         * @see View#onScrollChanged(int, int, int, int)
166cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         */
167cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        void onScrollChanged(int lPix, int tPix, int oldlPix, int oldtPix);
168cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
169cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /**
170cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         * @see View#awakenScrollBars()
171cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         */
172cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        boolean awakenScrollBars();
173cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
174cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /**
175cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         * @see View#awakenScrollBars(int, boolean)
176cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         */
177cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        boolean super_awakenScrollBars(int startDelay, boolean invalidate);
178cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
179cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
180cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    /**
181cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner     * An interface that allows the embedder to be notified of events and state changes related to
182cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner     * gesture processing.
183cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner     */
184cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    public interface GestureStateListener {
185cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /**
186cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         * Called when the pinch gesture starts.
187cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         */
188cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        void onPinchGestureStart();
189cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
190cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /**
191cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         * Called when the pinch gesture ends.
192cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         */
193cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        void onPinchGestureEnd();
194cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
195cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /**
196cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         * Called when the fling gesture is sent.
197cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         */
198cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        void onFlingStartGesture(int vx, int vy);
199cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
200cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /**
201cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         * Called when the fling cancel gesture is sent.
202cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         */
203cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        void onFlingCancelGesture();
204cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
205cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /**
206cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         * Called when a fling event was not handled by the renderer.
207cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         */
208cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        void onUnhandledFlingStartEvent();
209cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
210cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /**
211cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         * Called to indicate that a scroll update gesture had been consumed by the page.
212cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         * This callback is called whenever any layer is scrolled (like a frame or div). It is
213cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         * not called when a JS touch handler consumes the event (preventDefault), it is not called
214cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         * for JS-initiated scrolling.
215cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner         */
216cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        void onScrollUpdateGestureConsumed();
217cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
218cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
2195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /**
2205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * An interface for controlling visibility and state of embedder-provided zoom controls.
2215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     */
2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    public interface ZoomControlsDelegate {
2235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /**
2245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * Called when it's reasonable to show zoom controls.
2255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         */
2265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        void invokeZoomPicker();
2275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /**
2295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * Called when zoom controls need to be hidden (e.g. when the view hides).
230a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner         */
231aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner        void dismissZoomPicker();
2325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /**
2345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * Called when page scale has been changed, so the controls can update their state.
2355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         */
2365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        void updateZoomControls();
2375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /**
240aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner     * An interface that allows the embedder to be notified of changes to the parameters of the
241aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner     * currently displayed contents.
2425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * These notifications are consistent with respect to the UI thread (the size is the size of
2435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * the contents currently displayed on screen).
2445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     */
2455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    public interface UpdateFrameInfoListener {
2465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /**
2475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * Called each time any of the parameters are changed.
2485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         *
2495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * @param pageScaleFactor The page scale.
2505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         */
2515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        void onFrameInfoUpdated(float pageScaleFactor);
2525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private VSyncManager.Provider mVSyncProvider;
2555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private VSyncManager.Listener mVSyncListener;
2565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private int mVSyncSubscriberCount;
2575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private boolean mVSyncListenerRegistered;
2585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // To avoid IPC delay we use input events to directly trigger a vsync signal in the renderer.
2605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // When we do this, we also need to avoid sending the real vsync signal for the current
2615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // frame to avoid double-ticking. This flag is used to inhibit the next vsync notification.
2625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private boolean mDidSignalVSyncUsingInputEvent;
2635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    public VSyncManager.Listener getVSyncListener(VSyncManager.Provider vsyncProvider) {
2655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (mVSyncProvider != null && mVSyncListenerRegistered) {
2665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            mVSyncProvider.unregisterVSyncListener(mVSyncListener);
2675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            mVSyncListenerRegistered = false;
2685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
2695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        mVSyncProvider = vsyncProvider;
2715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        mVSyncListener = new VSyncManager.Listener() {
2725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            @Override
2735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            public void updateVSync(long tickTimeMicros, long intervalMicros) {
2745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (mNativeContentViewCore != 0) {
2755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    nativeUpdateVSyncParameters(mNativeContentViewCore, tickTimeMicros,
2765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                            intervalMicros);
2775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                }
2785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
2795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            @Override
2815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            public void onVSync(long frameTimeMicros) {
2825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                animateIfNecessary(frameTimeMicros);
2835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (mRequestedVSyncForInput) {
2855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    mRequestedVSyncForInput = false;
2865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    removeVSyncSubscriber();
2875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                }
2885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (mNativeContentViewCore != 0) {
2895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    nativeOnVSync(mNativeContentViewCore, frameTimeMicros);
2905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                }
2915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
2925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        };
2935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (mVSyncSubscriberCount > 0) {
2955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            // addVSyncSubscriber() is called before getVSyncListener.
2965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vsyncProvider.registerVSyncListener(mVSyncListener);
2975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            mVSyncListenerRegistered = true;
2985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
2995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return mVSyncListener;
3015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    @CalledByNative
3045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    void addVSyncSubscriber() {
3055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!isVSyncNotificationEnabled()) {
3065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            mDidSignalVSyncUsingInputEvent = false;
3075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
3085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (mVSyncProvider != null && !mVSyncListenerRegistered) {
3095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            mVSyncProvider.registerVSyncListener(mVSyncListener);
3105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            mVSyncListenerRegistered = true;
3115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
3125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        mVSyncSubscriberCount++;
3135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    @CalledByNative
3165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    void removeVSyncSubscriber() {
3175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (mVSyncProvider != null && mVSyncSubscriberCount == 1) {
3185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            assert mVSyncListenerRegistered;
3195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            mVSyncProvider.unregisterVSyncListener(mVSyncListener);
3205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            mVSyncListenerRegistered = false;
3215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
3225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        mVSyncSubscriberCount--;
3235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        assert mVSyncSubscriberCount >= 0;
3245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    @CalledByNative
3275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private void resetVSyncNotification() {
3285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        while (isVSyncNotificationEnabled()) removeVSyncSubscriber();
3295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        mVSyncSubscriberCount = 0;
3305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        mVSyncListenerRegistered = false;
3315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        mNeedAnimate = false;
3325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private boolean isVSyncNotificationEnabled() {
3355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return mVSyncProvider != null && mVSyncListenerRegistered;
3365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    @CalledByNative
3395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private void setNeedsAnimate() {
3405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!mNeedAnimate) {
3415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            mNeedAnimate = true;
3425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            addVSyncSubscriber();
3435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
3445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private final Context mContext;
3475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private ViewGroup mContainerView;
3485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private InternalAccessDelegate mContainerViewInternals;
3495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private WebContentsObserverAndroid mWebContentsObserver;
3505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private ContentViewClient mContentViewClient;
3525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private ContentSettings mContentSettings;
3545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // Native pointer to C++ ContentViewCoreImpl object which will be set by nativeInit().
3565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private long mNativeContentViewCore = 0;
3575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private boolean mInForeground = false;
3595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private ContentViewGestureHandler mContentViewGestureHandler;
3615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private GestureStateListener mGestureStateListener;
3625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private ZoomManager mZoomManager;
3635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private ZoomControlsDelegate mZoomControlsDelegate;
3645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private PopupZoomer mPopupZoomer;
3665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private Runnable mFakeMouseMoveRunnable = null;
3685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // Only valid when focused on a text / password field.
3705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private ImeAdapter mImeAdapter;
3715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private ImeAdapter.AdapterInputConnectionFactory mAdapterInputConnectionFactory;
3725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private AdapterInputConnection mInputConnection;
3735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private SelectionHandleController mSelectionHandleController;
3755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private InsertionHandleController mInsertionHandleController;
3765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private Runnable mDeferredHandleFadeInRunnable;
3785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private PositionObserver mPositionObserver;
3805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private PositionObserver.Listener mPositionListener;
3815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // Size of the viewport in physical pixels as set from onSizeChanged.
3835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private int mViewportWidthPix;
3845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private int mViewportHeightPix;
3855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private int mPhysicalBackingWidthPix;
3865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private int mPhysicalBackingHeightPix;
3875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private int mOverdrawBottomHeightPix;
3885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private int mViewportSizeOffsetWidthPix;
3895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private int mViewportSizeOffsetHeightPix;
3905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private int mLocationInWindowX;
3915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private int mLocationInWindowY;
3925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // Cached copy of all positions and scales as reported by the renderer.
3945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private final RenderCoordinates mRenderCoordinates;
3955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private final RenderCoordinates.NormalizedPoint mStartHandlePoint;
397cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    private final RenderCoordinates.NormalizedPoint mEndHandlePoint;
3985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private final RenderCoordinates.NormalizedPoint mInsertionHandlePoint;
399cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
400cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    // Tracks whether a selection is currently active.  When applied to selected text, indicates
4015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // whether the last selected text is still highlighted.
4025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private boolean mHasSelection;
403cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    private String mLastSelectedText;
4045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private boolean mSelectionEditable;
4055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private ActionMode mActionMode;
4065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private boolean mUnselectAllOnActionModeDismiss;
4075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // Delegate that will handle GET downloads, and be notified of completion of POST downloads.
4095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private ContentViewDownloadDelegate mDownloadDelegate;
410a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner
4115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // The AccessibilityInjector that handles loading Accessibility scripts into the web page.
4125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private AccessibilityInjector mAccessibilityInjector;
4135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // Whether native accessibility, i.e. without any script injection, is allowed.
4155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private boolean mNativeAccessibilityAllowed;
4165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // Whether native accessibility, i.e. without any script injection, has been enabled.
4185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private boolean mNativeAccessibilityEnabled;
4195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // Handles native accessibility, i.e. without any script injection.
4215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private BrowserAccessibilityManager mBrowserAccessibilityManager;
4225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // System accessibility service.
4245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private final AccessibilityManager mAccessibilityManager;
4255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
426cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    // Allows us to dynamically respond when the accessibility script injection flag changes.
4275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private ContentObserver mAccessibilityScriptInjectionObserver;
4285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
429cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    // Temporary notification to tell onSizeChanged to focus a form element,
430cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    // because the OSK was just brought up.
4315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private boolean mUnfocusOnNextSizeChanged = false;
4325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private final Rect mFocusPreOSKViewportRect = new Rect();
433cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
4345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // Used to keep track of whether we should try to undo the last zoom-to-textfield operation.
4355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private boolean mScrolledAndZoomedFocusedEditableNode = false;
4365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // Whether we use hardware-accelerated drawing.
4385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private boolean mHardwareAccelerated = false;
4395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // Whether we received a new frame since consumePendingRendererFrame() was last called.
4415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private boolean mPendingRendererFrame = false;
442aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner
4435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // Whether we should animate at the next vsync tick.
4445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private boolean mNeedAnimate = false;
445aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner
446a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner    // Whether we requested a proactive vsync event in response to touch input.
4475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // This reduces the latency of responding to input by ensuring the renderer
448a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner    // is sent a BeginFrame for every touch event we receive. Otherwise the
4495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // renderer's SetNeedsBeginFrame message would get serviced at the next
4505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    // vsync.
4515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private boolean mRequestedVSyncForInput = false;
4525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    private ViewAndroid mViewAndroid;
4545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    public static class UMAActionAfterDoubleTap {
4565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        public static final int NAVIGATE_BACK = 0;
4575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        public static final int NAVIGATE_STOP = 1;
4585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        public static final int NO_ACTION = 2;
4595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        public static final int COUNT = 3;
4605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
4615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    public static class UMASingleTapType {
4635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        public static final int DELAYED_TAP = 0;
4645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        public static final int UNDELAYED_TAP = 1;
4655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        public static final int COUNT = 2;
4665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
4675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /**
4695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * Constructs a new ContentViewCore. Embedders must call initialize() after constructing
4705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * a ContentViewCore and before using it.
4715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     *
4725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * @param context The context used to create this.
4735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     */
4745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    public ContentViewCore(Context context) {
4755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        mContext = context;
4765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        WeakContext.initializeWeakContext(context);
4785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        HeapStatsLogger.init(mContext.getApplicationContext());
4795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        mAdapterInputConnectionFactory = new AdapterInputConnectionFactory();
4805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        mRenderCoordinates = new RenderCoordinates();
4825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        mRenderCoordinates.setDeviceScaleFactor(
4835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                getContext().getResources().getDisplayMetrics().density);
4845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        mStartHandlePoint = mRenderCoordinates.createNormalizedPoint();
4855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        mEndHandlePoint = mRenderCoordinates.createNormalizedPoint();
4865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        mInsertionHandlePoint = mRenderCoordinates.createNormalizedPoint();
4875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        mAccessibilityManager = (AccessibilityManager)
4885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
4895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
4905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /**
4925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * @return The context used for creating this ContentViewCore.
4935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     */
4945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    @CalledByNative
4955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    public Context getContext() {
4965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return mContext;
4975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
4985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /**
5005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * @return The ViewGroup that all view actions of this ContentViewCore should interact with.
501a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner     */
5025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    public ViewGroup getContainerView() {
5035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return mContainerView;
5045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /**
5075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * Specifies how much smaller the WebKit layout size should be relative to the size of this
5085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * view.
5095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * @param offsetXPix The X amount in pixels to shrink the viewport by.
5105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * @param offsetYPix The Y amount in pixels to shrink the viewport by.
5115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     */
5125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    public void setViewportSizeOffset(int offsetXPix, int offsetYPix) {
513a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner        if (offsetXPix != mViewportSizeOffsetWidthPix ||
5145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                offsetYPix != mViewportSizeOffsetHeightPix) {
5155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            mViewportSizeOffsetWidthPix = offsetXPix;
5165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            mViewportSizeOffsetHeightPix = offsetYPix;
5175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (mNativeContentViewCore != 0) nativeWasResized(mNativeContentViewCore);
5185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
5195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /**
5225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * Returns a delegate that can be used to add and remove views from the ContainerView.
5235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     *
5246234c0bcfcdd730c6815136cf958b240af8f4a7cDavid 'Digit' Turner     * NOTE: Use with care, as not all ContentViewCore users setup their ContainerView in the same
5256234c0bcfcdd730c6815136cf958b240af8f4a7cDavid 'Digit' Turner     * way. In particular, the Android WebView has limitations on what implementation details can
5266234c0bcfcdd730c6815136cf958b240af8f4a7cDavid 'Digit' Turner     * be provided via a child view, as they are visible in the API and could introduce
5276234c0bcfcdd730c6815136cf958b240af8f4a7cDavid 'Digit' Turner     * compatibility breaks with existing applications. If in doubt, contact the
5286234c0bcfcdd730c6815136cf958b240af8f4a7cDavid 'Digit' Turner     * android_webview/OWNERS
5296234c0bcfcdd730c6815136cf958b240af8f4a7cDavid 'Digit' Turner     *
5306234c0bcfcdd730c6815136cf958b240af8f4a7cDavid 'Digit' Turner     * @return A ViewAndroidDelegate that can be used to add and remove views.
531     */
532    @VisibleForTesting
533    public ViewAndroidDelegate getViewAndroidDelegate() {
534        return new ViewAndroidDelegate() {
535            @Override
536            public View acquireAnchorView() {
537                View anchorView = new View(getContext());
538                mContainerView.addView(anchorView);
539                return anchorView;
540            }
541
542            @Override
543            @SuppressWarnings("deprecation")  // AbsoluteLayout.LayoutParams
544            public void setAnchorViewPosition(
545                    View view, float x, float y, float width, float height) {
546                assert view.getParent() == mContainerView;
547
548                float scale = (float) DeviceDisplayInfo.create(getContext()).getDIPScale();
549
550                // The anchor view should not go outside the bounds of the ContainerView.
551                int leftMargin = Math.round(x * scale);
552                int topMargin = Math.round(mRenderCoordinates.getContentOffsetYPix() + y * scale);
553                int scaledWidth = Math.round(width * scale);
554                // ContentViewCore currently only supports these two container view types.
555                if (mContainerView instanceof FrameLayout) {
556                    if (scaledWidth + leftMargin > mContainerView.getWidth()) {
557                        scaledWidth = mContainerView.getWidth() - leftMargin;
558                    }
559                    FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
560                        scaledWidth, Math.round(height * scale));
561                    lp.leftMargin = leftMargin;
562                    lp.topMargin = topMargin;
563                    view.setLayoutParams(lp);
564                } else if (mContainerView instanceof AbsoluteLayout) {
565                    // This fixes the offset due to a difference in
566                    // scrolling model of WebView vs. Chrome.
567                    // TODO(sgurun) fix this to use mContainerView.getScroll[X/Y]()
568                    // as it naturally accounts for scroll differences between
569                    // these models.
570                    leftMargin += mRenderCoordinates.getScrollXPixInt();
571                    topMargin += mRenderCoordinates.getScrollYPixInt();
572
573                    android.widget.AbsoluteLayout.LayoutParams lp =
574                            new android.widget.AbsoluteLayout.LayoutParams(
575                                scaledWidth, (int) (height * scale), leftMargin, topMargin);
576                    view.setLayoutParams(lp);
577                } else {
578                    Log.e(TAG, "Unknown layout " + mContainerView.getClass().getName());
579                }
580            }
581
582            @Override
583            public void releaseAnchorView(View anchorView) {
584                mContainerView.removeView(anchorView);
585            }
586        };
587    }
588
589    @VisibleForTesting
590    public ImeAdapter getImeAdapterForTest() {
591        return mImeAdapter;
592    }
593
594    @VisibleForTesting
595    public void setAdapterInputConnectionFactory(AdapterInputConnectionFactory factory) {
596        mAdapterInputConnectionFactory = factory;
597    }
598
599    @VisibleForTesting
600    public AdapterInputConnection getInputConnectionForTest() {
601        return mInputConnection;
602    }
603
604    private ImeAdapter createImeAdapter(Context context) {
605        return new ImeAdapter(new InputMethodManagerWrapper(context),
606                new ImeAdapter.ImeAdapterDelegate() {
607                    @Override
608                    public void onImeEvent(boolean isFinish) {
609                        getContentViewClient().onImeEvent();
610                        if (!isFinish) {
611                            hideHandles();
612                            undoScrollFocusedEditableNodeIntoViewIfNeeded(false);
613                        }
614                    }
615
616                    @Override
617                    public void onSetFieldValue() {
618                        scrollFocusedEditableNodeIntoView();
619                    }
620
621                    @Override
622                    public void onDismissInput() {
623                        getContentViewClient().onImeStateChangeRequested(false);
624                    }
625
626                    @Override
627                    public View getAttachedView() {
628                        return mContainerView;
629                    }
630
631                    @Override
632                    public ResultReceiver getNewShowKeyboardReceiver() {
633                        return new ResultReceiver(new Handler()) {
634                            @Override
635                            public void onReceiveResult(int resultCode, Bundle resultData) {
636                                getContentViewClient().onImeStateChangeRequested(
637                                        resultCode == InputMethodManager.RESULT_SHOWN ||
638                                        resultCode == InputMethodManager.RESULT_UNCHANGED_SHOWN);
639                                if (resultCode == InputMethodManager.RESULT_SHOWN) {
640                                    // If OSK is newly shown, delay the form focus until
641                                    // the onSizeChanged (in order to adjust relative to the
642                                    // new size).
643                                    // TODO(jdduke): We should not assume that onSizeChanged will
644                                    // always be called, crbug.com/294908.
645                                    getContainerView().getWindowVisibleDisplayFrame(
646                                            mFocusPreOSKViewportRect);
647                                } else if (resultCode ==
648                                        InputMethodManager.RESULT_UNCHANGED_SHOWN) {
649                                    // If the OSK was already there, focus the form immediately.
650                                    scrollFocusedEditableNodeIntoView();
651                                } else {
652                                    undoScrollFocusedEditableNodeIntoViewIfNeeded(false);
653                                }
654                            }
655                        };
656                    }
657                }
658        );
659    }
660
661    /**
662     * Returns true if the given Activity has hardware acceleration enabled
663     * in its manifest, or in its foreground window.
664     *
665     * TODO(husky): Remove when initialize() is refactored (see TODO there)
666     * TODO(dtrainor) This is still used by other classes.  Make sure to pull some version of this
667     * out before removing it.
668     */
669    public static boolean hasHardwareAcceleration(Activity activity) {
670        // Has HW acceleration been enabled manually in the current window?
671        Window window = activity.getWindow();
672        if (window != null) {
673            if ((window.getAttributes().flags
674                    & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0) {
675                return true;
676            }
677        }
678
679        // Has HW acceleration been enabled in the manifest?
680        try {
681            ActivityInfo info = activity.getPackageManager().getActivityInfo(
682                    activity.getComponentName(), 0);
683            if ((info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
684                return true;
685            }
686        } catch (PackageManager.NameNotFoundException e) {
687            Log.e("Chrome", "getActivityInfo(self) should not fail");
688        }
689
690        return false;
691    }
692
693    /**
694     * Returns true if the given Context is a HW-accelerated Activity.
695     *
696     * TODO(husky): Remove when initialize() is refactored (see TODO there)
697     */
698    private static boolean hasHardwareAcceleration(Context context) {
699        if (context instanceof Activity) {
700            return hasHardwareAcceleration((Activity) context);
701        }
702        return false;
703    }
704
705    /**
706     *
707     * @param containerView The view that will act as a container for all views created by this.
708     * @param internalDispatcher Handles dispatching all hidden or super methods to the
709     *                           containerView.
710     * @param nativeWebContents A pointer to the native web contents.
711     * @param windowAndroid An instance of the WindowAndroid.
712     */
713    // Perform important post-construction set up of the ContentViewCore.
714    // We do not require the containing view in the constructor to allow embedders to create a
715    // ContentViewCore without having fully created its containing view. The containing view
716    // is a vital component of the ContentViewCore, so embedders must exercise caution in what
717    // they do with the ContentViewCore before calling initialize().
718    // We supply the nativeWebContents pointer here rather than in the constructor to allow us
719    // to set the private browsing mode at a later point for the WebView implementation.
720    // Note that the caller remains the owner of the nativeWebContents and is responsible for
721    // deleting it after destroying the ContentViewCore.
722    public void initialize(ViewGroup containerView, InternalAccessDelegate internalDispatcher,
723            long nativeWebContents, WindowAndroid windowAndroid) {
724        // Check whether to use hardware acceleration. This is a bit hacky, and
725        // only works if the Context is actually an Activity (as it is in the
726        // Chrome application).
727        //
728        // What we're doing here is checking whether the app has *requested*
729        // hardware acceleration by setting the appropriate flags. This does not
730        // necessarily mean we're going to *get* hardware acceleration -- that's
731        // up to the Android framework.
732        //
733        // TODO(husky): Once the native code has been updated so that the
734        // HW acceleration flag can be set dynamically (Grace is doing this),
735        // move this check into onAttachedToWindow(), where we can test for
736        // HW support directly.
737        mHardwareAccelerated = hasHardwareAcceleration(mContext);
738
739        mContainerView = containerView;
740        mPositionObserver = new ViewPositionObserver(mContainerView);
741        mPositionListener = new PositionObserver.Listener() {
742            @Override
743            public void onPositionChanged(int x, int y) {
744                if (isSelectionHandleShowing() || isInsertionHandleShowing()) {
745                    temporarilyHideTextHandles();
746                }
747            }
748        };
749
750        long windowNativePointer = windowAndroid != null ? windowAndroid.getNativePointer() : 0;
751
752        long viewAndroidNativePointer = 0;
753        if (windowNativePointer != 0) {
754            mViewAndroid = new ViewAndroid(windowAndroid, getViewAndroidDelegate());
755            viewAndroidNativePointer = mViewAndroid.getNativePointer();
756        }
757
758        mNativeContentViewCore = nativeInit(mHardwareAccelerated,
759                nativeWebContents, viewAndroidNativePointer, windowNativePointer);
760        mContentSettings = new ContentSettings(this, mNativeContentViewCore);
761        initializeContainerView(internalDispatcher);
762
763        mAccessibilityInjector = AccessibilityInjector.newInstance(this);
764
765        String contentDescription = "Web View";
766        if (R.string.accessibility_content_view == 0) {
767            Log.w(TAG, "Setting contentDescription to 'Web View' as no value was specified.");
768        } else {
769            contentDescription = mContext.getResources().getString(
770                    R.string.accessibility_content_view);
771        }
772        mContainerView.setContentDescription(contentDescription);
773        mWebContentsObserver = new WebContentsObserverAndroid(this) {
774            @Override
775            public void didStartLoading(String url) {
776                hidePopupDialog();
777                resetGestureDetectors();
778            }
779        };
780
781        sendOrientationChangeEvent();
782    }
783
784    @CalledByNative
785    void onNativeContentViewCoreDestroyed(long nativeContentViewCore) {
786        assert nativeContentViewCore == mNativeContentViewCore;
787        mNativeContentViewCore = 0;
788    }
789
790    /**
791     * Set the Container view Internals.
792     * @param internalDispatcher Handles dispatching all hidden or super methods to the
793     *                           containerView.
794     */
795    public void setContainerViewInternals(InternalAccessDelegate internalDispatcher) {
796        mContainerViewInternals = internalDispatcher;
797    }
798
799    /**
800     * Initializes the View that will contain all Views created by the ContentViewCore.
801     *
802     * @param internalDispatcher Handles dispatching all hidden or super methods to the
803     *                           containerView.
804     */
805    private void initializeContainerView(InternalAccessDelegate internalDispatcher) {
806        TraceEvent.begin();
807        mContainerViewInternals = internalDispatcher;
808
809        mContainerView.setWillNotDraw(false);
810        mContainerView.setClickable(true);
811
812        mZoomManager = new ZoomManager(mContext, this);
813        mContentViewGestureHandler = new ContentViewGestureHandler(mContext, this, mZoomManager);
814        mZoomControlsDelegate = new ZoomControlsDelegate() {
815            @Override
816            public void invokeZoomPicker() {}
817            @Override
818            public void dismissZoomPicker() {}
819            @Override
820            public void updateZoomControls() {}
821        };
822
823        mRenderCoordinates.reset();
824        onRenderCoordinatesUpdated();
825
826        initPopupZoomer(mContext);
827        mImeAdapter = createImeAdapter(mContext);
828        TraceEvent.end();
829    }
830
831    private void initPopupZoomer(Context context){
832        mPopupZoomer = new PopupZoomer(context);
833        mPopupZoomer.setOnVisibilityChangedListener(new PopupZoomer.OnVisibilityChangedListener() {
834            @Override
835            public void onPopupZoomerShown(final PopupZoomer zoomer) {
836                mContainerView.post(new Runnable() {
837                    @Override
838                    public void run() {
839                        if (mContainerView.indexOfChild(zoomer) == -1) {
840                            mContainerView.addView(zoomer);
841                        } else {
842                            assert false : "PopupZoomer should never be shown without being hidden";
843                        }
844                    }
845                });
846            }
847
848            @Override
849            public void onPopupZoomerHidden(final PopupZoomer zoomer) {
850                mContainerView.post(new Runnable() {
851                    @Override
852                    public void run() {
853                        if (mContainerView.indexOfChild(zoomer) != -1) {
854                            mContainerView.removeView(zoomer);
855                            mContainerView.invalidate();
856                        } else {
857                            assert false : "PopupZoomer should never be hidden without being shown";
858                        }
859                    }
860                });
861            }
862        });
863        // TODO(yongsheng): LONG_TAP is not enabled in PopupZoomer. So need to dispatch a LONG_TAP
864        // gesture if a user completes a tap on PopupZoomer UI after a LONG_PRESS gesture.
865        PopupZoomer.OnTapListener listener = new PopupZoomer.OnTapListener() {
866            @Override
867            public boolean onSingleTap(View v, MotionEvent e) {
868                mContainerView.requestFocus();
869                if (mNativeContentViewCore != 0) {
870                    nativeSingleTap(mNativeContentViewCore, e.getEventTime(),
871                            e.getX(), e.getY(), true);
872                }
873                return true;
874            }
875
876            @Override
877            public boolean onLongPress(View v, MotionEvent e) {
878                if (mNativeContentViewCore != 0) {
879                    nativeLongPress(mNativeContentViewCore, e.getEventTime(),
880                            e.getX(), e.getY(), true);
881                }
882                return true;
883            }
884        };
885        mPopupZoomer.setOnTapListener(listener);
886    }
887
888    /**
889     * Destroy the internal state of the ContentView. This method may only be
890     * called after the ContentView has been removed from the view system. No
891     * other methods may be called on this ContentView after this method has
892     * been called.
893     */
894    public void destroy() {
895        if (mNativeContentViewCore != 0) {
896            nativeOnJavaContentViewCoreDestroyed(mNativeContentViewCore);
897        }
898        resetVSyncNotification();
899        mVSyncProvider = null;
900        if (mViewAndroid != null) mViewAndroid.destroy();
901        mNativeContentViewCore = 0;
902        mContentSettings = null;
903        mJavaScriptInterfaces.clear();
904        mRetainedJavaScriptObjects.clear();
905        unregisterAccessibilityContentObserver();
906    }
907
908    private void unregisterAccessibilityContentObserver() {
909        if (mAccessibilityScriptInjectionObserver == null) {
910            return;
911        }
912        getContext().getContentResolver().unregisterContentObserver(
913                mAccessibilityScriptInjectionObserver);
914        mAccessibilityScriptInjectionObserver = null;
915    }
916
917    /**
918     * Returns true initially, false after destroy() has been called.
919     * It is illegal to call any other public method after destroy().
920     */
921    public boolean isAlive() {
922        return mNativeContentViewCore != 0;
923    }
924
925    /**
926     * This is only useful for passing over JNI to native code that requires ContentViewCore*.
927     * @return native ContentViewCore pointer.
928     */
929    @CalledByNative
930    public long getNativeContentViewCore() {
931        return mNativeContentViewCore;
932    }
933
934    /**
935     * For internal use. Throws IllegalStateException if mNativeContentView is 0.
936     * Use this to ensure we get a useful Java stack trace, rather than a native
937     * crash dump, from use-after-destroy bugs in Java code.
938     */
939    void checkIsAlive() throws IllegalStateException {
940        if (!isAlive()) {
941            throw new IllegalStateException("ContentView used after destroy() was called");
942        }
943    }
944
945    public void setContentViewClient(ContentViewClient client) {
946        if (client == null) {
947            throw new IllegalArgumentException("The client can't be null.");
948        }
949        mContentViewClient = client;
950    }
951
952    ContentViewClient getContentViewClient() {
953        if (mContentViewClient == null) {
954            // We use the Null Object pattern to avoid having to perform a null check in this class.
955            // We create it lazily because most of the time a client will be set almost immediately
956            // after ContentView is created.
957            mContentViewClient = new ContentViewClient();
958            // We don't set the native ContentViewClient pointer here on purpose. The native
959            // implementation doesn't mind a null delegate and using one is better than passing a
960            // Null Object, since we cut down on the number of JNI calls.
961        }
962        return mContentViewClient;
963    }
964
965    public int getBackgroundColor() {
966        if (mNativeContentViewCore != 0) {
967            return nativeGetBackgroundColor(mNativeContentViewCore);
968        }
969        return Color.WHITE;
970    }
971
972    @CalledByNative
973    private void onBackgroundColorChanged(int color) {
974        getContentViewClient().onBackgroundColorChanged(color);
975    }
976
977    /**
978     * Load url without fixing up the url string. Consumers of ContentView are responsible for
979     * ensuring the URL passed in is properly formatted (i.e. the scheme has been added if left
980     * off during user input).
981     *
982     * @param params Parameters for this load.
983     */
984    public void loadUrl(LoadUrlParams params) {
985        if (mNativeContentViewCore == 0) return;
986
987        nativeLoadUrl(mNativeContentViewCore,
988                params.mUrl,
989                params.mLoadUrlType,
990                params.mTransitionType,
991                params.mUaOverrideOption,
992                params.getExtraHeadersString(),
993                params.mPostData,
994                params.mBaseUrlForDataUrl,
995                params.mVirtualUrlForDataUrl,
996                params.mCanLoadLocalResources);
997    }
998
999    /**
1000     * Stops loading the current web contents.
1001     */
1002    public void stopLoading() {
1003        reportActionAfterDoubleTapUMA(ContentViewCore.UMAActionAfterDoubleTap.NAVIGATE_STOP);
1004        if (mNativeContentViewCore != 0) nativeStopLoading(mNativeContentViewCore);
1005    }
1006
1007    /**
1008     * Get the URL of the current page.
1009     *
1010     * @return The URL of the current page.
1011     */
1012    public String getUrl() {
1013        if (mNativeContentViewCore != 0) return nativeGetURL(mNativeContentViewCore);
1014        return null;
1015    }
1016
1017    /**
1018     * Get the title of the current page.
1019     *
1020     * @return The title of the current page.
1021     */
1022    public String getTitle() {
1023        if (mNativeContentViewCore != 0) return nativeGetTitle(mNativeContentViewCore);
1024        return null;
1025    }
1026
1027    /**
1028     * Shows an interstitial page driven by the passed in delegate.
1029     *
1030     * @param url The URL being blocked by the interstitial.
1031     * @param delegate The delegate handling the interstitial.
1032     */
1033    @VisibleForTesting
1034    public void showInterstitialPage(
1035            String url, InterstitialPageDelegateAndroid delegate) {
1036        if (mNativeContentViewCore == 0) return;
1037        nativeShowInterstitialPage(mNativeContentViewCore, url, delegate.getNative());
1038    }
1039
1040    /**
1041     * @return Whether the page is currently showing an interstitial, such as a bad HTTPS page.
1042     */
1043    public boolean isShowingInterstitialPage() {
1044        return mNativeContentViewCore == 0 ?
1045                false : nativeIsShowingInterstitialPage(mNativeContentViewCore);
1046    }
1047
1048    /**
1049     * Mark any new frames that have arrived since this function was last called as non-pending.
1050     *
1051     * @return Whether there was a pending frame from the renderer.
1052     */
1053    public boolean consumePendingRendererFrame() {
1054        boolean hadPendingFrame = mPendingRendererFrame;
1055        mPendingRendererFrame = false;
1056        return hadPendingFrame;
1057    }
1058
1059    /**
1060     * @return Viewport width in physical pixels as set from onSizeChanged.
1061     */
1062    @CalledByNative
1063    public int getViewportWidthPix() { return mViewportWidthPix; }
1064
1065    /**
1066     * @return Viewport height in physical pixels as set from onSizeChanged.
1067     */
1068    @CalledByNative
1069    public int getViewportHeightPix() { return mViewportHeightPix; }
1070
1071    /**
1072     * @return Width of underlying physical surface.
1073     */
1074    @CalledByNative
1075    public int getPhysicalBackingWidthPix() { return mPhysicalBackingWidthPix; }
1076
1077    /**
1078     * @return Height of underlying physical surface.
1079     */
1080    @CalledByNative
1081    public int getPhysicalBackingHeightPix() { return mPhysicalBackingHeightPix; }
1082
1083    /**
1084     * @return Amount the output surface extends past the bottom of the window viewport.
1085     */
1086    @CalledByNative
1087    public int getOverdrawBottomHeightPix() { return mOverdrawBottomHeightPix; }
1088
1089    /**
1090     * @return The amount to shrink the viewport relative to {@link #getViewportWidthPix()}.
1091     */
1092    @CalledByNative
1093    public int getViewportSizeOffsetWidthPix() { return mViewportSizeOffsetWidthPix; }
1094
1095    /**
1096     * @return The amount to shrink the viewport relative to {@link #getViewportHeightPix()}.
1097     */
1098    @CalledByNative
1099    public int getViewportSizeOffsetHeightPix() { return mViewportSizeOffsetHeightPix; }
1100
1101    /**
1102     * @see android.webkit.WebView#getContentHeight()
1103     */
1104    public float getContentHeightCss() {
1105        return mRenderCoordinates.getContentHeightCss();
1106    }
1107
1108    /**
1109     * @see android.webkit.WebView#getContentWidth()
1110     */
1111    public float getContentWidthCss() {
1112        return mRenderCoordinates.getContentWidthCss();
1113    }
1114
1115    public Bitmap getBitmap() {
1116        return getBitmap(getViewportWidthPix(), getViewportHeightPix());
1117    }
1118
1119    public Bitmap getBitmap(int width, int height) {
1120        if (width == 0 || height == 0
1121                || getViewportWidthPix() == 0 || getViewportHeightPix() == 0) {
1122            return null;
1123        }
1124
1125        Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
1126
1127        if (mNativeContentViewCore != 0 &&
1128                nativePopulateBitmapFromCompositor(mNativeContentViewCore, b)) {
1129            // If we successfully grabbed a bitmap, check if we have to draw the Android overlay
1130            // components as well.
1131            if (mContainerView.getChildCount() > 0) {
1132                Canvas c = new Canvas(b);
1133                c.scale(width / (float) getViewportWidthPix(),
1134                        height / (float) getViewportHeightPix());
1135                mContainerView.draw(c);
1136            }
1137            return b;
1138        }
1139
1140        return null;
1141    }
1142
1143    /**
1144     * Generates a bitmap of the content that is performance optimized based on capture time.
1145     *
1146     * <p>
1147     * To have a consistent capture time across devices, we will scale down the captured bitmap
1148     * where necessary to reduce the time to generate the bitmap.
1149     *
1150     * @param width The width of the content to be captured.
1151     * @param height The height of the content to be captured.
1152     * @return A pair of the generated bitmap, and the scale that needs to be applied to return the
1153     *         bitmap to it's original size (i.e. if the bitmap is scaled down 50%, this
1154     *         will be 2).
1155     */
1156    public Pair<Bitmap, Float> getScaledPerformanceOptimizedBitmap(int width, int height) {
1157        float scale = 1f;
1158        // On tablets, always scale down to MDPI for performance reasons.
1159        if (DeviceUtils.isTablet(getContext())) {
1160            scale = getContext().getResources().getDisplayMetrics().density;
1161        }
1162        return Pair.create(
1163                getBitmap((int) (width / scale), (int) (height / scale)),
1164                scale);
1165    }
1166
1167    /**
1168     * @return Whether the current WebContents has a previous navigation entry.
1169     */
1170    public boolean canGoBack() {
1171        return mNativeContentViewCore != 0 && nativeCanGoBack(mNativeContentViewCore);
1172    }
1173
1174    /**
1175     * @return Whether the current WebContents has a navigation entry after the current one.
1176     */
1177    public boolean canGoForward() {
1178        return mNativeContentViewCore != 0 && nativeCanGoForward(mNativeContentViewCore);
1179    }
1180
1181    /**
1182     * @param offset The offset into the navigation history.
1183     * @return Whether we can move in history by given offset
1184     */
1185    public boolean canGoToOffset(int offset) {
1186        return mNativeContentViewCore != 0 && nativeCanGoToOffset(mNativeContentViewCore, offset);
1187    }
1188
1189    /**
1190     * Navigates to the specified offset from the "current entry". Does nothing if the offset is out
1191     * of bounds.
1192     * @param offset The offset into the navigation history.
1193     */
1194    public void goToOffset(int offset) {
1195        if (mNativeContentViewCore != 0) nativeGoToOffset(mNativeContentViewCore, offset);
1196    }
1197
1198    @Override
1199    public void goToNavigationIndex(int index) {
1200        if (mNativeContentViewCore != 0) nativeGoToNavigationIndex(mNativeContentViewCore, index);
1201    }
1202
1203    /**
1204     * Goes to the navigation entry before the current one.
1205     */
1206    public void goBack() {
1207        reportActionAfterDoubleTapUMA(ContentViewCore.UMAActionAfterDoubleTap.NAVIGATE_BACK);
1208        if (mNativeContentViewCore != 0) nativeGoBack(mNativeContentViewCore);
1209    }
1210
1211    /**
1212     * Goes to the navigation entry following the current one.
1213     */
1214    public void goForward() {
1215        if (mNativeContentViewCore != 0) nativeGoForward(mNativeContentViewCore);
1216    }
1217
1218    /**
1219     * Loads the current navigation if there is a pending lazy load (after tab restore).
1220     */
1221    public void loadIfNecessary() {
1222        if (mNativeContentViewCore != 0) nativeLoadIfNecessary(mNativeContentViewCore);
1223    }
1224
1225    /**
1226     * Requests the current navigation to be loaded upon the next call to loadIfNecessary().
1227     */
1228    public void requestRestoreLoad() {
1229        if (mNativeContentViewCore != 0) nativeRequestRestoreLoad(mNativeContentViewCore);
1230    }
1231
1232    /**
1233     * Reload the current page.
1234     */
1235    public void reload(boolean checkForRepost) {
1236        mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary();
1237        if (mNativeContentViewCore != 0) {
1238            nativeReload(mNativeContentViewCore, checkForRepost);
1239        }
1240    }
1241
1242    /**
1243     * Reload the current page, ignoring the contents of the cache.
1244     */
1245    public void reloadIgnoringCache(boolean checkForRepost) {
1246        mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary();
1247        if (mNativeContentViewCore != 0) {
1248            nativeReloadIgnoringCache(mNativeContentViewCore, checkForRepost);
1249        }
1250    }
1251
1252    /**
1253     * Cancel the pending reload.
1254     */
1255    public void cancelPendingReload() {
1256        if (mNativeContentViewCore != 0) nativeCancelPendingReload(mNativeContentViewCore);
1257    }
1258
1259    /**
1260     * Continue the pending reload.
1261     */
1262    public void continuePendingReload() {
1263        if (mNativeContentViewCore != 0) nativeContinuePendingReload(mNativeContentViewCore);
1264    }
1265
1266    /**
1267     * Clears the ContentViewCore's page history in both the backwards and
1268     * forwards directions.
1269     */
1270    public void clearHistory() {
1271        if (mNativeContentViewCore != 0) nativeClearHistory(mNativeContentViewCore);
1272    }
1273
1274    /**
1275     * @return The selected text (empty if no text selected).
1276     */
1277    public String getSelectedText() {
1278        return mHasSelection ? mLastSelectedText : "";
1279    }
1280
1281    /**
1282     * @return Whether the current selection is editable (false if no text selected).
1283     */
1284    public boolean isSelectionEditable() {
1285        return mHasSelection ? mSelectionEditable : false;
1286    }
1287
1288    // End FrameLayout overrides.
1289
1290    /**
1291     * @see View#onTouchEvent(MotionEvent)
1292     */
1293    public boolean onTouchEvent(MotionEvent event) {
1294        undoScrollFocusedEditableNodeIntoViewIfNeeded(false);
1295        if (!mRequestedVSyncForInput) {
1296            mRequestedVSyncForInput = true;
1297            addVSyncSubscriber();
1298        }
1299        return mContentViewGestureHandler.onTouchEvent(event);
1300    }
1301
1302    /**
1303     * @return ContentViewGestureHandler for all MotionEvent and gesture related calls.
1304     */
1305    ContentViewGestureHandler getContentViewGestureHandler() {
1306        return mContentViewGestureHandler;
1307    }
1308
1309    @Override
1310    public boolean sendTouchEvent(long timeMs, int action, TouchPoint[] pts) {
1311        if (mNativeContentViewCore != 0) {
1312            return nativeSendTouchEvent(mNativeContentViewCore, timeMs, action, pts);
1313        }
1314        return false;
1315    }
1316
1317    @SuppressWarnings("unused")
1318    @CalledByNative
1319    private void hasTouchEventHandlers(boolean hasTouchHandlers) {
1320        mContentViewGestureHandler.hasTouchEventHandlers(hasTouchHandlers);
1321    }
1322
1323    @SuppressWarnings("unused")
1324    @CalledByNative
1325    private void confirmTouchEvent(int ackResult) {
1326        mContentViewGestureHandler.confirmTouchEvent(ackResult);
1327    }
1328
1329    @SuppressWarnings("unused")
1330    @CalledByNative
1331    private void unhandledFlingStartEvent() {
1332        if (mGestureStateListener != null) {
1333            mGestureStateListener.onUnhandledFlingStartEvent();
1334        }
1335    }
1336
1337    @SuppressWarnings("unused")
1338    @CalledByNative
1339    private void onScrollUpdateGestureConsumed() {
1340        if (mGestureStateListener != null) {
1341            mGestureStateListener.onScrollUpdateGestureConsumed();
1342        }
1343    }
1344
1345    private void reportActionAfterDoubleTapUMA(int type) {
1346        mContentViewGestureHandler.reportActionAfterDoubleTapUMA(type);
1347    }
1348
1349    @Override
1350    public boolean sendGesture(int type, long timeMs, int x, int y, Bundle b) {
1351        if (offerGestureToEmbedder(type)) return false;
1352        if (mNativeContentViewCore == 0) return false;
1353        updateTextHandlesForGesture(type);
1354        updateGestureStateListener(type, b);
1355        switch (type) {
1356            case ContentViewGestureHandler.GESTURE_SHOW_PRESSED_STATE:
1357                nativeShowPressState(mNativeContentViewCore, timeMs, x, y);
1358                return true;
1359            case ContentViewGestureHandler.GESTURE_TAP_CANCEL:
1360                nativeTapCancel(mNativeContentViewCore, timeMs, x, y);
1361                return true;
1362            case ContentViewGestureHandler.GESTURE_TAP_DOWN:
1363                nativeTapDown(mNativeContentViewCore, timeMs, x, y);
1364                return true;
1365            case ContentViewGestureHandler.GESTURE_DOUBLE_TAP:
1366                nativeDoubleTap(mNativeContentViewCore, timeMs, x, y);
1367                return true;
1368            case ContentViewGestureHandler.GESTURE_SINGLE_TAP_UP:
1369                nativeSingleTap(mNativeContentViewCore, timeMs, x, y, false);
1370                return true;
1371            case ContentViewGestureHandler.GESTURE_SINGLE_TAP_CONFIRMED:
1372                handleTapOrPress(timeMs, x, y, 0,
1373                        b.getBoolean(ContentViewGestureHandler.SHOW_PRESS, false));
1374                return true;
1375            case ContentViewGestureHandler.GESTURE_SINGLE_TAP_UNCONFIRMED:
1376                nativeSingleTapUnconfirmed(mNativeContentViewCore, timeMs, x, y);
1377                return true;
1378            case ContentViewGestureHandler.GESTURE_LONG_PRESS:
1379                handleTapOrPress(timeMs, x, y, IS_LONG_PRESS, false);
1380                return true;
1381            case ContentViewGestureHandler.GESTURE_LONG_TAP:
1382                handleTapOrPress(timeMs, x, y, IS_LONG_TAP, false);
1383                return true;
1384            case ContentViewGestureHandler.GESTURE_SCROLL_START:
1385                nativeScrollBegin(mNativeContentViewCore, timeMs, x, y);
1386                return true;
1387            case ContentViewGestureHandler.GESTURE_SCROLL_BY: {
1388                int dx = b.getInt(ContentViewGestureHandler.DISTANCE_X);
1389                int dy = b.getInt(ContentViewGestureHandler.DISTANCE_Y);
1390                nativeScrollBy(mNativeContentViewCore, timeMs, x, y, dx, dy);
1391                return true;
1392            }
1393            case ContentViewGestureHandler.GESTURE_SCROLL_END:
1394                nativeScrollEnd(mNativeContentViewCore, timeMs);
1395                return true;
1396            case ContentViewGestureHandler.GESTURE_FLING_START:
1397                nativeFlingStart(mNativeContentViewCore, timeMs, x, y,
1398                        b.getInt(ContentViewGestureHandler.VELOCITY_X, 0),
1399                        b.getInt(ContentViewGestureHandler.VELOCITY_Y, 0));
1400                return true;
1401            case ContentViewGestureHandler.GESTURE_FLING_CANCEL:
1402                nativeFlingCancel(mNativeContentViewCore, timeMs);
1403                return true;
1404            case ContentViewGestureHandler.GESTURE_PINCH_BEGIN:
1405                nativePinchBegin(mNativeContentViewCore, timeMs, x, y);
1406                return true;
1407            case ContentViewGestureHandler.GESTURE_PINCH_BY:
1408                nativePinchBy(mNativeContentViewCore, timeMs, x, y,
1409                        b.getFloat(ContentViewGestureHandler.DELTA, 0));
1410                return true;
1411            case ContentViewGestureHandler.GESTURE_PINCH_END:
1412                nativePinchEnd(mNativeContentViewCore, timeMs);
1413                return true;
1414            default:
1415                return false;
1416        }
1417    }
1418
1419    @VisibleForTesting
1420    public void sendDoubleTapForTest(long timeMs, int x, int y, Bundle b) {
1421        sendGesture(ContentViewGestureHandler.GESTURE_DOUBLE_TAP, timeMs, x, y, b);
1422    }
1423
1424    @Override
1425    public void sendSingleTapUMA(int type) {
1426        if (mNativeContentViewCore == 0) return;
1427        nativeSendSingleTapUma(
1428                mNativeContentViewCore,
1429                type,
1430                UMASingleTapType.COUNT);
1431    }
1432
1433    @Override
1434    public void sendActionAfterDoubleTapUMA(int type,
1435            boolean clickDelayEnabled) {
1436        if (mNativeContentViewCore == 0) return;
1437        nativeSendActionAfterDoubleTapUma(
1438                mNativeContentViewCore,
1439                type,
1440                clickDelayEnabled,
1441                UMAActionAfterDoubleTap.COUNT);
1442    }
1443
1444    public void setGestureStateListener(GestureStateListener pinchGestureStateListener) {
1445        mGestureStateListener = pinchGestureStateListener;
1446    }
1447
1448    void updateGestureStateListener(int gestureType, Bundle b) {
1449        if (mGestureStateListener == null) return;
1450
1451        switch (gestureType) {
1452            case ContentViewGestureHandler.GESTURE_PINCH_BEGIN:
1453                mGestureStateListener.onPinchGestureStart();
1454                break;
1455            case ContentViewGestureHandler.GESTURE_PINCH_END:
1456                mGestureStateListener.onPinchGestureEnd();
1457                break;
1458            case ContentViewGestureHandler.GESTURE_FLING_START:
1459                mGestureStateListener.onFlingStartGesture(
1460                        b.getInt(ContentViewGestureHandler.VELOCITY_X, 0),
1461                        b.getInt(ContentViewGestureHandler.VELOCITY_Y, 0));
1462                break;
1463            case ContentViewGestureHandler.GESTURE_FLING_CANCEL:
1464                mGestureStateListener.onFlingCancelGesture();
1465                break;
1466            default:
1467                break;
1468        }
1469    }
1470
1471    public interface JavaScriptCallback {
1472        void handleJavaScriptResult(String jsonResult);
1473    }
1474
1475    /**
1476     * Injects the passed Javascript code in the current page and evaluates it.
1477     * If a result is required, pass in a callback.
1478     * Used in automation tests.
1479     *
1480     * @param script The Javascript to execute.
1481     * @param callback The callback to be fired off when a result is ready. The script's
1482     *                 result will be json encoded and passed as the parameter, and the call
1483     *                 will be made on the main thread.
1484     *                 If no result is required, pass null.
1485     */
1486    public void evaluateJavaScript(String script, JavaScriptCallback callback) {
1487        if (mNativeContentViewCore == 0) return;
1488        nativeEvaluateJavaScript(mNativeContentViewCore, script, callback, false);
1489    }
1490
1491    /**
1492     * Injects the passed Javascript code in the current page and evaluates it.
1493     * If there is no page existing, a new one will be created.
1494     *
1495     * @param script The Javascript to execute.
1496     */
1497    public void evaluateJavaScriptEvenIfNotYetNavigated(String script) {
1498        if (mNativeContentViewCore == 0) return;
1499        nativeEvaluateJavaScript(mNativeContentViewCore, script, null, true);
1500    }
1501
1502    /**
1503     * To be called when the ContentView is shown.
1504     */
1505    public void onShow() {
1506        assert mNativeContentViewCore != 0;
1507        if (!mInForeground) {
1508            int pid = nativeGetCurrentRenderProcessId(mNativeContentViewCore);
1509            ChildProcessLauncher.getBindingManager().bindAsHighPriority(pid);
1510            // Normally the initial binding is removed in onRenderProcessSwap(), but it is possible
1511            // to construct WebContents and spawn the renderer before passing it to ContentViewCore.
1512            // In this case there will be no onRenderProcessSwap() call and the initial binding will
1513            // be removed here.
1514            ChildProcessLauncher.getBindingManager().removeInitialBinding(pid);
1515        }
1516        mInForeground = true;
1517        nativeOnShow(mNativeContentViewCore);
1518        setAccessibilityState(mAccessibilityManager.isEnabled());
1519    }
1520
1521    /**
1522     * To be called when the ContentView is hidden.
1523     */
1524    public void onHide() {
1525        assert mNativeContentViewCore != 0;
1526        if (mInForeground) {
1527            int pid = nativeGetCurrentRenderProcessId(mNativeContentViewCore);
1528            ChildProcessLauncher.getBindingManager().unbindAsHighPriority(pid);
1529        }
1530        mInForeground = false;
1531        hidePopupDialog();
1532        setInjectedAccessibility(false);
1533        nativeOnHide(mNativeContentViewCore);
1534    }
1535
1536    /**
1537     * Return the ContentSettings object used to retrieve the settings for this
1538     * ContentViewCore. For modifications, ChromeNativePreferences is to be used.
1539     * @return A ContentSettings object that can be used to retrieve this
1540     *         ContentViewCore's settings.
1541     */
1542    public ContentSettings getContentSettings() {
1543        return mContentSettings;
1544    }
1545
1546    @Override
1547    public boolean didUIStealScroll(float x, float y) {
1548        return getContentViewClient().shouldOverrideScroll(
1549                x, y, computeHorizontalScrollOffset(), computeVerticalScrollOffset());
1550    }
1551
1552    private void onRenderCoordinatesUpdated() {
1553        if (mContentViewGestureHandler == null) return;
1554
1555        // We disable double tap zoom for pages that have a width=device-width
1556        // or narrower viewport (indicating that this is a mobile-optimized or
1557        // responsive web design, so text will be legible without zooming).
1558        // We also disable it for pages that disallow the user from zooming in
1559        // or out (even if they don't have a device-width or narrower viewport).
1560        mContentViewGestureHandler.updateShouldDisableDoubleTap(
1561                mRenderCoordinates.hasMobileViewport() || mRenderCoordinates.hasFixedPageScale());
1562    }
1563
1564    private void hidePopupDialog() {
1565        SelectPopupDialog.hide(this);
1566        hideHandles();
1567        hideSelectActionBar();
1568    }
1569
1570    void hideSelectActionBar() {
1571        if (mActionMode != null) {
1572            mActionMode.finish();
1573            mActionMode = null;
1574        }
1575    }
1576
1577    public boolean isSelectActionBarShowing() {
1578        return mActionMode != null;
1579    }
1580
1581    private void resetGestureDetectors() {
1582        mContentViewGestureHandler.resetGestureHandlers();
1583    }
1584
1585    /**
1586     * @see View#onAttachedToWindow()
1587     */
1588    @SuppressWarnings("javadoc")
1589    public void onAttachedToWindow() {
1590        setAccessibilityState(mAccessibilityManager.isEnabled());
1591    }
1592
1593    /**
1594     * @see View#onDetachedFromWindow()
1595     */
1596    @SuppressWarnings("javadoc")
1597    public void onDetachedFromWindow() {
1598        setInjectedAccessibility(false);
1599        hidePopupDialog();
1600        mZoomControlsDelegate.dismissZoomPicker();
1601        unregisterAccessibilityContentObserver();
1602    }
1603
1604    /**
1605     * @see View#onVisibilityChanged(android.view.View, int)
1606     */
1607    public void onVisibilityChanged(View changedView, int visibility) {
1608        if (visibility != View.VISIBLE) {
1609            mZoomControlsDelegate.dismissZoomPicker();
1610        }
1611    }
1612
1613    /**
1614     * @see View#onCreateInputConnection(EditorInfo)
1615     */
1616    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
1617        if (!mImeAdapter.hasTextInputType()) {
1618            // Although onCheckIsTextEditor will return false in this case, the EditorInfo
1619            // is still used by the InputMethodService. Need to make sure the IME doesn't
1620            // enter fullscreen mode.
1621            outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN;
1622        }
1623        mInputConnection =
1624                mAdapterInputConnectionFactory.get(mContainerView, mImeAdapter, outAttrs);
1625        return mInputConnection;
1626    }
1627
1628    public Editable getEditableForTest() {
1629        return mInputConnection.getEditable();
1630    }
1631
1632    /**
1633     * @see View#onCheckIsTextEditor()
1634     */
1635    public boolean onCheckIsTextEditor() {
1636        return mImeAdapter.hasTextInputType();
1637    }
1638
1639    /**
1640     * @see View#onConfigurationChanged(Configuration)
1641     */
1642    @SuppressWarnings("javadoc")
1643    public void onConfigurationChanged(Configuration newConfig) {
1644        TraceEvent.begin();
1645
1646        if (newConfig.keyboard != Configuration.KEYBOARD_NOKEYS) {
1647            mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore),
1648                    ImeAdapter.getTextInputTypeNone(),
1649                    AdapterInputConnection.INVALID_SELECTION,
1650                    AdapterInputConnection.INVALID_SELECTION);
1651            InputMethodManager manager = (InputMethodManager)
1652                    getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
1653            manager.restartInput(mContainerView);
1654        }
1655        mContainerViewInternals.super_onConfigurationChanged(newConfig);
1656        // Make sure the size is up to date in JavaScript's window.onorientationchanged.
1657        mContainerView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
1658            @Override
1659            public void onLayoutChange(View v, int left, int top, int right, int bottom,
1660                    int oldLeft, int oldTop, int oldRight, int oldBottom) {
1661                mContainerView.removeOnLayoutChangeListener(this);
1662                sendOrientationChangeEvent();
1663            }
1664        });
1665        // To request layout has side effect, but it seems OK as it only happen in
1666        // onConfigurationChange and layout has to be changed in most case.
1667        mContainerView.requestLayout();
1668        TraceEvent.end();
1669    }
1670
1671    /**
1672     * @see View#onSizeChanged(int, int, int, int)
1673     */
1674    @SuppressWarnings("javadoc")
1675    public void onSizeChanged(int wPix, int hPix, int owPix, int ohPix) {
1676        if (getViewportWidthPix() == wPix && getViewportHeightPix() == hPix) return;
1677
1678        mViewportWidthPix = wPix;
1679        mViewportHeightPix = hPix;
1680        if (mNativeContentViewCore != 0) {
1681            nativeWasResized(mNativeContentViewCore);
1682        }
1683
1684        updateAfterSizeChanged();
1685    }
1686
1687    /**
1688     * Called when the ContentView's position in the activity window changed. This information is
1689     * used for cropping screenshots.
1690     */
1691    public void onLocationInWindowChanged(int x, int y) {
1692        mLocationInWindowX = x;
1693        mLocationInWindowY = y;
1694    }
1695
1696    /**
1697     * Called when the underlying surface the compositor draws to changes size.
1698     * This may be larger than the viewport size.
1699     */
1700    public void onPhysicalBackingSizeChanged(int wPix, int hPix) {
1701        if (mPhysicalBackingWidthPix == wPix && mPhysicalBackingHeightPix == hPix) return;
1702
1703        mPhysicalBackingWidthPix = wPix;
1704        mPhysicalBackingHeightPix = hPix;
1705
1706        if (mNativeContentViewCore != 0) {
1707            nativeWasResized(mNativeContentViewCore);
1708        }
1709    }
1710
1711    /**
1712     * Called when the amount the surface is overdrawing off the bottom has changed.
1713     * @param overdrawHeightPix The overdraw height.
1714     */
1715    public void onOverdrawBottomHeightChanged(int overdrawHeightPix) {
1716        if (mOverdrawBottomHeightPix == overdrawHeightPix) return;
1717
1718        mOverdrawBottomHeightPix = overdrawHeightPix;
1719
1720        if (mNativeContentViewCore != 0) {
1721            nativeWasResized(mNativeContentViewCore);
1722        }
1723    }
1724
1725    private void updateAfterSizeChanged() {
1726        mPopupZoomer.hide(false);
1727
1728        // Execute a delayed form focus operation because the OSK was brought
1729        // up earlier.
1730        if (!mFocusPreOSKViewportRect.isEmpty()) {
1731            Rect rect = new Rect();
1732            getContainerView().getWindowVisibleDisplayFrame(rect);
1733            if (!rect.equals(mFocusPreOSKViewportRect)) {
1734                // Only assume the OSK triggered the onSizeChanged if width was preserved.
1735                if (rect.width() == mFocusPreOSKViewportRect.width()) {
1736                    scrollFocusedEditableNodeIntoView();
1737                }
1738                mFocusPreOSKViewportRect.setEmpty();
1739            }
1740        } else if (mUnfocusOnNextSizeChanged) {
1741            undoScrollFocusedEditableNodeIntoViewIfNeeded(true);
1742            mUnfocusOnNextSizeChanged = false;
1743        }
1744    }
1745
1746    private void scrollFocusedEditableNodeIntoView() {
1747        if (mNativeContentViewCore != 0) {
1748            Runnable scrollTask = new Runnable() {
1749                @Override
1750                public void run() {
1751                    if (mNativeContentViewCore != 0) {
1752                        nativeScrollFocusedEditableNodeIntoView(mNativeContentViewCore);
1753                    }
1754                }
1755            };
1756
1757            scrollTask.run();
1758
1759            // The native side keeps track of whether the zoom and scroll actually occurred. It is
1760            // more efficient to do it this way and sometimes fire an unnecessary message rather
1761            // than synchronize with the renderer and always have an additional message.
1762            mScrolledAndZoomedFocusedEditableNode = true;
1763        }
1764    }
1765
1766    private void undoScrollFocusedEditableNodeIntoViewIfNeeded(boolean backButtonPressed) {
1767        // The only call to this function that matters is the first call after the
1768        // scrollFocusedEditableNodeIntoView function call.
1769        // If the first call to this function is a result of a back button press we want to undo the
1770        // preceding scroll. If the call is a result of some other action we don't want to perform
1771        // an undo.
1772        // All subsequent calls are ignored since only the scroll function sets
1773        // mScrolledAndZoomedFocusedEditableNode to true.
1774        if (mScrolledAndZoomedFocusedEditableNode && backButtonPressed &&
1775                mNativeContentViewCore != 0) {
1776            Runnable scrollTask = new Runnable() {
1777                @Override
1778                public void run() {
1779                    if (mNativeContentViewCore != 0) {
1780                        nativeUndoScrollFocusedEditableNodeIntoView(mNativeContentViewCore);
1781                    }
1782                }
1783            };
1784
1785            scrollTask.run();
1786        }
1787        mScrolledAndZoomedFocusedEditableNode = false;
1788    }
1789
1790    /**
1791     * @see View#onWindowFocusChanged(boolean)
1792     */
1793    public void onWindowFocusChanged(boolean hasWindowFocus) {
1794        if (!hasWindowFocus) {
1795            mContentViewGestureHandler.onWindowFocusLost();
1796        }
1797    }
1798
1799    public void onFocusChanged(boolean gainFocus) {
1800        if (!gainFocus) getContentViewClient().onImeStateChangeRequested(false);
1801        if (mNativeContentViewCore != 0) nativeSetFocus(mNativeContentViewCore, gainFocus);
1802    }
1803
1804    /**
1805     * @see View#onKeyUp(int, KeyEvent)
1806     */
1807    public boolean onKeyUp(int keyCode, KeyEvent event) {
1808        if (mPopupZoomer.isShowing() && keyCode == KeyEvent.KEYCODE_BACK) {
1809            mPopupZoomer.hide(true);
1810            return true;
1811        }
1812        return mContainerViewInternals.super_onKeyUp(keyCode, event);
1813    }
1814
1815    /**
1816     * @see View#dispatchKeyEventPreIme(KeyEvent)
1817     */
1818    public boolean dispatchKeyEventPreIme(KeyEvent event) {
1819        try {
1820            TraceEvent.begin();
1821            if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && mImeAdapter.isActive()) {
1822                mUnfocusOnNextSizeChanged = true;
1823            } else {
1824                undoScrollFocusedEditableNodeIntoViewIfNeeded(false);
1825            }
1826            return mContainerViewInternals.super_dispatchKeyEventPreIme(event);
1827        } finally {
1828            TraceEvent.end();
1829        }
1830    }
1831
1832    /**
1833     * @see View#dispatchKeyEvent(KeyEvent)
1834     */
1835    public boolean dispatchKeyEvent(KeyEvent event) {
1836        if (getContentViewClient().shouldOverrideKeyEvent(event)) {
1837            return mContainerViewInternals.super_dispatchKeyEvent(event);
1838        }
1839
1840        if (mImeAdapter.dispatchKeyEvent(event)) return true;
1841
1842        return mContainerViewInternals.super_dispatchKeyEvent(event);
1843    }
1844
1845    /**
1846     * @see View#onHoverEvent(MotionEvent)
1847     * Mouse move events are sent on hover enter, hover move and hover exit.
1848     * They are sent on hover exit because sometimes it acts as both a hover
1849     * move and hover exit.
1850     */
1851    public boolean onHoverEvent(MotionEvent event) {
1852        TraceEvent.begin("onHoverEvent");
1853        mContainerView.removeCallbacks(mFakeMouseMoveRunnable);
1854        if (mBrowserAccessibilityManager != null) {
1855            return mBrowserAccessibilityManager.onHoverEvent(event);
1856        }
1857        if (mNativeContentViewCore != 0) {
1858            nativeSendMouseMoveEvent(mNativeContentViewCore, event.getEventTime(),
1859                    event.getX(), event.getY());
1860        }
1861        TraceEvent.end("onHoverEvent");
1862        return true;
1863    }
1864
1865    /**
1866     * @see View#onGenericMotionEvent(MotionEvent)
1867     */
1868    public boolean onGenericMotionEvent(MotionEvent event) {
1869        if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
1870            switch (event.getAction()) {
1871                case MotionEvent.ACTION_SCROLL:
1872                    nativeSendMouseWheelEvent(mNativeContentViewCore, event.getEventTime(),
1873                            event.getX(), event.getY(),
1874                            event.getAxisValue(MotionEvent.AXIS_VSCROLL));
1875
1876                    mContainerView.removeCallbacks(mFakeMouseMoveRunnable);
1877                    // Send a delayed onMouseMove event so that we end
1878                    // up hovering over the right position after the scroll.
1879                    final MotionEvent eventFakeMouseMove = MotionEvent.obtain(event);
1880                    mFakeMouseMoveRunnable = new Runnable() {
1881                        @Override
1882                        public void run() {
1883                            onHoverEvent(eventFakeMouseMove);
1884                        }
1885                    };
1886                    mContainerView.postDelayed(mFakeMouseMoveRunnable, 250);
1887                    return true;
1888            }
1889        }
1890        return mContainerViewInternals.super_onGenericMotionEvent(event);
1891    }
1892
1893    /**
1894     * @see View#scrollBy(int, int)
1895     * Currently the ContentView scrolling happens in the native side. In
1896     * the Java view system, it is always pinned at (0, 0). scrollBy() and scrollTo()
1897     * are overridden, so that View's mScrollX and mScrollY will be unchanged at
1898     * (0, 0). This is critical for drawing ContentView correctly.
1899     */
1900    public void scrollBy(int xPix, int yPix) {
1901        if (mNativeContentViewCore != 0) {
1902            nativeScrollBy(mNativeContentViewCore,
1903                    System.currentTimeMillis(), 0, 0, xPix, yPix);
1904        }
1905    }
1906
1907    /**
1908     * @see View#scrollTo(int, int)
1909     */
1910    public void scrollTo(int xPix, int yPix) {
1911        if (mNativeContentViewCore == 0) return;
1912        final float xCurrentPix = mRenderCoordinates.getScrollXPix();
1913        final float yCurrentPix = mRenderCoordinates.getScrollYPix();
1914        final float dxPix = xPix - xCurrentPix;
1915        final float dyPix = yPix - yCurrentPix;
1916        if (dxPix != 0 || dyPix != 0) {
1917            long time = System.currentTimeMillis();
1918            nativeScrollBegin(mNativeContentViewCore, time, xCurrentPix, yCurrentPix);
1919            nativeScrollBy(mNativeContentViewCore,
1920                    time, xCurrentPix, yCurrentPix, dxPix, dyPix);
1921            nativeScrollEnd(mNativeContentViewCore, time);
1922        }
1923    }
1924
1925    // NOTE: this can go away once ContentView.getScrollX() reports correct values.
1926    //       see: b/6029133
1927    public int getNativeScrollXForTest() {
1928        return mRenderCoordinates.getScrollXPixInt();
1929    }
1930
1931    // NOTE: this can go away once ContentView.getScrollY() reports correct values.
1932    //       see: b/6029133
1933    public int getNativeScrollYForTest() {
1934        return mRenderCoordinates.getScrollYPixInt();
1935    }
1936
1937    /**
1938     * @see View#computeHorizontalScrollExtent()
1939     */
1940    @SuppressWarnings("javadoc")
1941    public int computeHorizontalScrollExtent() {
1942        return mRenderCoordinates.getLastFrameViewportWidthPixInt();
1943    }
1944
1945    /**
1946     * @see View#computeHorizontalScrollOffset()
1947     */
1948    @SuppressWarnings("javadoc")
1949    public int computeHorizontalScrollOffset() {
1950        return mRenderCoordinates.getScrollXPixInt();
1951    }
1952
1953    /**
1954     * @see View#computeHorizontalScrollRange()
1955     */
1956    @SuppressWarnings("javadoc")
1957    public int computeHorizontalScrollRange() {
1958        return mRenderCoordinates.getContentWidthPixInt();
1959    }
1960
1961    /**
1962     * @see View#computeVerticalScrollExtent()
1963     */
1964    @SuppressWarnings("javadoc")
1965    public int computeVerticalScrollExtent() {
1966        return mRenderCoordinates.getLastFrameViewportHeightPixInt();
1967    }
1968
1969    /**
1970     * @see View#computeVerticalScrollOffset()
1971     */
1972    @SuppressWarnings("javadoc")
1973    public int computeVerticalScrollOffset() {
1974        return mRenderCoordinates.getScrollYPixInt();
1975    }
1976
1977    /**
1978     * @see View#computeVerticalScrollRange()
1979     */
1980    @SuppressWarnings("javadoc")
1981    public int computeVerticalScrollRange() {
1982        return mRenderCoordinates.getContentHeightPixInt();
1983    }
1984
1985    // End FrameLayout overrides.
1986
1987    /**
1988     * @see View#awakenScrollBars(int, boolean)
1989     */
1990    @SuppressWarnings("javadoc")
1991    public boolean awakenScrollBars(int startDelay, boolean invalidate) {
1992        // For the default implementation of ContentView which draws the scrollBars on the native
1993        // side, calling this function may get us into a bad state where we keep drawing the
1994        // scrollBars, so disable it by always returning false.
1995        if (mContainerView.getScrollBarStyle() == View.SCROLLBARS_INSIDE_OVERLAY) {
1996            return false;
1997        } else {
1998            return mContainerViewInternals.super_awakenScrollBars(startDelay, invalidate);
1999        }
2000    }
2001
2002    private void handleTapOrPress(
2003            long timeMs, float xPix, float yPix, int isLongPressOrTap, boolean showPress) {
2004        if (mContainerView.isFocusable() && mContainerView.isFocusableInTouchMode()
2005                && !mContainerView.isFocused())  {
2006            mContainerView.requestFocus();
2007        }
2008
2009        if (!mPopupZoomer.isShowing()) mPopupZoomer.setLastTouch(xPix, yPix);
2010
2011        if (isLongPressOrTap == IS_LONG_PRESS) {
2012            getInsertionHandleController().allowAutomaticShowing();
2013            getSelectionHandleController().allowAutomaticShowing();
2014            if (mNativeContentViewCore != 0) {
2015                nativeLongPress(mNativeContentViewCore, timeMs, xPix, yPix, false);
2016            }
2017        } else if (isLongPressOrTap == IS_LONG_TAP) {
2018            getInsertionHandleController().allowAutomaticShowing();
2019            getSelectionHandleController().allowAutomaticShowing();
2020            if (mNativeContentViewCore != 0) {
2021                nativeLongTap(mNativeContentViewCore, timeMs, xPix, yPix, false);
2022            }
2023        } else {
2024            if (!showPress && mNativeContentViewCore != 0) {
2025                nativeShowPressState(mNativeContentViewCore, timeMs, xPix, yPix);
2026            }
2027            if (mSelectionEditable) getInsertionHandleController().allowAutomaticShowing();
2028            if (mNativeContentViewCore != 0) {
2029                nativeSingleTap(mNativeContentViewCore, timeMs, xPix, yPix, false);
2030            }
2031        }
2032    }
2033
2034    public void setZoomControlsDelegate(ZoomControlsDelegate zoomControlsDelegate) {
2035        mZoomControlsDelegate = zoomControlsDelegate;
2036    }
2037
2038    public void updateMultiTouchZoomSupport(boolean supportsMultiTouchZoom) {
2039        mZoomManager.updateMultiTouchSupport(supportsMultiTouchZoom);
2040    }
2041
2042    public void updateDoubleTapSupport(boolean supportsDoubleTap) {
2043        mContentViewGestureHandler.updateDoubleTapSupport(supportsDoubleTap);
2044    }
2045
2046    public void selectPopupMenuItems(int[] indices) {
2047        if (mNativeContentViewCore != 0) {
2048            nativeSelectPopupMenuItems(mNativeContentViewCore, indices);
2049        }
2050    }
2051
2052    /**
2053     * Get the screen orientation from the OS and push it to WebKit.
2054     *
2055     * TODO(husky): Add a hook for mock orientations.
2056     */
2057    private void sendOrientationChangeEvent() {
2058        if (mNativeContentViewCore == 0) return;
2059
2060        WindowManager windowManager =
2061                (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
2062        switch (windowManager.getDefaultDisplay().getRotation()) {
2063            case Surface.ROTATION_90:
2064                nativeSendOrientationChangeEvent(mNativeContentViewCore, 90);
2065                break;
2066            case Surface.ROTATION_180:
2067                nativeSendOrientationChangeEvent(mNativeContentViewCore, 180);
2068                break;
2069            case Surface.ROTATION_270:
2070                nativeSendOrientationChangeEvent(mNativeContentViewCore, -90);
2071                break;
2072            case Surface.ROTATION_0:
2073                nativeSendOrientationChangeEvent(mNativeContentViewCore, 0);
2074                break;
2075            default:
2076                Log.w(TAG, "Unknown rotation!");
2077                break;
2078        }
2079    }
2080
2081    /**
2082     * Register the delegate to be used when content can not be handled by
2083     * the rendering engine, and should be downloaded instead. This will replace
2084     * the current delegate, if any.
2085     * @param delegate An implementation of ContentViewDownloadDelegate.
2086     */
2087    public void setDownloadDelegate(ContentViewDownloadDelegate delegate) {
2088        mDownloadDelegate = delegate;
2089    }
2090
2091    // Called by DownloadController.
2092    ContentViewDownloadDelegate getDownloadDelegate() {
2093        return mDownloadDelegate;
2094    }
2095
2096    private SelectionHandleController getSelectionHandleController() {
2097        if (mSelectionHandleController == null) {
2098            mSelectionHandleController = new SelectionHandleController(
2099                    getContainerView(), mPositionObserver) {
2100                @Override
2101                public void selectBetweenCoordinates(int x1, int y1, int x2, int y2) {
2102                    if (mNativeContentViewCore != 0 && !(x1 == x2 && y1 == y2)) {
2103                        nativeSelectBetweenCoordinates(mNativeContentViewCore,
2104                                x1, y1 - mRenderCoordinates.getContentOffsetYPix(),
2105                                x2, y2 - mRenderCoordinates.getContentOffsetYPix());
2106                    }
2107                }
2108
2109                @Override
2110                public void showHandles(int startDir, int endDir) {
2111                    super.showHandles(startDir, endDir);
2112                    showSelectActionBar();
2113                }
2114
2115            };
2116
2117            mSelectionHandleController.hideAndDisallowAutomaticShowing();
2118        }
2119
2120        return mSelectionHandleController;
2121    }
2122
2123    private InsertionHandleController getInsertionHandleController() {
2124        if (mInsertionHandleController == null) {
2125            mInsertionHandleController = new InsertionHandleController(
2126                    getContainerView(), mPositionObserver) {
2127                private static final int AVERAGE_LINE_HEIGHT = 14;
2128
2129                @Override
2130                public void setCursorPosition(int x, int y) {
2131                    if (mNativeContentViewCore != 0) {
2132                        nativeMoveCaret(mNativeContentViewCore,
2133                                x, y - mRenderCoordinates.getContentOffsetYPix());
2134                    }
2135                }
2136
2137                @Override
2138                public void paste() {
2139                    mImeAdapter.paste();
2140                    hideHandles();
2141                }
2142
2143                @Override
2144                public int getLineHeight() {
2145                    return (int) Math.ceil(
2146                            mRenderCoordinates.fromLocalCssToPix(AVERAGE_LINE_HEIGHT));
2147                }
2148
2149                @Override
2150                public void showHandle() {
2151                    super.showHandle();
2152                }
2153            };
2154
2155            mInsertionHandleController.hideAndDisallowAutomaticShowing();
2156        }
2157
2158        return mInsertionHandleController;
2159    }
2160
2161    @VisibleForTesting
2162    public InsertionHandleController getInsertionHandleControllerForTest() {
2163        return mInsertionHandleController;
2164    }
2165
2166    @VisibleForTesting
2167    public SelectionHandleController getSelectionHandleControllerForTest() {
2168        return mSelectionHandleController;
2169    }
2170
2171    private void updateHandleScreenPositions() {
2172        if (isSelectionHandleShowing()) {
2173            mSelectionHandleController.setStartHandlePosition(
2174                    mStartHandlePoint.getXPix(), mStartHandlePoint.getYPix());
2175            mSelectionHandleController.setEndHandlePosition(
2176                    mEndHandlePoint.getXPix(), mEndHandlePoint.getYPix());
2177        }
2178
2179        if (isInsertionHandleShowing()) {
2180            mInsertionHandleController.setHandlePosition(
2181                    mInsertionHandlePoint.getXPix(), mInsertionHandlePoint.getYPix());
2182        }
2183    }
2184
2185    private void hideHandles() {
2186        if (mSelectionHandleController != null) {
2187            mSelectionHandleController.hideAndDisallowAutomaticShowing();
2188        }
2189        if (mInsertionHandleController != null) {
2190            mInsertionHandleController.hideAndDisallowAutomaticShowing();
2191        }
2192        mPositionObserver.removeListener(mPositionListener);
2193    }
2194
2195    private void showSelectActionBar() {
2196        if (mActionMode != null) {
2197            mActionMode.invalidate();
2198            return;
2199        }
2200
2201        // Start a new action mode with a SelectActionModeCallback.
2202        SelectActionModeCallback.ActionHandler actionHandler =
2203                new SelectActionModeCallback.ActionHandler() {
2204            @Override
2205            public void selectAll() {
2206                mImeAdapter.selectAll();
2207            }
2208
2209            @Override
2210            public void cut() {
2211                mImeAdapter.cut();
2212            }
2213
2214            @Override
2215            public void copy() {
2216                mImeAdapter.copy();
2217            }
2218
2219            @Override
2220            public void paste() {
2221                mImeAdapter.paste();
2222            }
2223
2224            @Override
2225            public void share() {
2226                final String query = getSelectedText();
2227                if (TextUtils.isEmpty(query)) return;
2228
2229                Intent send = new Intent(Intent.ACTION_SEND);
2230                send.setType("text/plain");
2231                send.putExtra(Intent.EXTRA_TEXT, query);
2232                try {
2233                    Intent i = Intent.createChooser(send, getContext().getString(
2234                            R.string.actionbar_share));
2235                    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2236                    getContext().startActivity(i);
2237                } catch (android.content.ActivityNotFoundException ex) {
2238                    // If no app handles it, do nothing.
2239                }
2240            }
2241
2242            @Override
2243            public void search() {
2244                final String query = getSelectedText();
2245                if (TextUtils.isEmpty(query)) return;
2246
2247                // See if ContentViewClient wants to override
2248                if (getContentViewClient().doesPerformWebSearch()) {
2249                    getContentViewClient().performWebSearch(query);
2250                    return;
2251                }
2252
2253                Intent i = new Intent(Intent.ACTION_WEB_SEARCH);
2254                i.putExtra(SearchManager.EXTRA_NEW_SEARCH, true);
2255                i.putExtra(SearchManager.QUERY, query);
2256                i.putExtra(Browser.EXTRA_APPLICATION_ID, getContext().getPackageName());
2257                if (!(getContext() instanceof Activity)) {
2258                    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2259                }
2260                try {
2261                    getContext().startActivity(i);
2262                } catch (android.content.ActivityNotFoundException ex) {
2263                    // If no app handles it, do nothing.
2264                }
2265            }
2266
2267            @Override
2268            public boolean isSelectionEditable() {
2269                return mSelectionEditable;
2270            }
2271
2272            @Override
2273            public void onDestroyActionMode() {
2274                mActionMode = null;
2275                if (mUnselectAllOnActionModeDismiss) mImeAdapter.unselect();
2276                getContentViewClient().onContextualActionBarHidden();
2277            }
2278
2279            @Override
2280            public boolean isShareAvailable() {
2281                Intent intent = new Intent(Intent.ACTION_SEND);
2282                intent.setType("text/plain");
2283                return getContext().getPackageManager().queryIntentActivities(intent,
2284                        PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
2285            }
2286
2287            @Override
2288            public boolean isWebSearchAvailable() {
2289                if (getContentViewClient().doesPerformWebSearch()) return true;
2290                Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
2291                intent.putExtra(SearchManager.EXTRA_NEW_SEARCH, true);
2292                return getContext().getPackageManager().queryIntentActivities(intent,
2293                        PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
2294            }
2295        };
2296        mActionMode = null;
2297        // On ICS, startActionMode throws an NPE when getParent() is null.
2298        if (mContainerView.getParent() != null) {
2299            mActionMode = mContainerView.startActionMode(
2300                    getContentViewClient().getSelectActionModeCallback(getContext(), actionHandler,
2301                            nativeIsIncognito(mNativeContentViewCore)));
2302        }
2303        mUnselectAllOnActionModeDismiss = true;
2304        if (mActionMode == null) {
2305            // There is no ActionMode, so remove the selection.
2306            mImeAdapter.unselect();
2307        } else {
2308            getContentViewClient().onContextualActionBarShown();
2309        }
2310    }
2311
2312    public boolean getUseDesktopUserAgent() {
2313        if (mNativeContentViewCore != 0) {
2314            return nativeGetUseDesktopUserAgent(mNativeContentViewCore);
2315        }
2316        return false;
2317    }
2318
2319    /**
2320     * Set whether or not we're using a desktop user agent for the currently loaded page.
2321     * @param override If true, use a desktop user agent.  Use a mobile one otherwise.
2322     * @param reloadOnChange Reload the page if the UA has changed.
2323     */
2324    public void setUseDesktopUserAgent(boolean override, boolean reloadOnChange) {
2325        if (mNativeContentViewCore != 0) {
2326            nativeSetUseDesktopUserAgent(mNativeContentViewCore, override, reloadOnChange);
2327        }
2328    }
2329
2330    public void clearSslPreferences() {
2331        nativeClearSslPreferences(mNativeContentViewCore);
2332    }
2333
2334    private boolean isSelectionHandleShowing() {
2335        return mSelectionHandleController != null && mSelectionHandleController.isShowing();
2336    }
2337
2338    private boolean isInsertionHandleShowing() {
2339        return mInsertionHandleController != null && mInsertionHandleController.isShowing();
2340    }
2341
2342    private void updateTextHandlesForGesture(int type) {
2343        switch(type) {
2344            case ContentViewGestureHandler.GESTURE_DOUBLE_TAP:
2345            case ContentViewGestureHandler.GESTURE_SCROLL_START:
2346            case ContentViewGestureHandler.GESTURE_FLING_START:
2347            case ContentViewGestureHandler.GESTURE_PINCH_BEGIN:
2348                temporarilyHideTextHandles();
2349                break;
2350
2351            default:
2352                break;
2353        }
2354    }
2355
2356    // Makes the insertion/selection handles invisible. They will fade back in shortly after the
2357    // last call to scheduleTextHandleFadeIn (or temporarilyHideTextHandles).
2358    private void temporarilyHideTextHandles() {
2359        if (isSelectionHandleShowing() && !mSelectionHandleController.isDragging()) {
2360            mSelectionHandleController.setHandleVisibility(HandleView.INVISIBLE);
2361        }
2362        if (isInsertionHandleShowing() && !mInsertionHandleController.isDragging()) {
2363            mInsertionHandleController.setHandleVisibility(HandleView.INVISIBLE);
2364        }
2365        scheduleTextHandleFadeIn();
2366    }
2367
2368    private boolean allowTextHandleFadeIn() {
2369        if (mContentViewGestureHandler.isNativeScrolling() ||
2370                mContentViewGestureHandler.isNativePinching()) {
2371            return false;
2372        }
2373
2374        if (mPopupZoomer.isShowing()) return false;
2375
2376        return true;
2377    }
2378
2379    // Cancels any pending fade in and schedules a new one.
2380    private void scheduleTextHandleFadeIn() {
2381        if (!isInsertionHandleShowing() && !isSelectionHandleShowing()) return;
2382
2383        if (mDeferredHandleFadeInRunnable == null) {
2384            mDeferredHandleFadeInRunnable = new Runnable() {
2385                @Override
2386                public void run() {
2387                    if (!allowTextHandleFadeIn()) {
2388                        // Delay fade in until it is allowed.
2389                        scheduleTextHandleFadeIn();
2390                    } else {
2391                        if (isSelectionHandleShowing()) {
2392                            mSelectionHandleController.beginHandleFadeIn();
2393                        }
2394                        if (isInsertionHandleShowing()) {
2395                            mInsertionHandleController.beginHandleFadeIn();
2396                        }
2397                    }
2398                }
2399            };
2400        }
2401
2402        mContainerView.removeCallbacks(mDeferredHandleFadeInRunnable);
2403        mContainerView.postDelayed(mDeferredHandleFadeInRunnable, TEXT_HANDLE_FADE_IN_DELAY);
2404    }
2405
2406    /**
2407     * Shows the IME if the focused widget could accept text input.
2408     */
2409    public void showImeIfNeeded() {
2410        if (mNativeContentViewCore != 0) nativeShowImeIfNeeded(mNativeContentViewCore);
2411    }
2412
2413    @SuppressWarnings("unused")
2414    @CalledByNative
2415    private void updateFrameInfo(
2416            float scrollOffsetX, float scrollOffsetY,
2417            float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor,
2418            float contentWidth, float contentHeight,
2419            float viewportWidth, float viewportHeight,
2420            float controlsOffsetYCss, float contentOffsetYCss,
2421            float overdrawBottomHeightCss) {
2422        TraceEvent.instant("ContentViewCore:updateFrameInfo");
2423        // Adjust contentWidth/Height to be always at least as big as
2424        // the actual viewport (as set by onSizeChanged).
2425        contentWidth = Math.max(contentWidth,
2426                mRenderCoordinates.fromPixToLocalCss(mViewportWidthPix));
2427        contentHeight = Math.max(contentHeight,
2428                mRenderCoordinates.fromPixToLocalCss(mViewportHeightPix));
2429
2430        final float contentOffsetYPix = mRenderCoordinates.fromDipToPix(contentOffsetYCss);
2431
2432        final boolean contentSizeChanged =
2433                contentWidth != mRenderCoordinates.getContentWidthCss()
2434                || contentHeight != mRenderCoordinates.getContentHeightCss();
2435        final boolean scaleLimitsChanged =
2436                minPageScaleFactor != mRenderCoordinates.getMinPageScaleFactor()
2437                || maxPageScaleFactor != mRenderCoordinates.getMaxPageScaleFactor();
2438        final boolean pageScaleChanged =
2439                pageScaleFactor != mRenderCoordinates.getPageScaleFactor();
2440        final boolean scrollChanged =
2441                pageScaleChanged
2442                || scrollOffsetX != mRenderCoordinates.getScrollX()
2443                || scrollOffsetY != mRenderCoordinates.getScrollY();
2444        final boolean contentOffsetChanged =
2445                contentOffsetYPix != mRenderCoordinates.getContentOffsetYPix();
2446
2447        final boolean needHidePopupZoomer = contentSizeChanged || scrollChanged;
2448        final boolean needUpdateZoomControls = scaleLimitsChanged || scrollChanged;
2449        final boolean needTemporarilyHideHandles = scrollChanged;
2450
2451        if (needHidePopupZoomer) mPopupZoomer.hide(true);
2452
2453        if (scrollChanged) {
2454            mContainerViewInternals.onScrollChanged(
2455                    (int) mRenderCoordinates.fromLocalCssToPix(scrollOffsetX),
2456                    (int) mRenderCoordinates.fromLocalCssToPix(scrollOffsetY),
2457                    (int) mRenderCoordinates.getScrollXPix(),
2458                    (int) mRenderCoordinates.getScrollYPix());
2459        }
2460
2461        mRenderCoordinates.updateFrameInfo(
2462                scrollOffsetX, scrollOffsetY,
2463                contentWidth, contentHeight,
2464                viewportWidth, viewportHeight,
2465                pageScaleFactor, minPageScaleFactor, maxPageScaleFactor,
2466                contentOffsetYPix);
2467        onRenderCoordinatesUpdated();
2468
2469        if (needTemporarilyHideHandles) temporarilyHideTextHandles();
2470        if (needUpdateZoomControls) mZoomControlsDelegate.updateZoomControls();
2471        if (contentOffsetChanged) updateHandleScreenPositions();
2472
2473        // Update offsets for fullscreen.
2474        final float deviceScale = mRenderCoordinates.getDeviceScaleFactor();
2475        final float controlsOffsetPix = controlsOffsetYCss * deviceScale;
2476        final float overdrawBottomHeightPix = overdrawBottomHeightCss * deviceScale;
2477        getContentViewClient().onOffsetsForFullscreenChanged(
2478                controlsOffsetPix, contentOffsetYPix, overdrawBottomHeightPix);
2479
2480        mPendingRendererFrame = true;
2481        if (mBrowserAccessibilityManager != null) {
2482            mBrowserAccessibilityManager.notifyFrameInfoInitialized();
2483        }
2484
2485        // Update geometry for external video surface.
2486        getContentViewClient().onGeometryChanged(-1, null);
2487    }
2488
2489    @CalledByNative
2490    private void updateImeAdapter(int nativeImeAdapterAndroid, int textInputType,
2491            String text, int selectionStart, int selectionEnd,
2492            int compositionStart, int compositionEnd, boolean showImeIfNeeded, boolean requireAck) {
2493        TraceEvent.begin();
2494        mSelectionEditable = (textInputType != ImeAdapter.getTextInputTypeNone());
2495
2496        if (mActionMode != null) mActionMode.invalidate();
2497
2498        mImeAdapter.attachAndShowIfNeeded(nativeImeAdapterAndroid, textInputType,
2499                selectionStart, selectionEnd, showImeIfNeeded);
2500
2501        if (mInputConnection != null) {
2502            mInputConnection.updateState(text, selectionStart, selectionEnd, compositionStart,
2503                    compositionEnd, requireAck);
2504        }
2505        TraceEvent.end();
2506    }
2507
2508    @SuppressWarnings("unused")
2509    @CalledByNative
2510    private void setTitle(String title) {
2511        getContentViewClient().onUpdateTitle(title);
2512    }
2513
2514    /**
2515     * Called (from native) when the <select> popup needs to be shown.
2516     * @param items           Items to show.
2517     * @param enabled         POPUP_ITEM_TYPEs for items.
2518     * @param multiple        Whether the popup menu should support multi-select.
2519     * @param selectedIndices Indices of selected items.
2520     */
2521    @SuppressWarnings("unused")
2522    @CalledByNative
2523    private void showSelectPopup(String[] items, int[] enabled, boolean multiple,
2524            int[] selectedIndices) {
2525        SelectPopupDialog.show(this, items, enabled, multiple, selectedIndices);
2526    }
2527
2528    @SuppressWarnings("unused")
2529    @CalledByNative
2530    private void showDisambiguationPopup(Rect targetRect, Bitmap zoomedBitmap) {
2531        mPopupZoomer.setBitmap(zoomedBitmap);
2532        mPopupZoomer.show(targetRect);
2533        temporarilyHideTextHandles();
2534    }
2535
2536    @SuppressWarnings("unused")
2537    @CalledByNative
2538    private TouchEventSynthesizer createTouchEventSynthesizer() {
2539        return new TouchEventSynthesizer(this);
2540    }
2541
2542    @SuppressWarnings("unused")
2543    @CalledByNative
2544    private void onSelectionChanged(String text) {
2545        mLastSelectedText = text;
2546    }
2547
2548    @SuppressWarnings("unused")
2549    @CalledByNative
2550    private void onSelectionBoundsChanged(Rect anchorRectDip, int anchorDir, Rect focusRectDip,
2551            int focusDir, boolean isAnchorFirst) {
2552        // All coordinates are in DIP.
2553        int x1 = anchorRectDip.left;
2554        int y1 = anchorRectDip.bottom;
2555        int x2 = focusRectDip.left;
2556        int y2 = focusRectDip.bottom;
2557
2558        if (x1 != x2 || y1 != y2 ||
2559                (mSelectionHandleController != null && mSelectionHandleController.isDragging())) {
2560            if (mInsertionHandleController != null) {
2561                mInsertionHandleController.hide();
2562            }
2563            if (isAnchorFirst) {
2564                mStartHandlePoint.setLocalDip(x1, y1);
2565                mEndHandlePoint.setLocalDip(x2, y2);
2566            } else {
2567                mStartHandlePoint.setLocalDip(x2, y2);
2568                mEndHandlePoint.setLocalDip(x1, y1);
2569            }
2570
2571            boolean wereSelectionHandlesShowing = getSelectionHandleController().isShowing();
2572
2573            getSelectionHandleController().onSelectionChanged(anchorDir, focusDir);
2574            updateHandleScreenPositions();
2575            mHasSelection = true;
2576
2577            if (!wereSelectionHandlesShowing && getSelectionHandleController().isShowing()) {
2578                // TODO(cjhopman): Remove this when there is a better signal that long press caused
2579                // a selection. See http://crbug.com/150151.
2580                mContainerView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
2581            }
2582
2583        } else {
2584            mUnselectAllOnActionModeDismiss = false;
2585            hideSelectActionBar();
2586            if (x1 != 0 && y1 != 0 && mSelectionEditable) {
2587                // Selection is a caret, and a text field is focused.
2588                if (mSelectionHandleController != null) {
2589                    mSelectionHandleController.hide();
2590                }
2591                mInsertionHandlePoint.setLocalDip(x1, y1);
2592
2593                getInsertionHandleController().onCursorPositionChanged();
2594                updateHandleScreenPositions();
2595                InputMethodManager manager = (InputMethodManager)
2596                        getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
2597                if (manager.isWatchingCursor(mContainerView)) {
2598                    final int xPix = (int) mInsertionHandlePoint.getXPix();
2599                    final int yPix = (int) mInsertionHandlePoint.getYPix();
2600                    manager.updateCursor(mContainerView, xPix, yPix, xPix, yPix);
2601                }
2602            } else {
2603                // Deselection
2604                if (mSelectionHandleController != null) {
2605                    mSelectionHandleController.hideAndDisallowAutomaticShowing();
2606                }
2607                if (mInsertionHandleController != null) {
2608                    mInsertionHandleController.hideAndDisallowAutomaticShowing();
2609                }
2610            }
2611            mHasSelection = false;
2612        }
2613        if (isSelectionHandleShowing() || isInsertionHandleShowing()) {
2614            mPositionObserver.addListener(mPositionListener);
2615        }
2616    }
2617
2618    @SuppressWarnings("unused")
2619    @CalledByNative
2620    private static void onEvaluateJavaScriptResult(
2621            String jsonResult, JavaScriptCallback callback) {
2622        callback.handleJavaScriptResult(jsonResult);
2623    }
2624
2625    @SuppressWarnings("unused")
2626    @CalledByNative
2627    private void showPastePopup(int xDip, int yDip) {
2628        mInsertionHandlePoint.setLocalDip(xDip, yDip);
2629        getInsertionHandleController().showHandle();
2630        updateHandleScreenPositions();
2631        getInsertionHandleController().showHandleWithPastePopup();
2632    }
2633
2634    @SuppressWarnings("unused")
2635    @CalledByNative
2636    private void onRenderProcessSwap(int oldPid, int newPid) {
2637        if (mInForeground && oldPid != newPid) {
2638            ChildProcessLauncher.getBindingManager().unbindAsHighPriority(oldPid);
2639            ChildProcessLauncher.getBindingManager().bindAsHighPriority(newPid);
2640        }
2641
2642        // We want to remove the initial binding even if the ContentView is not attached, so that
2643        // renderers for ContentViews loading in background do not retain the high priority.
2644        ChildProcessLauncher.getBindingManager().removeInitialBinding(newPid);
2645
2646        attachImeAdapter();
2647    }
2648
2649    @SuppressWarnings("unused")
2650    @CalledByNative
2651    private void onWebContentsConnected() {
2652        attachImeAdapter();
2653    }
2654
2655    /**
2656     * Attaches the native ImeAdapter object to the java ImeAdapter to allow communication via JNI.
2657     */
2658    public void attachImeAdapter() {
2659        if (mImeAdapter != null && mNativeContentViewCore != 0) {
2660            mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore));
2661        }
2662    }
2663
2664    /**
2665     * @see View#hasFocus()
2666     */
2667    @CalledByNative
2668    public boolean hasFocus() {
2669        return mContainerView.hasFocus();
2670    }
2671
2672    /**
2673     * Checks whether the ContentViewCore can be zoomed in.
2674     *
2675     * @return True if the ContentViewCore can be zoomed in.
2676     */
2677    // This method uses the term 'zoom' for legacy reasons, but relates
2678    // to what chrome calls the 'page scale factor'.
2679    public boolean canZoomIn() {
2680        final float zoomInExtent = mRenderCoordinates.getMaxPageScaleFactor()
2681                - mRenderCoordinates.getPageScaleFactor();
2682        return zoomInExtent > ZOOM_CONTROLS_EPSILON;
2683    }
2684
2685    /**
2686     * Checks whether the ContentViewCore can be zoomed out.
2687     *
2688     * @return True if the ContentViewCore can be zoomed out.
2689     */
2690    // This method uses the term 'zoom' for legacy reasons, but relates
2691    // to what chrome calls the 'page scale factor'.
2692    public boolean canZoomOut() {
2693        final float zoomOutExtent = mRenderCoordinates.getPageScaleFactor()
2694                - mRenderCoordinates.getMinPageScaleFactor();
2695        return zoomOutExtent > ZOOM_CONTROLS_EPSILON;
2696    }
2697
2698    /**
2699     * Zooms in the ContentViewCore by 25% (or less if that would result in
2700     * zooming in more than possible).
2701     *
2702     * @return True if there was a zoom change, false otherwise.
2703     */
2704    // This method uses the term 'zoom' for legacy reasons, but relates
2705    // to what chrome calls the 'page scale factor'.
2706    public boolean zoomIn() {
2707        if (!canZoomIn()) {
2708            return false;
2709        }
2710        return pinchByDelta(1.25f);
2711    }
2712
2713    /**
2714     * Zooms out the ContentViewCore by 20% (or less if that would result in
2715     * zooming out more than possible).
2716     *
2717     * @return True if there was a zoom change, false otherwise.
2718     */
2719    // This method uses the term 'zoom' for legacy reasons, but relates
2720    // to what chrome calls the 'page scale factor'.
2721    public boolean zoomOut() {
2722        if (!canZoomOut()) {
2723            return false;
2724        }
2725        return pinchByDelta(0.8f);
2726    }
2727
2728    /**
2729     * Resets the zoom factor of the ContentViewCore.
2730     *
2731     * @return True if there was a zoom change, false otherwise.
2732     */
2733    // This method uses the term 'zoom' for legacy reasons, but relates
2734    // to what chrome calls the 'page scale factor'.
2735    public boolean zoomReset() {
2736        // The page scale factor is initialized to mNativeMinimumScale when
2737        // the page finishes loading. Thus sets it back to mNativeMinimumScale.
2738        if (!canZoomOut()) return false;
2739        return pinchByDelta(
2740                mRenderCoordinates.getMinPageScaleFactor()
2741                        / mRenderCoordinates.getPageScaleFactor());
2742    }
2743
2744    /**
2745     * Simulate a pinch zoom gesture.
2746     *
2747     * @param delta the factor by which the current page scale should be multiplied by.
2748     * @return whether the gesture was sent.
2749     */
2750    public boolean pinchByDelta(float delta) {
2751        if (mNativeContentViewCore == 0) {
2752            return false;
2753        }
2754
2755        long timeMs = System.currentTimeMillis();
2756        int xPix = getViewportWidthPix() / 2;
2757        int yPix = getViewportHeightPix() / 2;
2758
2759        getContentViewGestureHandler().pinchBegin(timeMs, xPix, yPix);
2760        getContentViewGestureHandler().pinchBy(timeMs, xPix, yPix, delta);
2761        getContentViewGestureHandler().pinchEnd(timeMs);
2762
2763        return true;
2764    }
2765
2766    /**
2767     * Invokes the graphical zoom picker widget for this ContentView.
2768     */
2769    @Override
2770    public void invokeZoomPicker() {
2771        mZoomControlsDelegate.invokeZoomPicker();
2772    }
2773
2774    /**
2775     * This will mimic {@link #addPossiblyUnsafeJavascriptInterface(Object, String, Class)}
2776     * and automatically pass in {@link JavascriptInterface} as the required annotation.
2777     *
2778     * @param object The Java object to inject into the ContentViewCore's JavaScript context.  Null
2779     *               values are ignored.
2780     * @param name   The name used to expose the instance in JavaScript.
2781     */
2782    public void addJavascriptInterface(Object object, String name) {
2783        addPossiblyUnsafeJavascriptInterface(object, name, JavascriptInterface.class);
2784    }
2785
2786    /**
2787     * This method injects the supplied Java object into the ContentViewCore.
2788     * The object is injected into the JavaScript context of the main frame,
2789     * using the supplied name. This allows the Java object to be accessed from
2790     * JavaScript. Note that that injected objects will not appear in
2791     * JavaScript until the page is next (re)loaded. For example:
2792     * <pre> view.addJavascriptInterface(new Object(), "injectedObject");
2793     * view.loadData("<!DOCTYPE html><title></title>", "text/html", null);
2794     * view.loadUrl("javascript:alert(injectedObject.toString())");</pre>
2795     * <p><strong>IMPORTANT:</strong>
2796     * <ul>
2797     * <li> addJavascriptInterface() can be used to allow JavaScript to control
2798     * the host application. This is a powerful feature, but also presents a
2799     * security risk. Use of this method in a ContentViewCore containing
2800     * untrusted content could allow an attacker to manipulate the host
2801     * application in unintended ways, executing Java code with the permissions
2802     * of the host application. Use extreme care when using this method in a
2803     * ContentViewCore which could contain untrusted content. Particular care
2804     * should be taken to avoid unintentional access to inherited methods, such
2805     * as {@link Object#getClass()}. To prevent access to inherited methods,
2806     * pass an annotation for {@code requiredAnnotation}.  This will ensure
2807     * that only methods with {@code requiredAnnotation} are exposed to the
2808     * Javascript layer.  {@code requiredAnnotation} will be passed to all
2809     * subsequently injected Java objects if any methods return an object.  This
2810     * means the same restrictions (or lack thereof) will apply.  Alternatively,
2811     * {@link #addJavascriptInterface(Object, String)} can be called, which
2812     * automatically uses the {@link JavascriptInterface} annotation.
2813     * <li> JavaScript interacts with Java objects on a private, background
2814     * thread of the ContentViewCore. Care is therefore required to maintain
2815     * thread safety.</li>
2816     * </ul></p>
2817     *
2818     * @param object             The Java object to inject into the
2819     *                           ContentViewCore's JavaScript context. Null
2820     *                           values are ignored.
2821     * @param name               The name used to expose the instance in
2822     *                           JavaScript.
2823     * @param requiredAnnotation Restrict exposed methods to ones with this
2824     *                           annotation.  If {@code null} all methods are
2825     *                           exposed.
2826     *
2827     */
2828    public void addPossiblyUnsafeJavascriptInterface(Object object, String name,
2829            Class<? extends Annotation> requiredAnnotation) {
2830        if (mNativeContentViewCore != 0 && object != null) {
2831            mJavaScriptInterfaces.put(name, object);
2832            nativeAddJavascriptInterface(mNativeContentViewCore, object, name, requiredAnnotation,
2833                    mRetainedJavaScriptObjects);
2834        }
2835    }
2836
2837    /**
2838     * Removes a previously added JavaScript interface with the given name.
2839     *
2840     * @param name The name of the interface to remove.
2841     */
2842    public void removeJavascriptInterface(String name) {
2843        mJavaScriptInterfaces.remove(name);
2844        if (mNativeContentViewCore != 0) {
2845            nativeRemoveJavascriptInterface(mNativeContentViewCore, name);
2846        }
2847    }
2848
2849    /**
2850     * Return the current scale of the ContentView.
2851     * @return The current page scale factor.
2852     */
2853    public float getScale() {
2854        return mRenderCoordinates.getPageScaleFactor();
2855    }
2856
2857    /**
2858     * If the view is ready to draw contents to the screen. In hardware mode,
2859     * the initialization of the surface texture may not occur until after the
2860     * view has been added to the layout. This method will return {@code true}
2861     * once the texture is actually ready.
2862     */
2863    public boolean isReady() {
2864        return nativeIsRenderWidgetHostViewReady(mNativeContentViewCore);
2865    }
2866
2867    @CalledByNative
2868    private void startContentIntent(String contentUrl) {
2869        getContentViewClient().onStartContentIntent(getContext(), contentUrl);
2870    }
2871
2872    @Override
2873    public void onAccessibilityStateChanged(boolean enabled) {
2874        setAccessibilityState(enabled);
2875    }
2876
2877    /**
2878     * Determines whether or not this ContentViewCore can handle this accessibility action.
2879     * @param action The action to perform.
2880     * @return Whether or not this action is supported.
2881     */
2882    public boolean supportsAccessibilityAction(int action) {
2883        return mAccessibilityInjector.supportsAccessibilityAction(action);
2884    }
2885
2886    /**
2887     * Attempts to perform an accessibility action on the web content.  If the accessibility action
2888     * cannot be processed, it returns {@code null}, allowing the caller to know to call the
2889     * super {@link View#performAccessibilityAction(int, Bundle)} method and use that return value.
2890     * Otherwise the return value from this method should be used.
2891     * @param action The action to perform.
2892     * @param arguments Optional action arguments.
2893     * @return Whether the action was performed or {@code null} if the call should be delegated to
2894     *         the super {@link View} class.
2895     */
2896    public boolean performAccessibilityAction(int action, Bundle arguments) {
2897        if (mAccessibilityInjector.supportsAccessibilityAction(action)) {
2898            return mAccessibilityInjector.performAccessibilityAction(action, arguments);
2899        }
2900
2901        return false;
2902    }
2903
2904    /**
2905     * Set the BrowserAccessibilityManager, used for native accessibility
2906     * (not script injection). This is only set when system accessibility
2907     * has been enabled.
2908     * @param manager The new BrowserAccessibilityManager.
2909     */
2910    public void setBrowserAccessibilityManager(BrowserAccessibilityManager manager) {
2911        mBrowserAccessibilityManager = manager;
2912    }
2913
2914    /**
2915     * Get the BrowserAccessibilityManager, used for native accessibility
2916     * (not script injection). This will return null when system accessibility
2917     * is not enabled.
2918     * @return This view's BrowserAccessibilityManager.
2919     */
2920    public BrowserAccessibilityManager getBrowserAccessibilityManager() {
2921        return mBrowserAccessibilityManager;
2922    }
2923
2924    /**
2925     * If native accessibility (not script injection) is enabled, and if this is
2926     * running on JellyBean or later, returns an AccessibilityNodeProvider that
2927     * implements native accessibility for this view. Returns null otherwise.
2928     * Lazily initializes native accessibility here if it's allowed.
2929     * @return The AccessibilityNodeProvider, if available, or null otherwise.
2930     */
2931    public AccessibilityNodeProvider getAccessibilityNodeProvider() {
2932        if (mBrowserAccessibilityManager != null) {
2933            return mBrowserAccessibilityManager.getAccessibilityNodeProvider();
2934        }
2935
2936        if (mNativeAccessibilityAllowed &&
2937                !mNativeAccessibilityEnabled &&
2938                mNativeContentViewCore != 0 &&
2939                Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
2940            mNativeAccessibilityEnabled = true;
2941            nativeSetAccessibilityEnabled(mNativeContentViewCore, true);
2942        }
2943
2944        return null;
2945    }
2946
2947    /**
2948     * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)
2949     */
2950    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
2951        // Note: this is only used by the script-injecting accessibility code.
2952        mAccessibilityInjector.onInitializeAccessibilityNodeInfo(info);
2953    }
2954
2955    /**
2956     * @see View#onInitializeAccessibilityEvent(AccessibilityEvent)
2957     */
2958    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
2959        // Note: this is only used by the script-injecting accessibility code.
2960        event.setClassName(this.getClass().getName());
2961
2962        // Identify where the top-left of the screen currently points to.
2963        event.setScrollX(mRenderCoordinates.getScrollXPixInt());
2964        event.setScrollY(mRenderCoordinates.getScrollYPixInt());
2965
2966        // The maximum scroll values are determined by taking the content dimensions and
2967        // subtracting off the actual dimensions of the ChromeView.
2968        int maxScrollXPix = Math.max(0, mRenderCoordinates.getMaxHorizontalScrollPixInt());
2969        int maxScrollYPix = Math.max(0, mRenderCoordinates.getMaxVerticalScrollPixInt());
2970        event.setScrollable(maxScrollXPix > 0 || maxScrollYPix > 0);
2971
2972        // Setting the maximum scroll values requires API level 15 or higher.
2973        final int SDK_VERSION_REQUIRED_TO_SET_SCROLL = 15;
2974        if (Build.VERSION.SDK_INT >= SDK_VERSION_REQUIRED_TO_SET_SCROLL) {
2975            event.setMaxScrollX(maxScrollXPix);
2976            event.setMaxScrollY(maxScrollYPix);
2977        }
2978    }
2979
2980    /**
2981     * Returns whether accessibility script injection is enabled on the device
2982     */
2983    public boolean isDeviceAccessibilityScriptInjectionEnabled() {
2984        try {
2985            if (!mContentSettings.getJavaScriptEnabled()) {
2986                return false;
2987            }
2988
2989            int result = getContext().checkCallingOrSelfPermission(
2990                    android.Manifest.permission.INTERNET);
2991            if (result != PackageManager.PERMISSION_GRANTED) {
2992                return false;
2993            }
2994
2995            Field field = Settings.Secure.class.getField("ACCESSIBILITY_SCRIPT_INJECTION");
2996            field.setAccessible(true);
2997            String accessibilityScriptInjection = (String) field.get(null);
2998            ContentResolver contentResolver = getContext().getContentResolver();
2999
3000            if (mAccessibilityScriptInjectionObserver == null) {
3001                ContentObserver contentObserver = new ContentObserver(new Handler()) {
3002                    @Override
3003                    public void onChange(boolean selfChange, Uri uri) {
3004                        setAccessibilityState(mAccessibilityManager.isEnabled());
3005                    }
3006                };
3007                contentResolver.registerContentObserver(
3008                    Settings.Secure.getUriFor(accessibilityScriptInjection),
3009                    false,
3010                    contentObserver);
3011                mAccessibilityScriptInjectionObserver = contentObserver;
3012            }
3013
3014            return Settings.Secure.getInt(contentResolver, accessibilityScriptInjection, 0) == 1;
3015        } catch (NoSuchFieldException e) {
3016        } catch (IllegalAccessException e) {
3017        }
3018        return false;
3019    }
3020
3021    /**
3022     * Returns whether or not accessibility injection is being used.
3023     */
3024    public boolean isInjectingAccessibilityScript() {
3025        return mAccessibilityInjector.accessibilityIsAvailable();
3026    }
3027
3028    /**
3029     * Turns browser accessibility on or off.
3030     * If |state| is |false|, this turns off both native and injected accessibility.
3031     * Otherwise, if accessibility script injection is enabled, this will enable the injected
3032     * accessibility scripts. Native accessibility is enabled on demand.
3033     */
3034    public void setAccessibilityState(boolean state) {
3035        if (!state) {
3036            setInjectedAccessibility(false);
3037            mNativeAccessibilityAllowed = false;
3038        } else {
3039            boolean useScriptInjection = isDeviceAccessibilityScriptInjectionEnabled();
3040            setInjectedAccessibility(useScriptInjection);
3041            mNativeAccessibilityAllowed = !useScriptInjection;
3042        }
3043    }
3044
3045    /**
3046     * Enable or disable injected accessibility features
3047     */
3048    public void setInjectedAccessibility(boolean enabled) {
3049        mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary();
3050        mAccessibilityInjector.setScriptEnabled(enabled);
3051    }
3052
3053    /**
3054     * Stop any TTS notifications that are currently going on.
3055     */
3056    public void stopCurrentAccessibilityNotifications() {
3057        mAccessibilityInjector.onPageLostFocus();
3058    }
3059
3060    /**
3061     * Inform WebKit that Fullscreen mode has been exited by the user.
3062     */
3063    public void exitFullscreen() {
3064        if (mNativeContentViewCore != 0) nativeExitFullscreen(mNativeContentViewCore);
3065    }
3066
3067    /**
3068     * Changes whether hiding the top controls is enabled.
3069     *
3070     * @param enableHiding Whether hiding the top controls should be enabled or not.
3071     * @param enableShowing Whether showing the top controls should be enabled or not.
3072     * @param animate Whether the transition should be animated or not.
3073     */
3074    public void updateTopControlsState(boolean enableHiding, boolean enableShowing,
3075            boolean animate) {
3076        if (mNativeContentViewCore != 0) {
3077            nativeUpdateTopControlsState(
3078                    mNativeContentViewCore, enableHiding, enableShowing, animate);
3079        }
3080    }
3081
3082    /**
3083     * Callback factory method for nativeGetNavigationHistory().
3084     */
3085    @CalledByNative
3086    private void addToNavigationHistory(Object history, int index, String url, String virtualUrl,
3087            String originalUrl, String title, Bitmap favicon) {
3088        NavigationEntry entry = new NavigationEntry(
3089                index, url, virtualUrl, originalUrl, title, favicon);
3090        ((NavigationHistory) history).addEntry(entry);
3091    }
3092
3093    /**
3094     * Get a copy of the navigation history of the view.
3095     */
3096    public NavigationHistory getNavigationHistory() {
3097        NavigationHistory history = new NavigationHistory();
3098        if (mNativeContentViewCore != 0) {
3099            int currentIndex = nativeGetNavigationHistory(mNativeContentViewCore, history);
3100            history.setCurrentEntryIndex(currentIndex);
3101        }
3102        return history;
3103    }
3104
3105    @Override
3106    public NavigationHistory getDirectedNavigationHistory(boolean isForward, int itemLimit) {
3107        NavigationHistory history = new NavigationHistory();
3108        if (mNativeContentViewCore != 0) {
3109            nativeGetDirectedNavigationHistory(
3110                mNativeContentViewCore, history, isForward, itemLimit);
3111        }
3112        return history;
3113    }
3114
3115    /**
3116     * @return The original request URL for the current navigation entry, or null if there is no
3117     *         current entry.
3118     */
3119    public String getOriginalUrlForActiveNavigationEntry() {
3120        if (mNativeContentViewCore != 0) {
3121            return nativeGetOriginalUrlForActiveNavigationEntry(mNativeContentViewCore);
3122        }
3123        return "";
3124    }
3125
3126    /**
3127     * @return The cached copy of render positions and scales.
3128     */
3129    public RenderCoordinates getRenderCoordinates() {
3130        return mRenderCoordinates;
3131    }
3132
3133    @CalledByNative
3134    private int getLocationInWindowX() {
3135        return mLocationInWindowX;
3136    }
3137
3138    @CalledByNative
3139    private int getLocationInWindowY() {
3140        return mLocationInWindowY;
3141    }
3142
3143    @CalledByNative
3144    private static Rect createRect(int x, int y, int right, int bottom) {
3145        return new Rect(x, y, right, bottom);
3146    }
3147
3148    public void attachExternalVideoSurface(int playerId, Surface surface) {
3149        if (mNativeContentViewCore != 0) {
3150            nativeAttachExternalVideoSurface(mNativeContentViewCore, playerId, surface);
3151        }
3152    }
3153
3154    public void detachExternalVideoSurface(int playerId) {
3155        if (mNativeContentViewCore != 0) {
3156            nativeDetachExternalVideoSurface(mNativeContentViewCore, playerId);
3157        }
3158    }
3159
3160    private boolean onAnimate(long frameTimeMicros) {
3161        if (mNativeContentViewCore == 0) return false;
3162        return nativeOnAnimate(mNativeContentViewCore, frameTimeMicros);
3163    }
3164
3165    private void animateIfNecessary(long frameTimeMicros) {
3166        if (mNeedAnimate) {
3167            mNeedAnimate = onAnimate(frameTimeMicros);
3168            if (!mNeedAnimate) removeVSyncSubscriber();
3169        }
3170    }
3171
3172    @CalledByNative
3173    private void notifyExternalSurface(
3174            int playerId, boolean isRequest, float x, float y, float width, float height) {
3175        if (isRequest) getContentViewClient().onExternalVideoSurfaceRequested(playerId);
3176        getContentViewClient().onGeometryChanged(playerId, new RectF(x, y, x + width, y + height));
3177    }
3178
3179    /**
3180     * Offer a subset of gesture events to the embedding View,
3181     * primarily for WebView compatibility.
3182     *
3183     * @param type The type of the event.
3184     *
3185     * @return true if the embedder handled the event.
3186     */
3187    private boolean offerGestureToEmbedder(int type) {
3188        if (type == ContentViewGestureHandler.GESTURE_LONG_PRESS) {
3189            return mContainerView.performLongClick();
3190        }
3191        return false;
3192    }
3193
3194    private native long nativeInit(boolean hardwareAccelerated, long webContentsPtr,
3195            long viewAndroidPtr, long windowAndroidPtr);
3196
3197    @CalledByNative
3198    private ContentVideoViewClient getContentVideoViewClient() {
3199        return getContentViewClient().getContentVideoViewClient();
3200    }
3201
3202    @CalledByNative
3203    private boolean shouldBlockMediaRequest(String url) {
3204        return getContentViewClient().shouldBlockMediaRequest(url);
3205    }
3206
3207    private native void nativeOnJavaContentViewCoreDestroyed(long nativeContentViewCoreImpl);
3208
3209    private native void nativeLoadUrl(
3210            long nativeContentViewCoreImpl,
3211            String url,
3212            int loadUrlType,
3213            int transitionType,
3214            int uaOverrideOption,
3215            String extraHeaders,
3216            byte[] postData,
3217            String baseUrlForDataUrl,
3218            String virtualUrlForDataUrl,
3219            boolean canLoadLocalResources);
3220
3221    private native String nativeGetURL(long nativeContentViewCoreImpl);
3222
3223    private native String nativeGetTitle(long nativeContentViewCoreImpl);
3224
3225    private native void nativeShowInterstitialPage(
3226            long nativeContentViewCoreImpl, String url, long nativeInterstitialPageDelegateAndroid);
3227    private native boolean nativeIsShowingInterstitialPage(long nativeContentViewCoreImpl);
3228
3229    private native boolean nativeIsIncognito(long nativeContentViewCoreImpl);
3230
3231    private native void nativeSetFocus(long nativeContentViewCoreImpl, boolean focused);
3232
3233    private native void nativeSendOrientationChangeEvent(
3234            long nativeContentViewCoreImpl, int orientation);
3235
3236    // All touch events (including flings, scrolls etc) accept coordinates in physical pixels.
3237    private native boolean nativeSendTouchEvent(
3238            long nativeContentViewCoreImpl, long timeMs, int action, TouchPoint[] pts);
3239
3240    private native int nativeSendMouseMoveEvent(
3241            long nativeContentViewCoreImpl, long timeMs, float x, float y);
3242
3243    private native int nativeSendMouseWheelEvent(
3244            long nativeContentViewCoreImpl, long timeMs, float x, float y, float verticalAxis);
3245
3246    private native void nativeScrollBegin(
3247            long nativeContentViewCoreImpl, long timeMs, float x, float y);
3248
3249    private native void nativeScrollEnd(long nativeContentViewCoreImpl, long timeMs);
3250
3251    private native void nativeScrollBy(
3252            long nativeContentViewCoreImpl, long timeMs, float x, float y,
3253            float deltaX, float deltaY);
3254
3255    private native void nativeFlingStart(
3256            long nativeContentViewCoreImpl, long timeMs, float x, float y, float vx, float vy);
3257
3258    private native void nativeFlingCancel(long nativeContentViewCoreImpl, long timeMs);
3259
3260    private native void nativeSingleTap(
3261            long nativeContentViewCoreImpl, long timeMs, float x, float y, boolean linkPreviewTap);
3262
3263    private native void nativeSingleTapUnconfirmed(
3264            long nativeContentViewCoreImpl, long timeMs, float x, float y);
3265
3266    private native void nativeShowPressState(
3267            long nativeContentViewCoreImpl, long timeMs, float x, float y);
3268
3269    private native void nativeTapCancel(
3270            long nativeContentViewCoreImpl, long timeMs, float x, float y);
3271
3272    private native void nativeTapDown(
3273            long nativeContentViewCoreImpl, long timeMs, float x, float y);
3274
3275    private native void nativeDoubleTap(
3276            long nativeContentViewCoreImpl, long timeMs, float x, float y);
3277
3278    private native void nativeLongPress(
3279            long nativeContentViewCoreImpl, long timeMs, float x, float y, boolean linkPreviewTap);
3280
3281    private native void nativeLongTap(
3282            long nativeContentViewCoreImpl, long timeMs, float x, float y, boolean linkPreviewTap);
3283
3284    private native void nativePinchBegin(
3285            long nativeContentViewCoreImpl, long timeMs, float x, float y);
3286
3287    private native void nativePinchEnd(long nativeContentViewCoreImpl, long timeMs);
3288
3289    private native void nativePinchBy(long nativeContentViewCoreImpl, long timeMs,
3290            float anchorX, float anchorY, float deltaScale);
3291
3292    private native void nativeSelectBetweenCoordinates(
3293            long nativeContentViewCoreImpl, float x1, float y1, float x2, float y2);
3294
3295    private native void nativeMoveCaret(long nativeContentViewCoreImpl, float x, float y);
3296
3297    private native boolean nativeCanGoBack(long nativeContentViewCoreImpl);
3298    private native boolean nativeCanGoForward(long nativeContentViewCoreImpl);
3299    private native boolean nativeCanGoToOffset(long nativeContentViewCoreImpl, int offset);
3300    private native void nativeGoBack(long nativeContentViewCoreImpl);
3301    private native void nativeGoForward(long nativeContentViewCoreImpl);
3302    private native void nativeGoToOffset(long nativeContentViewCoreImpl, int offset);
3303    private native void nativeGoToNavigationIndex(long nativeContentViewCoreImpl, int index);
3304    private native void nativeLoadIfNecessary(long nativeContentViewCoreImpl);
3305    private native void nativeRequestRestoreLoad(long nativeContentViewCoreImpl);
3306
3307    private native void nativeStopLoading(long nativeContentViewCoreImpl);
3308
3309    private native void nativeReload(long nativeContentViewCoreImpl, boolean checkForRepost);
3310    private native void nativeReloadIgnoringCache(
3311            long nativeContentViewCoreImpl, boolean checkForRepost);
3312
3313    private native void nativeCancelPendingReload(long nativeContentViewCoreImpl);
3314
3315    private native void nativeContinuePendingReload(long nativeContentViewCoreImpl);
3316
3317    private native void nativeSelectPopupMenuItems(long nativeContentViewCoreImpl, int[] indices);
3318
3319    private native void nativeScrollFocusedEditableNodeIntoView(long nativeContentViewCoreImpl);
3320    private native void nativeUndoScrollFocusedEditableNodeIntoView(long nativeContentViewCoreImpl);
3321
3322    private native void nativeClearHistory(long nativeContentViewCoreImpl);
3323
3324    private native void nativeEvaluateJavaScript(long nativeContentViewCoreImpl,
3325            String script, JavaScriptCallback callback, boolean startRenderer);
3326
3327    private native int nativeGetNativeImeAdapter(long nativeContentViewCoreImpl);
3328
3329    private native int nativeGetCurrentRenderProcessId(long nativeContentViewCoreImpl);
3330
3331    private native int nativeGetBackgroundColor(long nativeContentViewCoreImpl);
3332
3333    private native void nativeOnShow(long nativeContentViewCoreImpl);
3334    private native void nativeOnHide(long nativeContentViewCoreImpl);
3335
3336    private native void nativeSetUseDesktopUserAgent(long nativeContentViewCoreImpl,
3337            boolean enabled, boolean reloadOnChange);
3338    private native boolean nativeGetUseDesktopUserAgent(long nativeContentViewCoreImpl);
3339
3340    private native void nativeClearSslPreferences(long nativeContentViewCoreImpl);
3341
3342    private native void nativeAddJavascriptInterface(long nativeContentViewCoreImpl, Object object,
3343            String name, Class requiredAnnotation, HashSet<Object> retainedObjectSet);
3344
3345    private native void nativeRemoveJavascriptInterface(long nativeContentViewCoreImpl,
3346            String name);
3347
3348    private native int nativeGetNavigationHistory(long nativeContentViewCoreImpl, Object context);
3349    private native void nativeGetDirectedNavigationHistory(long nativeContentViewCoreImpl,
3350            Object context, boolean isForward, int maxEntries);
3351    private native String nativeGetOriginalUrlForActiveNavigationEntry(
3352            long nativeContentViewCoreImpl);
3353
3354    private native void nativeUpdateVSyncParameters(long nativeContentViewCoreImpl,
3355            long timebaseMicros, long intervalMicros);
3356
3357    private native void nativeOnVSync(long nativeContentViewCoreImpl, long frameTimeMicros);
3358
3359    private native boolean nativeOnAnimate(long nativeContentViewCoreImpl, long frameTimeMicros);
3360
3361    private native boolean nativePopulateBitmapFromCompositor(long nativeContentViewCoreImpl,
3362            Bitmap bitmap);
3363
3364    private native void nativeWasResized(long nativeContentViewCoreImpl);
3365
3366    private native boolean nativeIsRenderWidgetHostViewReady(long nativeContentViewCoreImpl);
3367
3368    private native void nativeExitFullscreen(long nativeContentViewCoreImpl);
3369    private native void nativeUpdateTopControlsState(long nativeContentViewCoreImpl,
3370            boolean enableHiding, boolean enableShowing, boolean animate);
3371
3372    private native void nativeShowImeIfNeeded(long nativeContentViewCoreImpl);
3373
3374    private native void nativeAttachExternalVideoSurface(
3375            long nativeContentViewCoreImpl, int playerId, Surface surface);
3376
3377    private native void nativeDetachExternalVideoSurface(
3378            long nativeContentViewCoreImpl, int playerId);
3379
3380    private native void nativeSetAccessibilityEnabled(
3381            long nativeContentViewCoreImpl, boolean enabled);
3382
3383    private native void nativeSendSingleTapUma(long nativeContentViewCoreImpl,
3384            int type, int count);
3385
3386    private native void nativeSendActionAfterDoubleTapUma(long nativeContentViewCoreImpl,
3387            int type, boolean hasDelay, int count);
3388}
3389