ContentViewCore.java revision a3f7b4e666c476898878fa745f637129375cd889
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)package org.chromium.content.browser; 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.app.Activity; 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.ContentResolver; 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.Context; 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.pm.ActivityInfo; 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.pm.PackageManager; 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.res.Configuration; 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.database.ContentObserver; 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.graphics.Bitmap; 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.graphics.Canvas; 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.graphics.Color; 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.graphics.Rect; 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.net.Uri; 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.Build; 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.Bundle; 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.Handler; 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.ResultReceiver; 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.provider.Settings; 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.provider.Settings.Secure; 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.text.Editable; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.util.Log; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.util.Pair; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.ActionMode; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.InputDevice; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.KeyEvent; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.MotionEvent; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.Surface; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.View; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.ViewGroup; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.Window; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.WindowManager; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.accessibility.AccessibilityEvent; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.accessibility.AccessibilityManager; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.accessibility.AccessibilityNodeInfo; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.accessibility.AccessibilityNodeProvider; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.inputmethod.EditorInfo; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.inputmethod.InputConnection; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.inputmethod.InputMethodManager; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.widget.FrameLayout; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import com.google.common.annotations.VisibleForTesting; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.base.CalledByNative; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.base.JNINamespace; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.base.WeakContext; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.content.R; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.content.browser.ContentViewGestureHandler.MotionEventDelegate; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.content.browser.accessibility.AccessibilityInjector; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.content.browser.accessibility.BrowserAccessibilityManager; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.content.browser.input.AdapterInputConnection; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.content.browser.input.HandleView; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.content.browser.input.ImeAdapter; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.content.browser.input.InputMethodManagerWrapper; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.content.browser.input.ImeAdapter.AdapterInputConnectionFactory; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.content.browser.input.InsertionHandleController; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.content.browser.input.SelectPopupDialog; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.content.browser.input.SelectionHandleController; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.content.common.TraceEvent; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.ui.ViewAndroid; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.ui.ViewAndroidDelegate; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.ui.WindowAndroid; 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.ui.gfx.DeviceDisplayInfo; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.lang.annotation.Annotation; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.lang.reflect.Field; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.Arrays; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.HashMap; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.HashSet; 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.Map; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Provides a Java-side 'wrapper' around a WebContent (native) instance. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Contains all the major functionality necessary to manage the lifecycle of a ContentView without 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * being tied to the view system. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)@JNINamespace("content") 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public class ContentViewCore implements MotionEventDelegate, 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NavigationClient, 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AccessibilityStateChangeListener { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Indicates that input events are batched together and delivered just before vsync. 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static final int INPUT_EVENTS_DELIVERED_AT_VSYNC = 1; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Opposite of INPUT_EVENTS_DELIVERED_AT_VSYNC. 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public static final int INPUT_EVENTS_DELIVERED_IMMEDIATELY = 0; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static final String TAG = "ContentViewCore"; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Used to avoid enabling zooming in / out if resulting zooming will 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // produce little visible difference. 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static final float ZOOM_CONTROLS_EPSILON = 0.007f; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Used to represent gestures for long press and long tap. 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static final int IS_LONG_PRESS = 1; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static final int IS_LONG_TAP = 2; 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Length of the delay (in ms) before fading in handles after the last page movement. 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private static final int TEXT_HANDLE_FADE_IN_DELAY = 300; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the embedder adds a JavaScript interface object that contains an indirect reference to 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the ContentViewCore, then storing a strong ref to the interface object on the native 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // side would prevent garbage collection of the ContentViewCore (as that strong ref would 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // create a new GC root). 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For that reason, we store only a weak reference to the interface object on the 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // native side. However we still need a strong reference on the Java side to 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // prevent garbage collection if the embedder doesn't maintain their own ref to the 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // interface object - the Java side ref won't create a new GC root. 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This map stores those refernces. We put into the map on addJavaScriptInterface() 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and remove from it in removeJavaScriptInterface(). 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private final Map<String, Object> mJavaScriptInterfaces = new HashMap<String, Object>(); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Additionally, we keep track of all Java bound JS objects that are in use on the 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // current page to ensure that they are not garbage collected until the page is 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // navigated. This includes interface objects that have been removed 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // via the removeJavaScriptInterface API and transient objects returned from methods 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // on the interface object. Note we use HashSet rather than Set as the native side 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // expects HashSet (no bindings for interfaces). 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private final HashSet<Object> mRetainedJavaScriptObjects = new HashSet<Object>(); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Interface that consumers of {@link ContentViewCore} must implement to allow the proper 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * dispatching of view methods through the containing view. 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * <p> 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * All methods with the "super_" prefix should be routed to the parent of the 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * implementing container view. 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @SuppressWarnings("javadoc") 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public interface InternalAccessDelegate { 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @see View#drawChild(Canvas, View, long) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) boolean drawChild(Canvas canvas, View child, long drawingTime); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @see View#onKeyUp(keyCode, KeyEvent) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) boolean super_onKeyUp(int keyCode, KeyEvent event); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @see View#dispatchKeyEventPreIme(KeyEvent) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) boolean super_dispatchKeyEventPreIme(KeyEvent event); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @see View#dispatchKeyEvent(KeyEvent) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) boolean super_dispatchKeyEvent(KeyEvent event); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @see View#onGenericMotionEvent(MotionEvent) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) boolean super_onGenericMotionEvent(MotionEvent event); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @see View#onConfigurationChanged(Configuration) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void super_onConfigurationChanged(Configuration newConfig); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @see View#awakenScrollBars() 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) boolean awakenScrollBars(); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @see View#awakenScrollBars(int, boolean) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) boolean super_awakenScrollBars(int startDelay, boolean invalidate); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * An interface that allows the embedder to be notified when the pinch gesture starts and 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * stops. 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public interface PinchGestureStateListener { 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Called when the pinch gesture starts. 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void onPinchGestureStart(); 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Called when the pinch gesture ends. 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void onPinchGestureEnd(); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * An interface for controlling visibility and state of embedder-provided zoom controls. 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public interface ZoomControlsDelegate { 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Called when it's reasonable to show zoom controls. 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void invokeZoomPicker(); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Called when zoom controls need to be hidden (e.g. when the view hides). 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void dismissZoomPicker(); 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Called when page scale has been changed, so the controls can update their state. 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void updateZoomControls(); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * An interface that allows the embedder to be notified of changes to the parameters of the 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * currently displayed contents. 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * These notifications are consistent with respect to the UI thread (the size is the size of 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the contents currently displayed on screen). 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public interface UpdateFrameInfoListener { 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Called each time any of the parameters are changed. 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param widthCss The content width in logical (CSS) pixels. 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param heightCss The content height in logical (CSS) pixels. 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param pageScaleFactor The page scale. 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void onFrameInfoUpdated(float widthCss, float heightCss, float pageScaleFactor); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private VSyncManager.Provider mVSyncProvider; 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private VSyncManager.Listener mVSyncListener; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private int mVSyncSubscriberCount; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private boolean mVSyncListenerRegistered; 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // To avoid IPC delay we use input events to directly trigger a vsync signal in the renderer. 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When we do this, we also need to avoid sending the real vsync signal for the current 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // frame to avoid double-ticking. This flag is used to inhibit the next vsync notification. 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private boolean mDidSignalVSyncUsingInputEvent; 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public VSyncManager.Listener getVSyncListener(VSyncManager.Provider vsyncProvider) { 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mVSyncProvider != null && mVSyncListenerRegistered) { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mVSyncProvider.unregisterVSyncListener(mVSyncListener); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mVSyncListenerRegistered = false; 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mVSyncProvider = vsyncProvider; 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mVSyncListener = new VSyncManager.Listener() { 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @Override 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public void updateVSync(long tickTimeMicros, long intervalMicros) { 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mNativeContentViewCore != 0) { 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nativeUpdateVSyncParameters(mNativeContentViewCore, tickTimeMicros, 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) intervalMicros); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @Override 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public void onVSync(long frameTimeMicros) { 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) animateIfNecessary(frameTimeMicros); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mDidSignalVSyncUsingInputEvent) { 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TraceEvent.instant("ContentViewCore::onVSync ignored"); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mDidSignalVSyncUsingInputEvent = false; 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mNativeContentViewCore != 0) { 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nativeOnVSync(mNativeContentViewCore, frameTimeMicros); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mVSyncSubscriberCount > 0) { 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // setVSyncNotificationEnabled(true) is called before getVSyncListener. 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) vsyncProvider.registerVSyncListener(mVSyncListener); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mVSyncListenerRegistered = true; 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return mVSyncListener; 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @CalledByNative 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void setVSyncNotificationEnabled(boolean enabled) { 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!isVSyncNotificationEnabled() && enabled) { 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mDidSignalVSyncUsingInputEvent = false; 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mVSyncProvider != null) { 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!mVSyncListenerRegistered && enabled) { 287 mVSyncProvider.registerVSyncListener(mVSyncListener); 288 mVSyncListenerRegistered = true; 289 } else if (mVSyncSubscriberCount == 1 && !enabled) { 290 assert mVSyncListenerRegistered; 291 mVSyncProvider.unregisterVSyncListener(mVSyncListener); 292 mVSyncListenerRegistered = false; 293 } 294 } 295 mVSyncSubscriberCount += enabled ? 1 : -1; 296 assert mVSyncSubscriberCount >= 0; 297 } 298 299 @CalledByNative 300 private void resetVSyncNotification() { 301 while (isVSyncNotificationEnabled()) setVSyncNotificationEnabled(false); 302 mVSyncSubscriberCount = 0; 303 mVSyncListenerRegistered = false; 304 mNeedAnimate = false; 305 } 306 307 private boolean isVSyncNotificationEnabled() { 308 return mVSyncProvider != null && mVSyncListenerRegistered; 309 } 310 311 @CalledByNative 312 private void setNeedsAnimate() { 313 if (!mNeedAnimate) { 314 mNeedAnimate = true; 315 setVSyncNotificationEnabled(true); 316 } 317 } 318 319 private final Context mContext; 320 private ViewGroup mContainerView; 321 private InternalAccessDelegate mContainerViewInternals; 322 private WebContentsObserverAndroid mWebContentsObserver; 323 324 private ContentViewClient mContentViewClient; 325 326 private ContentSettings mContentSettings; 327 328 // Native pointer to C++ ContentViewCoreImpl object which will be set by nativeInit(). 329 private int mNativeContentViewCore = 0; 330 331 private boolean mAttachedToWindow = false; 332 333 private ContentViewGestureHandler mContentViewGestureHandler; 334 private PinchGestureStateListener mPinchGestureStateListener; 335 private UpdateFrameInfoListener mUpdateFrameInfoListener; 336 private ZoomManager mZoomManager; 337 private ZoomControlsDelegate mZoomControlsDelegate; 338 339 private PopupZoomer mPopupZoomer; 340 341 private Runnable mFakeMouseMoveRunnable = null; 342 343 // Only valid when focused on a text / password field. 344 private ImeAdapter mImeAdapter; 345 private ImeAdapter.AdapterInputConnectionFactory mAdapterInputConnectionFactory; 346 private AdapterInputConnection mInputConnection; 347 348 private SelectionHandleController mSelectionHandleController; 349 private InsertionHandleController mInsertionHandleController; 350 351 private Runnable mDeferredHandleFadeInRunnable; 352 353 // Size of the viewport in physical pixels as set from onSizeChanged. 354 private int mViewportWidthPix; 355 private int mViewportHeightPix; 356 private int mPhysicalBackingWidthPix; 357 private int mPhysicalBackingHeightPix; 358 private int mOverdrawBottomHeightPix; 359 private int mViewportSizeOffsetWidthPix; 360 private int mViewportSizeOffsetHeightPix; 361 362 // Cached copy of all positions and scales as reported by the renderer. 363 private final RenderCoordinates mRenderCoordinates; 364 365 private final RenderCoordinates.NormalizedPoint mStartHandlePoint; 366 private final RenderCoordinates.NormalizedPoint mEndHandlePoint; 367 private final RenderCoordinates.NormalizedPoint mInsertionHandlePoint; 368 369 // Tracks whether a selection is currently active. When applied to selected text, indicates 370 // whether the last selected text is still highlighted. 371 private boolean mHasSelection; 372 private String mLastSelectedText; 373 private boolean mSelectionEditable; 374 private ActionMode mActionMode; 375 private boolean mUnselectAllOnActionModeDismiss; 376 377 // Delegate that will handle GET downloads, and be notified of completion of POST downloads. 378 private ContentViewDownloadDelegate mDownloadDelegate; 379 380 // The AccessibilityInjector that handles loading Accessibility scripts into the web page. 381 private AccessibilityInjector mAccessibilityInjector; 382 383 // Handles native accessibility, i.e. without any script injection. 384 private BrowserAccessibilityManager mBrowserAccessibilityManager; 385 386 // System accessibility service. 387 private final AccessibilityManager mAccessibilityManager; 388 389 // Allows us to dynamically respond when the accessibility script injection flag changes. 390 private ContentObserver mAccessibilityScriptInjectionObserver; 391 392 // Temporary notification to tell onSizeChanged to focus a form element, 393 // because the OSK was just brought up. 394 private boolean mUnfocusOnNextSizeChanged = false; 395 private final Rect mFocusPreOSKViewportRect = new Rect(); 396 397 private boolean mNeedUpdateOrientationChanged; 398 399 // Used to keep track of whether we should try to undo the last zoom-to-textfield operation. 400 private boolean mScrolledAndZoomedFocusedEditableNode = false; 401 402 // Whether we use hardware-accelerated drawing. 403 private boolean mHardwareAccelerated = false; 404 405 // Whether we received a new frame since consumePendingRendererFrame() was last called. 406 private boolean mPendingRendererFrame = false; 407 408 // Whether we should animate at the next vsync tick. 409 private boolean mNeedAnimate = false; 410 411 private ViewAndroid mViewAndroid; 412 413 414 /** 415 * Constructs a new ContentViewCore. Embedders must call initialize() after constructing 416 * a ContentViewCore and before using it. 417 * 418 * @param context The context used to create this. 419 */ 420 public ContentViewCore(Context context) { 421 mContext = context; 422 423 WeakContext.initializeWeakContext(context); 424 HeapStatsLogger.init(mContext.getApplicationContext()); 425 mAdapterInputConnectionFactory = new AdapterInputConnectionFactory(); 426 427 mRenderCoordinates = new RenderCoordinates(); 428 mRenderCoordinates.setDeviceScaleFactor( 429 getContext().getResources().getDisplayMetrics().density); 430 mStartHandlePoint = mRenderCoordinates.createNormalizedPoint(); 431 mEndHandlePoint = mRenderCoordinates.createNormalizedPoint(); 432 mInsertionHandlePoint = mRenderCoordinates.createNormalizedPoint(); 433 mAccessibilityManager = (AccessibilityManager) 434 getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); 435 } 436 437 /** 438 * @return The context used for creating this ContentViewCore. 439 */ 440 @CalledByNative 441 public Context getContext() { 442 return mContext; 443 } 444 445 /** 446 * @return The ViewGroup that all view actions of this ContentViewCore should interact with. 447 */ 448 public ViewGroup getContainerView() { 449 return mContainerView; 450 } 451 452 /** 453 * Specifies how much smaller the WebKit layout size should be relative to the size of this 454 * view. 455 * @param offsetXPix The X amount in pixels to shrink the viewport by. 456 * @param offsetYPix The Y amount in pixels to shrink the viewport by. 457 */ 458 public void setViewportSizeOffset(int offsetXPix, int offsetYPix) { 459 if (offsetXPix != mViewportSizeOffsetWidthPix || 460 offsetYPix != mViewportSizeOffsetHeightPix) { 461 mViewportSizeOffsetWidthPix = offsetXPix; 462 mViewportSizeOffsetHeightPix = offsetYPix; 463 if (mNativeContentViewCore != 0) nativeWasResized(mNativeContentViewCore); 464 } 465 } 466 467 /** 468 * Returns a delegate that can be used to add and remove views from the ContainerView. 469 * 470 * NOTE: Use with care, as not all ContentViewCore users setup their ContainerView in the same 471 * way. In particular, the Android WebView has limitations on what implementation details can 472 * be provided via a child view, as they are visible in the API and could introduce 473 * compatibility breaks with existing applications. If in doubt, contact the 474 * android_webview/OWNERS 475 * 476 * @return A ViewAndroidDelegate that can be used to add and remove views. 477 */ 478 @VisibleForTesting 479 public ViewAndroidDelegate getViewAndroidDelegate() { 480 return new ViewAndroidDelegate() { 481 @Override 482 public View acquireAnchorView() { 483 View anchorView = new View(getContext()); 484 mContainerView.addView(anchorView); 485 return anchorView; 486 } 487 488 @Override 489 public void setAnchorViewPosition( 490 View view, float x, float y, float width, float height) { 491 assert(view.getParent() == mContainerView); 492 float scale = (float) DeviceDisplayInfo.create(getContext()).getDIPScale(); 493 494 // The anchor view should not go outside the bounds of the ContainerView. 495 int scaledX = Math.round(x * scale); 496 int scaledWidth = Math.round(width * scale); 497 if (scaledWidth + scaledX > mContainerView.getWidth()) { 498 scaledWidth = mContainerView.getWidth() - scaledX; 499 } 500 501 FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( 502 scaledWidth, Math.round(height * scale)); 503 lp.leftMargin = scaledX; 504 lp.topMargin = (int) mRenderCoordinates.getContentOffsetYPix() + 505 Math.round(y * scale); 506 view.setLayoutParams(lp); 507 } 508 509 @Override 510 public void releaseAnchorView(View anchorView) { 511 mContainerView.removeView(anchorView); 512 } 513 }; 514 } 515 516 @VisibleForTesting 517 public ImeAdapter getImeAdapterForTest() { 518 return mImeAdapter; 519 } 520 521 @VisibleForTesting 522 public void setAdapterInputConnectionFactory(AdapterInputConnectionFactory factory) { 523 mAdapterInputConnectionFactory = factory; 524 } 525 526 @VisibleForTesting 527 public AdapterInputConnection getInputConnectionForTest() { 528 return mInputConnection; 529 } 530 531 private ImeAdapter createImeAdapter(Context context) { 532 return new ImeAdapter(new InputMethodManagerWrapper(context), 533 new ImeAdapter.ImeAdapterDelegate() { 534 @Override 535 public void onImeEvent(boolean isFinish) { 536 getContentViewClient().onImeEvent(); 537 if (!isFinish) { 538 undoScrollFocusedEditableNodeIntoViewIfNeeded(false); 539 } 540 } 541 542 @Override 543 public void onSetFieldValue() { 544 scrollFocusedEditableNodeIntoView(); 545 } 546 547 @Override 548 public void onDismissInput() { 549 getContentViewClient().onImeStateChangeRequested(false); 550 } 551 552 @Override 553 public View getAttachedView() { 554 return mContainerView; 555 } 556 557 @Override 558 public ResultReceiver getNewShowKeyboardReceiver() { 559 return new ResultReceiver(new Handler()) { 560 @Override 561 public void onReceiveResult(int resultCode, Bundle resultData) { 562 getContentViewClient().onImeStateChangeRequested( 563 resultCode == InputMethodManager.RESULT_SHOWN || 564 resultCode == InputMethodManager.RESULT_UNCHANGED_SHOWN); 565 if (resultCode == InputMethodManager.RESULT_SHOWN) { 566 // If OSK is newly shown, delay the form focus until 567 // the onSizeChanged (in order to adjust relative to the 568 // new size). 569 getContainerView().getWindowVisibleDisplayFrame( 570 mFocusPreOSKViewportRect); 571 } else if (resultCode == 572 InputMethodManager.RESULT_UNCHANGED_SHOWN) { 573 // If the OSK was already there, focus the form immediately. 574 scrollFocusedEditableNodeIntoView(); 575 } else { 576 undoScrollFocusedEditableNodeIntoViewIfNeeded(false); 577 } 578 } 579 }; 580 } 581 582 @Override 583 public void hideSelectionAndInsertionHandles() { 584 getInsertionHandleController().hideAndDisallowAutomaticShowing(); 585 getSelectionHandleController().hideAndDisallowAutomaticShowing(); 586 } 587 } 588 ); 589 } 590 591 /** 592 * Returns true if the given Activity has hardware acceleration enabled 593 * in its manifest, or in its foreground window. 594 * 595 * TODO(husky): Remove when initialize() is refactored (see TODO there) 596 * TODO(dtrainor) This is still used by other classes. Make sure to pull some version of this 597 * out before removing it. 598 */ 599 public static boolean hasHardwareAcceleration(Activity activity) { 600 // Has HW acceleration been enabled manually in the current window? 601 Window window = activity.getWindow(); 602 if (window != null) { 603 if ((window.getAttributes().flags 604 & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0) { 605 return true; 606 } 607 } 608 609 // Has HW acceleration been enabled in the manifest? 610 try { 611 ActivityInfo info = activity.getPackageManager().getActivityInfo( 612 activity.getComponentName(), 0); 613 if ((info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) { 614 return true; 615 } 616 } catch (PackageManager.NameNotFoundException e) { 617 Log.e("Chrome", "getActivityInfo(self) should not fail"); 618 } 619 620 return false; 621 } 622 623 /** 624 * Returns true if the given Context is a HW-accelerated Activity. 625 * 626 * TODO(husky): Remove when initialize() is refactored (see TODO there) 627 */ 628 private static boolean hasHardwareAcceleration(Context context) { 629 if (context instanceof Activity) { 630 return hasHardwareAcceleration((Activity) context); 631 } 632 return false; 633 } 634 635 /** 636 * 637 * @param containerView The view that will act as a container for all views created by this. 638 * @param internalDispatcher Handles dispatching all hidden or super methods to the 639 * containerView. 640 * @param nativeWebContents A pointer to the native web contents. 641 * @param windowAndroid An instance of the WindowAndroid. 642 */ 643 // Perform important post-construction set up of the ContentViewCore. 644 // We do not require the containing view in the constructor to allow embedders to create a 645 // ContentViewCore without having fully created its containing view. The containing view 646 // is a vital component of the ContentViewCore, so embedders must exercise caution in what 647 // they do with the ContentViewCore before calling initialize(). 648 // We supply the nativeWebContents pointer here rather than in the constructor to allow us 649 // to set the private browsing mode at a later point for the WebView implementation. 650 // Note that the caller remains the owner of the nativeWebContents and is responsible for 651 // deleting it after destroying the ContentViewCore. 652 public void initialize(ViewGroup containerView, InternalAccessDelegate internalDispatcher, 653 int nativeWebContents, WindowAndroid windowAndroid, 654 int inputEventDeliveryMode) { 655 // Check whether to use hardware acceleration. This is a bit hacky, and 656 // only works if the Context is actually an Activity (as it is in the 657 // Chrome application). 658 // 659 // What we're doing here is checking whether the app has *requested* 660 // hardware acceleration by setting the appropriate flags. This does not 661 // necessarily mean we're going to *get* hardware acceleration -- that's 662 // up to the Android framework. 663 // 664 // TODO(husky): Once the native code has been updated so that the 665 // HW acceleration flag can be set dynamically (Grace is doing this), 666 // move this check into onAttachedToWindow(), where we can test for 667 // HW support directly. 668 mHardwareAccelerated = hasHardwareAcceleration(mContext); 669 670 mContainerView = containerView; 671 672 int windowNativePointer = windowAndroid != null ? windowAndroid.getNativePointer() : 0; 673 674 int viewAndroidNativePointer = 0; 675 if (windowNativePointer != 0) { 676 mViewAndroid = new ViewAndroid(windowAndroid, getViewAndroidDelegate()); 677 viewAndroidNativePointer = mViewAndroid.getNativePointer(); 678 } 679 680 mNativeContentViewCore = nativeInit(mHardwareAccelerated, 681 nativeWebContents, viewAndroidNativePointer, windowNativePointer); 682 mContentSettings = new ContentSettings(this, mNativeContentViewCore); 683 initializeContainerView(internalDispatcher, inputEventDeliveryMode); 684 685 mAccessibilityInjector = AccessibilityInjector.newInstance(this); 686 687 String contentDescription = "Web View"; 688 if (R.string.accessibility_content_view == 0) { 689 Log.w(TAG, "Setting contentDescription to 'Web View' as no value was specified."); 690 } else { 691 contentDescription = mContext.getResources().getString( 692 R.string.accessibility_content_view); 693 } 694 mContainerView.setContentDescription(contentDescription); 695 mWebContentsObserver = new WebContentsObserverAndroid(this) { 696 @Override 697 public void didStartLoading(String url) { 698 hidePopupDialog(); 699 resetGestureDetectors(); 700 } 701 }; 702 } 703 704 @CalledByNative 705 void onNativeContentViewCoreDestroyed(int nativeContentViewCore) { 706 assert nativeContentViewCore == mNativeContentViewCore; 707 mNativeContentViewCore = 0; 708 } 709 710 /** 711 * Initializes the View that will contain all Views created by the ContentViewCore. 712 * 713 * @param internalDispatcher Handles dispatching all hidden or super methods to the 714 * containerView. 715 */ 716 private void initializeContainerView(InternalAccessDelegate internalDispatcher, 717 int inputEventDeliveryMode) { 718 TraceEvent.begin(); 719 mContainerViewInternals = internalDispatcher; 720 721 mContainerView.setWillNotDraw(false); 722 mContainerView.setFocusable(true); 723 mContainerView.setFocusableInTouchMode(true); 724 mContainerView.setClickable(true); 725 726 if (mContainerView.getScrollBarStyle() == View.SCROLLBARS_INSIDE_OVERLAY) { 727 mContainerView.setHorizontalScrollBarEnabled(false); 728 mContainerView.setVerticalScrollBarEnabled(false); 729 } 730 731 mZoomManager = new ZoomManager(mContext, this); 732 mContentViewGestureHandler = new ContentViewGestureHandler(mContext, this, mZoomManager, 733 inputEventDeliveryMode); 734 mZoomControlsDelegate = new ZoomControlsDelegate() { 735 @Override 736 public void invokeZoomPicker() {} 737 @Override 738 public void dismissZoomPicker() {} 739 @Override 740 public void updateZoomControls() {} 741 }; 742 743 mRenderCoordinates.reset(); 744 745 initPopupZoomer(mContext); 746 mImeAdapter = createImeAdapter(mContext); 747 TraceEvent.end(); 748 } 749 750 private void initPopupZoomer(Context context){ 751 mPopupZoomer = new PopupZoomer(context); 752 mPopupZoomer.setOnVisibilityChangedListener(new PopupZoomer.OnVisibilityChangedListener() { 753 @Override 754 public void onPopupZoomerShown(final PopupZoomer zoomer) { 755 mContainerView.post(new Runnable() { 756 @Override 757 public void run() { 758 if (mContainerView.indexOfChild(zoomer) == -1) { 759 mContainerView.addView(zoomer); 760 } else { 761 assert false : "PopupZoomer should never be shown without being hidden"; 762 } 763 } 764 }); 765 } 766 767 @Override 768 public void onPopupZoomerHidden(final PopupZoomer zoomer) { 769 mContainerView.post(new Runnable() { 770 @Override 771 public void run() { 772 if (mContainerView.indexOfChild(zoomer) != -1) { 773 mContainerView.removeView(zoomer); 774 mContainerView.invalidate(); 775 } else { 776 assert false : "PopupZoomer should never be hidden without being shown"; 777 } 778 } 779 }); 780 } 781 }); 782 // TODO(yongsheng): LONG_TAP is not enabled in PopupZoomer. So need to dispatch a LONG_TAP 783 // gesture if a user completes a tap on PopupZoomer UI after a LONG_PRESS gesture. 784 PopupZoomer.OnTapListener listener = new PopupZoomer.OnTapListener() { 785 @Override 786 public boolean onSingleTap(View v, MotionEvent e) { 787 mContainerView.requestFocus(); 788 if (mNativeContentViewCore != 0) { 789 nativeSingleTap(mNativeContentViewCore, e.getEventTime(), 790 e.getX(), e.getY(), true); 791 } 792 return true; 793 } 794 795 @Override 796 public boolean onLongPress(View v, MotionEvent e) { 797 if (mNativeContentViewCore != 0) { 798 nativeLongPress(mNativeContentViewCore, e.getEventTime(), 799 e.getX(), e.getY(), true); 800 } 801 return true; 802 } 803 }; 804 mPopupZoomer.setOnTapListener(listener); 805 } 806 807 /** 808 * Destroy the internal state of the ContentView. This method may only be 809 * called after the ContentView has been removed from the view system. No 810 * other methods may be called on this ContentView after this method has 811 * been called. 812 */ 813 public void destroy() { 814 if (mNativeContentViewCore != 0) { 815 nativeOnJavaContentViewCoreDestroyed(mNativeContentViewCore); 816 } 817 resetVSyncNotification(); 818 mVSyncProvider = null; 819 if (mViewAndroid != null) mViewAndroid.destroy(); 820 mNativeContentViewCore = 0; 821 mContentSettings = null; 822 mJavaScriptInterfaces.clear(); 823 mRetainedJavaScriptObjects.clear(); 824 if (mAccessibilityScriptInjectionObserver != null) { 825 getContext().getContentResolver().unregisterContentObserver( 826 mAccessibilityScriptInjectionObserver); 827 mAccessibilityScriptInjectionObserver = null; 828 } 829 } 830 831 /** 832 * Returns true initially, false after destroy() has been called. 833 * It is illegal to call any other public method after destroy(). 834 */ 835 public boolean isAlive() { 836 return mNativeContentViewCore != 0; 837 } 838 839 /** 840 * This is only useful for passing over JNI to native code that requires ContentViewCore*. 841 * @return native ContentViewCore pointer. 842 */ 843 @CalledByNative 844 public int getNativeContentViewCore() { 845 return mNativeContentViewCore; 846 } 847 848 /** 849 * For internal use. Throws IllegalStateException if mNativeContentView is 0. 850 * Use this to ensure we get a useful Java stack trace, rather than a native 851 * crash dump, from use-after-destroy bugs in Java code. 852 */ 853 void checkIsAlive() throws IllegalStateException { 854 if (!isAlive()) { 855 throw new IllegalStateException("ContentView used after destroy() was called"); 856 } 857 } 858 859 public void setContentViewClient(ContentViewClient client) { 860 if (client == null) { 861 throw new IllegalArgumentException("The client can't be null."); 862 } 863 mContentViewClient = client; 864 } 865 866 ContentViewClient getContentViewClient() { 867 if (mContentViewClient == null) { 868 // We use the Null Object pattern to avoid having to perform a null check in this class. 869 // We create it lazily because most of the time a client will be set almost immediately 870 // after ContentView is created. 871 mContentViewClient = new ContentViewClient(); 872 // We don't set the native ContentViewClient pointer here on purpose. The native 873 // implementation doesn't mind a null delegate and using one is better than passing a 874 // Null Object, since we cut down on the number of JNI calls. 875 } 876 return mContentViewClient; 877 } 878 879 public int getBackgroundColor() { 880 if (mNativeContentViewCore != 0) { 881 return nativeGetBackgroundColor(mNativeContentViewCore); 882 } 883 return Color.WHITE; 884 } 885 886 @CalledByNative 887 private void onBackgroundColorChanged(int color) { 888 getContentViewClient().onBackgroundColorChanged(color); 889 } 890 891 /** 892 * Load url without fixing up the url string. Consumers of ContentView are responsible for 893 * ensuring the URL passed in is properly formatted (i.e. the scheme has been added if left 894 * off during user input). 895 * 896 * @param params Parameters for this load. 897 */ 898 public void loadUrl(LoadUrlParams params) { 899 if (mNativeContentViewCore == 0) return; 900 901 nativeLoadUrl(mNativeContentViewCore, 902 params.mUrl, 903 params.mLoadUrlType, 904 params.mTransitionType, 905 params.mUaOverrideOption, 906 params.getExtraHeadersString(), 907 params.mPostData, 908 params.mBaseUrlForDataUrl, 909 params.mVirtualUrlForDataUrl, 910 params.mCanLoadLocalResources); 911 } 912 913 /** 914 * Stops loading the current web contents. 915 */ 916 public void stopLoading() { 917 if (mNativeContentViewCore != 0) nativeStopLoading(mNativeContentViewCore); 918 } 919 920 /** 921 * Get the URL of the current page. 922 * 923 * @return The URL of the current page. 924 */ 925 public String getUrl() { 926 if (mNativeContentViewCore != 0) return nativeGetURL(mNativeContentViewCore); 927 return null; 928 } 929 930 /** 931 * Get the title of the current page. 932 * 933 * @return The title of the current page. 934 */ 935 public String getTitle() { 936 if (mNativeContentViewCore != 0) return nativeGetTitle(mNativeContentViewCore); 937 return null; 938 } 939 940 /** 941 * Shows an interstitial page driven by the passed in delegate. 942 * 943 * @param url The URL being blocked by the interstitial. 944 * @param delegate The delegate handling the interstitial. 945 */ 946 @VisibleForTesting 947 public void showInterstitialPage( 948 String url, InterstitialPageDelegateAndroid delegate) { 949 if (mNativeContentViewCore == 0) return; 950 nativeShowInterstitialPage(mNativeContentViewCore, url, delegate.getNative()); 951 } 952 953 /** 954 * @return Whether the page is currently showing an interstitial, such as a bad HTTPS page. 955 */ 956 public boolean isShowingInterstitialPage() { 957 return mNativeContentViewCore == 0 ? 958 false : nativeIsShowingInterstitialPage(mNativeContentViewCore); 959 } 960 961 /** 962 * Mark any new frames that have arrived since this function was last called as non-pending. 963 * 964 * @return Whether there was a pending frame from the renderer. 965 */ 966 public boolean consumePendingRendererFrame() { 967 boolean hadPendingFrame = mPendingRendererFrame; 968 mPendingRendererFrame = false; 969 return hadPendingFrame; 970 } 971 972 /** 973 * @return Viewport width in physical pixels as set from onSizeChanged. 974 */ 975 @CalledByNative 976 public int getViewportWidthPix() { return mViewportWidthPix; } 977 978 /** 979 * @return Viewport height in physical pixels as set from onSizeChanged. 980 */ 981 @CalledByNative 982 public int getViewportHeightPix() { return mViewportHeightPix; } 983 984 /** 985 * @return Width of underlying physical surface. 986 */ 987 @CalledByNative 988 public int getPhysicalBackingWidthPix() { return mPhysicalBackingWidthPix; } 989 990 /** 991 * @return Height of underlying physical surface. 992 */ 993 @CalledByNative 994 public int getPhysicalBackingHeightPix() { return mPhysicalBackingHeightPix; } 995 996 /** 997 * @return Amount the output surface extends past the bottom of the window viewport. 998 */ 999 @CalledByNative 1000 public int getOverdrawBottomHeightPix() { return mOverdrawBottomHeightPix; } 1001 1002 /** 1003 * @return The amount to shrink the viewport relative to {@link #getViewportWidthPix()}. 1004 */ 1005 @CalledByNative 1006 public int getViewportSizeOffsetWidthPix() { return mViewportSizeOffsetWidthPix; } 1007 1008 /** 1009 * @return The amount to shrink the viewport relative to {@link #getViewportHeightPix()}. 1010 */ 1011 @CalledByNative 1012 public int getViewportSizeOffsetHeightPix() { return mViewportSizeOffsetHeightPix; } 1013 1014 /** 1015 * @see android.webkit.WebView#getContentHeight() 1016 */ 1017 public float getContentHeightCss() { 1018 return mRenderCoordinates.getContentHeightCss(); 1019 } 1020 1021 /** 1022 * @see android.webkit.WebView#getContentWidth() 1023 */ 1024 public float getContentWidthCss() { 1025 return mRenderCoordinates.getContentWidthCss(); 1026 } 1027 1028 public Bitmap getBitmap() { 1029 return getBitmap(getViewportWidthPix(), getViewportHeightPix()); 1030 } 1031 1032 public Bitmap getBitmap(int width, int height) { 1033 if (width == 0 || height == 0 1034 || getViewportWidthPix() == 0 || getViewportHeightPix() == 0) { 1035 return null; 1036 } 1037 1038 Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 1039 1040 if (mNativeContentViewCore != 0 && 1041 nativePopulateBitmapFromCompositor(mNativeContentViewCore, b)) { 1042 // If we successfully grabbed a bitmap, check if we have to draw the Android overlay 1043 // components as well. 1044 if (mContainerView.getChildCount() > 0) { 1045 Canvas c = new Canvas(b); 1046 c.scale(width / (float) getViewportWidthPix(), 1047 height / (float) getViewportHeightPix()); 1048 mContainerView.draw(c); 1049 } 1050 return b; 1051 } 1052 1053 return null; 1054 } 1055 1056 /** 1057 * Generates a bitmap of the content that is performance optimized based on capture time. 1058 * 1059 * <p> 1060 * To have a consistent capture time across devices, we will scale down the captured bitmap 1061 * where necessary to reduce the time to generate the bitmap. 1062 * 1063 * @param width The width of the content to be captured. 1064 * @param height The height of the content to be captured. 1065 * @return A pair of the generated bitmap, and the scale that needs to be applied to return the 1066 * bitmap to it's original size (i.e. if the bitmap is scaled down 50%, this 1067 * will be 2). 1068 */ 1069 public Pair<Bitmap, Float> getScaledPerformanceOptimizedBitmap(int width, int height) { 1070 float scale = 1f; 1071 // On tablets, always scale down to MDPI for performance reasons. 1072 if (DeviceUtils.isTablet(getContext())) { 1073 scale = getContext().getResources().getDisplayMetrics().density; 1074 } 1075 return Pair.create( 1076 getBitmap((int) (width / scale), (int) (height / scale)), 1077 scale); 1078 } 1079 1080 /** 1081 * @return Whether the current WebContents has a previous navigation entry. 1082 */ 1083 public boolean canGoBack() { 1084 return mNativeContentViewCore != 0 && nativeCanGoBack(mNativeContentViewCore); 1085 } 1086 1087 /** 1088 * @return Whether the current WebContents has a navigation entry after the current one. 1089 */ 1090 public boolean canGoForward() { 1091 return mNativeContentViewCore != 0 && nativeCanGoForward(mNativeContentViewCore); 1092 } 1093 1094 /** 1095 * @param offset The offset into the navigation history. 1096 * @return Whether we can move in history by given offset 1097 */ 1098 public boolean canGoToOffset(int offset) { 1099 return mNativeContentViewCore != 0 && nativeCanGoToOffset(mNativeContentViewCore, offset); 1100 } 1101 1102 /** 1103 * Navigates to the specified offset from the "current entry". Does nothing if the offset is out 1104 * of bounds. 1105 * @param offset The offset into the navigation history. 1106 */ 1107 public void goToOffset(int offset) { 1108 if (mNativeContentViewCore != 0) nativeGoToOffset(mNativeContentViewCore, offset); 1109 } 1110 1111 @Override 1112 public void goToNavigationIndex(int index) { 1113 if (mNativeContentViewCore != 0) nativeGoToNavigationIndex(mNativeContentViewCore, index); 1114 } 1115 1116 /** 1117 * Goes to the navigation entry before the current one. 1118 */ 1119 public void goBack() { 1120 if (mNativeContentViewCore != 0) nativeGoBack(mNativeContentViewCore); 1121 } 1122 1123 /** 1124 * Goes to the navigation entry following the current one. 1125 */ 1126 public void goForward() { 1127 if (mNativeContentViewCore != 0) nativeGoForward(mNativeContentViewCore); 1128 } 1129 1130 /** 1131 * Reload the current page. 1132 */ 1133 public void reload() { 1134 mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary(); 1135 if (mNativeContentViewCore != 0) nativeReload(mNativeContentViewCore); 1136 } 1137 1138 /** 1139 * Cancel the pending reload. 1140 */ 1141 public void cancelPendingReload() { 1142 if (mNativeContentViewCore != 0) nativeCancelPendingReload(mNativeContentViewCore); 1143 } 1144 1145 /** 1146 * Continue the pending reload. 1147 */ 1148 public void continuePendingReload() { 1149 if (mNativeContentViewCore != 0) nativeContinuePendingReload(mNativeContentViewCore); 1150 } 1151 1152 /** 1153 * Clears the ContentViewCore's page history in both the backwards and 1154 * forwards directions. 1155 */ 1156 public void clearHistory() { 1157 if (mNativeContentViewCore != 0) nativeClearHistory(mNativeContentViewCore); 1158 } 1159 1160 String getSelectedText() { 1161 return mHasSelection ? mLastSelectedText : ""; 1162 } 1163 1164 // End FrameLayout overrides. 1165 1166 /** 1167 * @see {@link android.webkit.WebView#flingScroll(int, int)} 1168 */ 1169 public void flingScroll(int vx, int vy) { 1170 // Notes: 1171 // (1) Use large negative values for the x/y parameters so we don't accidentally scroll a 1172 // nested frame. 1173 // (2) vx and vy are inverted to match WebView behavior. 1174 mContentViewGestureHandler.fling( 1175 System.currentTimeMillis(), -Integer.MAX_VALUE, -Integer.MIN_VALUE, -vx, -vy); 1176 } 1177 1178 /** 1179 * @see View#onTouchEvent(MotionEvent) 1180 */ 1181 public boolean onTouchEvent(MotionEvent event) { 1182 undoScrollFocusedEditableNodeIntoViewIfNeeded(false); 1183 return mContentViewGestureHandler.onTouchEvent(event); 1184 } 1185 1186 /** 1187 * @return ContentViewGestureHandler for all MotionEvent and gesture related calls. 1188 */ 1189 ContentViewGestureHandler getContentViewGestureHandler() { 1190 return mContentViewGestureHandler; 1191 } 1192 1193 @Override 1194 public boolean sendTouchEvent(long timeMs, int action, TouchPoint[] pts) { 1195 if (mNativeContentViewCore != 0) { 1196 return nativeSendTouchEvent(mNativeContentViewCore, timeMs, action, pts); 1197 } 1198 return false; 1199 } 1200 1201 @SuppressWarnings("unused") 1202 @CalledByNative 1203 private void hasTouchEventHandlers(boolean hasTouchHandlers) { 1204 mContentViewGestureHandler.hasTouchEventHandlers(hasTouchHandlers); 1205 } 1206 1207 @SuppressWarnings("unused") 1208 @CalledByNative 1209 private void confirmTouchEvent(int ackResult) { 1210 mContentViewGestureHandler.confirmTouchEvent(ackResult); 1211 } 1212 1213 @Override 1214 public boolean sendGesture(int type, long timeMs, int x, int y, boolean lastInputEventForVSync, 1215 Bundle b) { 1216 if (offerGestureToEmbedder(type)) return false; 1217 if (mNativeContentViewCore == 0) return false; 1218 updateTextHandlesForGesture(type); 1219 updatePinchGestureStateListener(type); 1220 if (lastInputEventForVSync && isVSyncNotificationEnabled()) { 1221 assert type == ContentViewGestureHandler.GESTURE_SCROLL_BY || 1222 type == ContentViewGestureHandler.GESTURE_PINCH_BY; 1223 mDidSignalVSyncUsingInputEvent = true; 1224 } 1225 switch (type) { 1226 case ContentViewGestureHandler.GESTURE_SHOW_PRESSED_STATE: 1227 nativeShowPressState(mNativeContentViewCore, timeMs, x, y); 1228 return true; 1229 case ContentViewGestureHandler.GESTURE_SHOW_PRESS_CANCEL: 1230 nativeShowPressCancel(mNativeContentViewCore, timeMs, x, y); 1231 return true; 1232 case ContentViewGestureHandler.GESTURE_DOUBLE_TAP: 1233 nativeDoubleTap(mNativeContentViewCore, timeMs, x, y); 1234 return true; 1235 case ContentViewGestureHandler.GESTURE_SINGLE_TAP_UP: 1236 nativeSingleTap(mNativeContentViewCore, timeMs, x, y, false); 1237 return true; 1238 case ContentViewGestureHandler.GESTURE_SINGLE_TAP_CONFIRMED: 1239 handleTapOrPress(timeMs, x, y, 0, 1240 b.getBoolean(ContentViewGestureHandler.SHOW_PRESS, false)); 1241 return true; 1242 case ContentViewGestureHandler.GESTURE_SINGLE_TAP_UNCONFIRMED: 1243 nativeSingleTapUnconfirmed(mNativeContentViewCore, timeMs, x, y); 1244 return true; 1245 case ContentViewGestureHandler.GESTURE_LONG_PRESS: 1246 handleTapOrPress(timeMs, x, y, IS_LONG_PRESS, false); 1247 return true; 1248 case ContentViewGestureHandler.GESTURE_LONG_TAP: 1249 handleTapOrPress(timeMs, x, y, IS_LONG_TAP, false); 1250 return true; 1251 case ContentViewGestureHandler.GESTURE_SCROLL_START: 1252 nativeScrollBegin(mNativeContentViewCore, timeMs, x, y); 1253 return true; 1254 case ContentViewGestureHandler.GESTURE_SCROLL_BY: { 1255 int dx = b.getInt(ContentViewGestureHandler.DISTANCE_X); 1256 int dy = b.getInt(ContentViewGestureHandler.DISTANCE_Y); 1257 nativeScrollBy(mNativeContentViewCore, timeMs, x, y, dx, dy, 1258 lastInputEventForVSync); 1259 return true; 1260 } 1261 case ContentViewGestureHandler.GESTURE_SCROLL_END: 1262 nativeScrollEnd(mNativeContentViewCore, timeMs); 1263 return true; 1264 case ContentViewGestureHandler.GESTURE_FLING_START: 1265 nativeFlingStart(mNativeContentViewCore, timeMs, x, y, 1266 b.getInt(ContentViewGestureHandler.VELOCITY_X, 0), 1267 b.getInt(ContentViewGestureHandler.VELOCITY_Y, 0)); 1268 return true; 1269 case ContentViewGestureHandler.GESTURE_FLING_CANCEL: 1270 nativeFlingCancel(mNativeContentViewCore, timeMs); 1271 return true; 1272 case ContentViewGestureHandler.GESTURE_PINCH_BEGIN: 1273 nativePinchBegin(mNativeContentViewCore, timeMs, x, y); 1274 return true; 1275 case ContentViewGestureHandler.GESTURE_PINCH_BY: 1276 nativePinchBy(mNativeContentViewCore, timeMs, x, y, 1277 b.getFloat(ContentViewGestureHandler.DELTA, 0), 1278 lastInputEventForVSync); 1279 return true; 1280 case ContentViewGestureHandler.GESTURE_PINCH_END: 1281 nativePinchEnd(mNativeContentViewCore, timeMs); 1282 return true; 1283 default: 1284 return false; 1285 } 1286 } 1287 1288 public void setPinchGestureStateListener(PinchGestureStateListener pinchGestureStateListener) { 1289 mPinchGestureStateListener = pinchGestureStateListener; 1290 } 1291 1292 void updatePinchGestureStateListener(int gestureType) { 1293 if (mPinchGestureStateListener == null) return; 1294 1295 switch (gestureType) { 1296 case ContentViewGestureHandler.GESTURE_PINCH_BEGIN: 1297 mPinchGestureStateListener.onPinchGestureStart(); 1298 break; 1299 case ContentViewGestureHandler.GESTURE_PINCH_END: 1300 mPinchGestureStateListener.onPinchGestureEnd(); 1301 break; 1302 default: 1303 break; 1304 } 1305 } 1306 1307 public interface JavaScriptCallback { 1308 void handleJavaScriptResult(String jsonResult); 1309 } 1310 1311 /** 1312 * Injects the passed Javascript code in the current page and evaluates it. 1313 * If a result is required, pass in a callback. 1314 * Used in automation tests. 1315 * 1316 * @param script The Javascript to execute. 1317 * @param callback The callback to be fired off when a result is ready. The script's 1318 * result will be json encoded and passed as the parameter, and the call 1319 * will be made on the main thread. 1320 * If no result is required, pass null. 1321 * @throws IllegalStateException If the ContentView has been destroyed. 1322 */ 1323 public void evaluateJavaScript( 1324 String script, JavaScriptCallback callback) throws IllegalStateException { 1325 checkIsAlive(); 1326 nativeEvaluateJavaScript(mNativeContentViewCore, script, callback); 1327 } 1328 1329 /** 1330 * This method should be called when the containing activity is paused. 1331 */ 1332 public void onActivityPause() { 1333 TraceEvent.begin(); 1334 hidePopupDialog(); 1335 nativeOnHide(mNativeContentViewCore); 1336 TraceEvent.end(); 1337 } 1338 1339 /** 1340 * This method should be called when the containing activity is resumed. 1341 */ 1342 public void onActivityResume() { 1343 nativeOnShow(mNativeContentViewCore); 1344 setAccessibilityState(mAccessibilityManager.isEnabled()); 1345 } 1346 1347 /** 1348 * To be called when the ContentView is shown. 1349 */ 1350 public void onShow() { 1351 nativeOnShow(mNativeContentViewCore); 1352 setAccessibilityState(mAccessibilityManager.isEnabled()); 1353 } 1354 1355 /** 1356 * To be called when the ContentView is hidden. 1357 */ 1358 public void onHide() { 1359 hidePopupDialog(); 1360 setInjectedAccessibility(false); 1361 nativeOnHide(mNativeContentViewCore); 1362 } 1363 1364 /** 1365 * Return the ContentSettings object used to retrieve the settings for this 1366 * ContentViewCore. For modifications, ChromeNativePreferences is to be used. 1367 * @return A ContentSettings object that can be used to retrieve this 1368 * ContentViewCore's settings. 1369 */ 1370 public ContentSettings getContentSettings() { 1371 return mContentSettings; 1372 } 1373 1374 @Override 1375 public boolean didUIStealScroll(float x, float y) { 1376 return getContentViewClient().shouldOverrideScroll( 1377 x, y, computeHorizontalScrollOffset(), computeVerticalScrollOffset()); 1378 } 1379 1380 @Override 1381 public boolean hasFixedPageScale() { 1382 return mRenderCoordinates.hasFixedPageScale(); 1383 } 1384 1385 private void hidePopupDialog() { 1386 SelectPopupDialog.hide(this); 1387 hideHandles(); 1388 hideSelectActionBar(); 1389 } 1390 1391 void hideSelectActionBar() { 1392 if (mActionMode != null) { 1393 mActionMode.finish(); 1394 mActionMode = null; 1395 } 1396 } 1397 1398 private void resetGestureDetectors() { 1399 mContentViewGestureHandler.resetGestureHandlers(); 1400 } 1401 1402 /** 1403 * @see View#onAttachedToWindow() 1404 */ 1405 @SuppressWarnings("javadoc") 1406 public void onAttachedToWindow() { 1407 mAttachedToWindow = true; 1408 if (mNativeContentViewCore != 0) { 1409 int pid = nativeGetCurrentRenderProcessId(mNativeContentViewCore); 1410 ChildProcessLauncher.bindAsHighPriority(pid); 1411 // Normally the initial binding is removed in onRenderProcessSwap(), but it is 1412 // possible to construct WebContents and spawn the renderer before passing it to 1413 // ContentViewCore. In this case there will be no onRendererSwap() call and the 1414 // initial binding will be removed here. 1415 ChildProcessLauncher.removeInitialBinding(pid); 1416 } 1417 setAccessibilityState(mAccessibilityManager.isEnabled()); 1418 } 1419 1420 /** 1421 * @see View#onDetachedFromWindow() 1422 */ 1423 @SuppressWarnings("javadoc") 1424 public void onDetachedFromWindow() { 1425 mAttachedToWindow = false; 1426 if (mNativeContentViewCore != 0) { 1427 int pid = nativeGetCurrentRenderProcessId(mNativeContentViewCore); 1428 ChildProcessLauncher.unbindAsHighPriority(pid); 1429 } 1430 setInjectedAccessibility(false); 1431 hidePopupDialog(); 1432 mZoomControlsDelegate.dismissZoomPicker(); 1433 } 1434 1435 /** 1436 * @see View#onVisibilityChanged(android.view.View, int) 1437 */ 1438 public void onVisibilityChanged(View changedView, int visibility) { 1439 if (visibility != View.VISIBLE) { 1440 mZoomControlsDelegate.dismissZoomPicker(); 1441 } 1442 } 1443 1444 /** 1445 * @see View#onCreateInputConnection(EditorInfo) 1446 */ 1447 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 1448 if (!mImeAdapter.hasTextInputType()) { 1449 // Although onCheckIsTextEditor will return false in this case, the EditorInfo 1450 // is still used by the InputMethodService. Need to make sure the IME doesn't 1451 // enter fullscreen mode. 1452 outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN; 1453 } 1454 mInputConnection = 1455 mAdapterInputConnectionFactory.get(mContainerView, mImeAdapter, outAttrs); 1456 return mInputConnection; 1457 } 1458 1459 public Editable getEditableForTest() { 1460 return mInputConnection.getEditable(); 1461 } 1462 1463 /** 1464 * @see View#onCheckIsTextEditor() 1465 */ 1466 public boolean onCheckIsTextEditor() { 1467 return mImeAdapter.hasTextInputType(); 1468 } 1469 1470 /** 1471 * @see View#onConfigurationChanged(Configuration) 1472 */ 1473 @SuppressWarnings("javadoc") 1474 public void onConfigurationChanged(Configuration newConfig) { 1475 TraceEvent.begin(); 1476 1477 if (newConfig.keyboard != Configuration.KEYBOARD_NOKEYS) { 1478 mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore), 1479 ImeAdapter.getTextInputTypeNone(), 1480 AdapterInputConnection.INVALID_SELECTION, 1481 AdapterInputConnection.INVALID_SELECTION); 1482 InputMethodManager manager = (InputMethodManager) 1483 getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 1484 manager.restartInput(mContainerView); 1485 } 1486 mContainerViewInternals.super_onConfigurationChanged(newConfig); 1487 mNeedUpdateOrientationChanged = true; 1488 TraceEvent.end(); 1489 } 1490 1491 /** 1492 * @see View#onSizeChanged(int, int, int, int) 1493 */ 1494 @SuppressWarnings("javadoc") 1495 public void onSizeChanged(int wPix, int hPix, int owPix, int ohPix) { 1496 if (getViewportWidthPix() == wPix && getViewportHeightPix() == hPix) return; 1497 1498 mViewportWidthPix = wPix; 1499 mViewportHeightPix = hPix; 1500 if (mNativeContentViewCore != 0) { 1501 nativeWasResized(mNativeContentViewCore); 1502 } 1503 1504 updateAfterSizeChanged(); 1505 } 1506 1507 /** 1508 * Called when the underlying surface the compositor draws to changes size. 1509 * This may be larger than the viewport size. 1510 */ 1511 public void onPhysicalBackingSizeChanged(int wPix, int hPix) { 1512 if (mPhysicalBackingWidthPix == wPix && mPhysicalBackingHeightPix == hPix) return; 1513 1514 mPhysicalBackingWidthPix = wPix; 1515 mPhysicalBackingHeightPix = hPix; 1516 1517 if (mNativeContentViewCore != 0) { 1518 nativeWasResized(mNativeContentViewCore); 1519 } 1520 } 1521 1522 /** 1523 * Called when the amount the surface is overdrawing off the bottom has changed. 1524 * @param overdrawHeightPix The overdraw height. 1525 */ 1526 public void onOverdrawBottomHeightChanged(int overdrawHeightPix) { 1527 if (mOverdrawBottomHeightPix == overdrawHeightPix) return; 1528 1529 mOverdrawBottomHeightPix = overdrawHeightPix; 1530 1531 if (mNativeContentViewCore != 0) { 1532 nativeWasResized(mNativeContentViewCore); 1533 } 1534 } 1535 1536 private void updateAfterSizeChanged() { 1537 mPopupZoomer.hide(false); 1538 1539 // Execute a delayed form focus operation because the OSK was brought 1540 // up earlier. 1541 if (!mFocusPreOSKViewportRect.isEmpty()) { 1542 Rect rect = new Rect(); 1543 getContainerView().getWindowVisibleDisplayFrame(rect); 1544 if (!rect.equals(mFocusPreOSKViewportRect)) { 1545 scrollFocusedEditableNodeIntoView(); 1546 mFocusPreOSKViewportRect.setEmpty(); 1547 } 1548 } else if (mUnfocusOnNextSizeChanged) { 1549 undoScrollFocusedEditableNodeIntoViewIfNeeded(true); 1550 mUnfocusOnNextSizeChanged = false; 1551 } 1552 1553 if (mNeedUpdateOrientationChanged) { 1554 sendOrientationChangeEvent(); 1555 mNeedUpdateOrientationChanged = false; 1556 } 1557 } 1558 1559 private void scrollFocusedEditableNodeIntoView() { 1560 if (mNativeContentViewCore != 0) { 1561 Runnable scrollTask = new Runnable() { 1562 @Override 1563 public void run() { 1564 if (mNativeContentViewCore != 0) { 1565 nativeScrollFocusedEditableNodeIntoView(mNativeContentViewCore); 1566 } 1567 } 1568 }; 1569 1570 scrollTask.run(); 1571 1572 // The native side keeps track of whether the zoom and scroll actually occurred. It is 1573 // more efficient to do it this way and sometimes fire an unnecessary message rather 1574 // than synchronize with the renderer and always have an additional message. 1575 mScrolledAndZoomedFocusedEditableNode = true; 1576 } 1577 } 1578 1579 private void undoScrollFocusedEditableNodeIntoViewIfNeeded(boolean backButtonPressed) { 1580 // The only call to this function that matters is the first call after the 1581 // scrollFocusedEditableNodeIntoView function call. 1582 // If the first call to this function is a result of a back button press we want to undo the 1583 // preceding scroll. If the call is a result of some other action we don't want to perform 1584 // an undo. 1585 // All subsequent calls are ignored since only the scroll function sets 1586 // mScrolledAndZoomedFocusedEditableNode to true. 1587 if (mScrolledAndZoomedFocusedEditableNode && backButtonPressed && 1588 mNativeContentViewCore != 0) { 1589 Runnable scrollTask = new Runnable() { 1590 @Override 1591 public void run() { 1592 if (mNativeContentViewCore != 0) { 1593 nativeUndoScrollFocusedEditableNodeIntoView(mNativeContentViewCore); 1594 } 1595 } 1596 }; 1597 1598 scrollTask.run(); 1599 } 1600 mScrolledAndZoomedFocusedEditableNode = false; 1601 } 1602 1603 public void onFocusChanged(boolean gainFocus) { 1604 if (!gainFocus) getContentViewClient().onImeStateChangeRequested(false); 1605 if (mNativeContentViewCore != 0) nativeSetFocus(mNativeContentViewCore, gainFocus); 1606 } 1607 1608 /** 1609 * @see View#onKeyUp(int, KeyEvent) 1610 */ 1611 public boolean onKeyUp(int keyCode, KeyEvent event) { 1612 if (mPopupZoomer.isShowing() && keyCode == KeyEvent.KEYCODE_BACK) { 1613 mPopupZoomer.hide(true); 1614 return true; 1615 } 1616 return mContainerViewInternals.super_onKeyUp(keyCode, event); 1617 } 1618 1619 /** 1620 * @see View#dispatchKeyEventPreIme(KeyEvent) 1621 */ 1622 public boolean dispatchKeyEventPreIme(KeyEvent event) { 1623 try { 1624 TraceEvent.begin(); 1625 if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && mImeAdapter.isActive()) { 1626 mUnfocusOnNextSizeChanged = true; 1627 } else { 1628 undoScrollFocusedEditableNodeIntoViewIfNeeded(false); 1629 } 1630 return mContainerViewInternals.super_dispatchKeyEventPreIme(event); 1631 } finally { 1632 TraceEvent.end(); 1633 } 1634 } 1635 1636 /** 1637 * @see View#dispatchKeyEvent(KeyEvent) 1638 */ 1639 public boolean dispatchKeyEvent(KeyEvent event) { 1640 if (getContentViewClient().shouldOverrideKeyEvent(event)) { 1641 return mContainerViewInternals.super_dispatchKeyEvent(event); 1642 } 1643 1644 if (mImeAdapter.dispatchKeyEvent(event)) return true; 1645 1646 return mContainerViewInternals.super_dispatchKeyEvent(event); 1647 } 1648 1649 /** 1650 * @see View#onHoverEvent(MotionEvent) 1651 * Mouse move events are sent on hover enter, hover move and hover exit. 1652 * They are sent on hover exit because sometimes it acts as both a hover 1653 * move and hover exit. 1654 */ 1655 public boolean onHoverEvent(MotionEvent event) { 1656 TraceEvent.begin("onHoverEvent"); 1657 mContainerView.removeCallbacks(mFakeMouseMoveRunnable); 1658 if (mBrowserAccessibilityManager != null) { 1659 return mBrowserAccessibilityManager.onHoverEvent(event); 1660 } 1661 if (mNativeContentViewCore != 0) { 1662 nativeSendMouseMoveEvent(mNativeContentViewCore, event.getEventTime(), 1663 event.getX(), event.getY()); 1664 } 1665 TraceEvent.end("onHoverEvent"); 1666 return true; 1667 } 1668 1669 /** 1670 * @see View#onGenericMotionEvent(MotionEvent) 1671 */ 1672 public boolean onGenericMotionEvent(MotionEvent event) { 1673 if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { 1674 switch (event.getAction()) { 1675 case MotionEvent.ACTION_SCROLL: 1676 nativeSendMouseWheelEvent(mNativeContentViewCore, event.getEventTime(), 1677 event.getX(), event.getY(), 1678 event.getAxisValue(MotionEvent.AXIS_VSCROLL)); 1679 1680 mContainerView.removeCallbacks(mFakeMouseMoveRunnable); 1681 // Send a delayed onMouseMove event so that we end 1682 // up hovering over the right position after the scroll. 1683 final MotionEvent eventFakeMouseMove = MotionEvent.obtain(event); 1684 mFakeMouseMoveRunnable = new Runnable() { 1685 @Override 1686 public void run() { 1687 onHoverEvent(eventFakeMouseMove); 1688 } 1689 }; 1690 mContainerView.postDelayed(mFakeMouseMoveRunnable, 250); 1691 return true; 1692 } 1693 } 1694 return mContainerViewInternals.super_onGenericMotionEvent(event); 1695 } 1696 1697 /** 1698 * @see View#scrollBy(int, int) 1699 * Currently the ContentView scrolling happens in the native side. In 1700 * the Java view system, it is always pinned at (0, 0). scrollBy() and scrollTo() 1701 * are overridden, so that View's mScrollX and mScrollY will be unchanged at 1702 * (0, 0). This is critical for drawing ContentView correctly. 1703 */ 1704 public void scrollBy(int xPix, int yPix) { 1705 if (mNativeContentViewCore != 0) { 1706 nativeScrollBy(mNativeContentViewCore, 1707 System.currentTimeMillis(), 0, 0, xPix, yPix, false); 1708 } 1709 } 1710 1711 /** 1712 * @see View#scrollTo(int, int) 1713 */ 1714 public void scrollTo(int xPix, int yPix) { 1715 if (mNativeContentViewCore == 0) return; 1716 final float xCurrentPix = mRenderCoordinates.getScrollXPix(); 1717 final float yCurrentPix = mRenderCoordinates.getScrollYPix(); 1718 final float dxPix = xPix - xCurrentPix; 1719 final float dyPix = yPix - yCurrentPix; 1720 if (dxPix != 0 || dyPix != 0) { 1721 long time = System.currentTimeMillis(); 1722 nativeScrollBegin(mNativeContentViewCore, time, xCurrentPix, yCurrentPix); 1723 nativeScrollBy(mNativeContentViewCore, 1724 time, xCurrentPix, yCurrentPix, dxPix, dyPix, false); 1725 nativeScrollEnd(mNativeContentViewCore, time); 1726 } 1727 } 1728 1729 // NOTE: this can go away once ContentView.getScrollX() reports correct values. 1730 // see: b/6029133 1731 public int getNativeScrollXForTest() { 1732 return mRenderCoordinates.getScrollXPixInt(); 1733 } 1734 1735 // NOTE: this can go away once ContentView.getScrollY() reports correct values. 1736 // see: b/6029133 1737 public int getNativeScrollYForTest() { 1738 return mRenderCoordinates.getScrollYPixInt(); 1739 } 1740 1741 /** 1742 * @see View#computeHorizontalScrollExtent() 1743 */ 1744 @SuppressWarnings("javadoc") 1745 public int computeHorizontalScrollExtent() { 1746 return mRenderCoordinates.getLastFrameViewportWidthPixInt(); 1747 } 1748 1749 /** 1750 * @see View#computeHorizontalScrollOffset() 1751 */ 1752 @SuppressWarnings("javadoc") 1753 public int computeHorizontalScrollOffset() { 1754 return mRenderCoordinates.getScrollXPixInt(); 1755 } 1756 1757 /** 1758 * @see View#computeHorizontalScrollRange() 1759 */ 1760 @SuppressWarnings("javadoc") 1761 public int computeHorizontalScrollRange() { 1762 return mRenderCoordinates.getContentWidthPixInt(); 1763 } 1764 1765 /** 1766 * @see View#computeVerticalScrollExtent() 1767 */ 1768 @SuppressWarnings("javadoc") 1769 public int computeVerticalScrollExtent() { 1770 return mRenderCoordinates.getLastFrameViewportHeightPixInt(); 1771 } 1772 1773 /** 1774 * @see View#computeVerticalScrollOffset() 1775 */ 1776 @SuppressWarnings("javadoc") 1777 public int computeVerticalScrollOffset() { 1778 return mRenderCoordinates.getScrollYPixInt(); 1779 } 1780 1781 /** 1782 * @see View#computeVerticalScrollRange() 1783 */ 1784 @SuppressWarnings("javadoc") 1785 public int computeVerticalScrollRange() { 1786 return mRenderCoordinates.getContentHeightPixInt(); 1787 } 1788 1789 // End FrameLayout overrides. 1790 1791 /** 1792 * @see View#awakenScrollBars(int, boolean) 1793 */ 1794 @SuppressWarnings("javadoc") 1795 public boolean awakenScrollBars(int startDelay, boolean invalidate) { 1796 // For the default implementation of ContentView which draws the scrollBars on the native 1797 // side, calling this function may get us into a bad state where we keep drawing the 1798 // scrollBars, so disable it by always returning false. 1799 if (mContainerView.getScrollBarStyle() == View.SCROLLBARS_INSIDE_OVERLAY) { 1800 return false; 1801 } else { 1802 return mContainerViewInternals.super_awakenScrollBars(startDelay, invalidate); 1803 } 1804 } 1805 1806 @SuppressWarnings("unused") 1807 @CalledByNative 1808 private void onTabCrash() { 1809 getContentViewClient().onTabCrash(); 1810 } 1811 1812 private void handleTapOrPress( 1813 long timeMs, float xPix, float yPix, int isLongPressOrTap, boolean showPress) { 1814 if (!mContainerView.isFocused()) mContainerView.requestFocus(); 1815 1816 if (!mPopupZoomer.isShowing()) mPopupZoomer.setLastTouch(xPix, yPix); 1817 1818 if (isLongPressOrTap == IS_LONG_PRESS) { 1819 getInsertionHandleController().allowAutomaticShowing(); 1820 getSelectionHandleController().allowAutomaticShowing(); 1821 if (mNativeContentViewCore != 0) { 1822 nativeLongPress(mNativeContentViewCore, timeMs, xPix, yPix, false); 1823 } 1824 } else if (isLongPressOrTap == IS_LONG_TAP) { 1825 getInsertionHandleController().allowAutomaticShowing(); 1826 getSelectionHandleController().allowAutomaticShowing(); 1827 if (mNativeContentViewCore != 0) { 1828 nativeLongTap(mNativeContentViewCore, timeMs, xPix, yPix, false); 1829 } 1830 } else { 1831 if (!showPress && mNativeContentViewCore != 0) { 1832 nativeShowPressState(mNativeContentViewCore, timeMs, xPix, yPix); 1833 } 1834 if (mSelectionEditable) getInsertionHandleController().allowAutomaticShowing(); 1835 if (mNativeContentViewCore != 0) { 1836 nativeSingleTap(mNativeContentViewCore, timeMs, xPix, yPix, false); 1837 } 1838 } 1839 } 1840 1841 public void setZoomControlsDelegate(ZoomControlsDelegate zoomControlsDelegate) { 1842 mZoomControlsDelegate = zoomControlsDelegate; 1843 } 1844 1845 public void updateMultiTouchZoomSupport(boolean supportsMultiTouchZoom) { 1846 mZoomManager.updateMultiTouchSupport(supportsMultiTouchZoom); 1847 } 1848 1849 public void selectPopupMenuItems(int[] indices) { 1850 if (mNativeContentViewCore != 0) { 1851 nativeSelectPopupMenuItems(mNativeContentViewCore, indices); 1852 } 1853 } 1854 1855 /** 1856 * Get the screen orientation from the OS and push it to WebKit. 1857 * 1858 * TODO(husky): Add a hook for mock orientations. 1859 * 1860 * TODO(husky): Currently each new tab starts with an orientation of 0 until you actually 1861 * rotate the device. This is wrong if you actually started in landscape mode. To fix this, we 1862 * need to push the correct orientation, but only after WebKit's Frame object has been fully 1863 * initialized. Need to find a good time to do that. onPageFinished() would probably work but 1864 * it isn't implemented yet. 1865 */ 1866 private void sendOrientationChangeEvent() { 1867 if (mNativeContentViewCore == 0) return; 1868 1869 WindowManager windowManager = 1870 (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); 1871 switch (windowManager.getDefaultDisplay().getRotation()) { 1872 case Surface.ROTATION_90: 1873 nativeSendOrientationChangeEvent(mNativeContentViewCore, 90); 1874 break; 1875 case Surface.ROTATION_180: 1876 nativeSendOrientationChangeEvent(mNativeContentViewCore, 180); 1877 break; 1878 case Surface.ROTATION_270: 1879 nativeSendOrientationChangeEvent(mNativeContentViewCore, -90); 1880 break; 1881 case Surface.ROTATION_0: 1882 nativeSendOrientationChangeEvent(mNativeContentViewCore, 0); 1883 break; 1884 default: 1885 Log.w(TAG, "Unknown rotation!"); 1886 break; 1887 } 1888 } 1889 1890 /** 1891 * Register the delegate to be used when content can not be handled by 1892 * the rendering engine, and should be downloaded instead. This will replace 1893 * the current delegate, if any. 1894 * @param delegate An implementation of ContentViewDownloadDelegate. 1895 */ 1896 public void setDownloadDelegate(ContentViewDownloadDelegate delegate) { 1897 mDownloadDelegate = delegate; 1898 } 1899 1900 // Called by DownloadController. 1901 ContentViewDownloadDelegate getDownloadDelegate() { 1902 return mDownloadDelegate; 1903 } 1904 1905 private SelectionHandleController getSelectionHandleController() { 1906 if (mSelectionHandleController == null) { 1907 mSelectionHandleController = new SelectionHandleController(getContainerView()) { 1908 @Override 1909 public void selectBetweenCoordinates(int x1, int y1, int x2, int y2) { 1910 if (mNativeContentViewCore != 0 && !(x1 == x2 && y1 == y2)) { 1911 nativeSelectBetweenCoordinates(mNativeContentViewCore, 1912 x1, y1 - mRenderCoordinates.getContentOffsetYPix(), 1913 x2, y2 - mRenderCoordinates.getContentOffsetYPix()); 1914 } 1915 } 1916 1917 @Override 1918 public void showHandles(int startDir, int endDir) { 1919 super.showHandles(startDir, endDir); 1920 showSelectActionBar(); 1921 } 1922 1923 }; 1924 1925 mSelectionHandleController.hideAndDisallowAutomaticShowing(); 1926 } 1927 1928 return mSelectionHandleController; 1929 } 1930 1931 private InsertionHandleController getInsertionHandleController() { 1932 if (mInsertionHandleController == null) { 1933 mInsertionHandleController = new InsertionHandleController(getContainerView()) { 1934 private static final int AVERAGE_LINE_HEIGHT = 14; 1935 1936 @Override 1937 public void setCursorPosition(int x, int y) { 1938 if (mNativeContentViewCore != 0) { 1939 nativeMoveCaret(mNativeContentViewCore, 1940 x, y - mRenderCoordinates.getContentOffsetYPix()); 1941 } 1942 } 1943 1944 @Override 1945 public void paste() { 1946 mImeAdapter.paste(); 1947 hideHandles(); 1948 } 1949 1950 @Override 1951 public int getLineHeight() { 1952 return (int) Math.ceil( 1953 mRenderCoordinates.fromLocalCssToPix(AVERAGE_LINE_HEIGHT)); 1954 } 1955 1956 @Override 1957 public void showHandle() { 1958 super.showHandle(); 1959 } 1960 }; 1961 1962 mInsertionHandleController.hideAndDisallowAutomaticShowing(); 1963 } 1964 1965 return mInsertionHandleController; 1966 } 1967 1968 public InsertionHandleController getInsertionHandleControllerForTest() { 1969 return mInsertionHandleController; 1970 } 1971 1972 private void updateHandleScreenPositions() { 1973 if (isSelectionHandleShowing()) { 1974 mSelectionHandleController.setStartHandlePosition( 1975 mStartHandlePoint.getXPix(), mStartHandlePoint.getYPix()); 1976 mSelectionHandleController.setEndHandlePosition( 1977 mEndHandlePoint.getXPix(), mEndHandlePoint.getYPix()); 1978 } 1979 1980 if (isInsertionHandleShowing()) { 1981 mInsertionHandleController.setHandlePosition( 1982 mInsertionHandlePoint.getXPix(), mInsertionHandlePoint.getYPix()); 1983 } 1984 } 1985 1986 private void hideHandles() { 1987 if (mSelectionHandleController != null) { 1988 mSelectionHandleController.hideAndDisallowAutomaticShowing(); 1989 } 1990 if (mInsertionHandleController != null) { 1991 mInsertionHandleController.hideAndDisallowAutomaticShowing(); 1992 } 1993 } 1994 1995 private void showSelectActionBar() { 1996 if (mActionMode != null) { 1997 mActionMode.invalidate(); 1998 return; 1999 } 2000 2001 // Start a new action mode with a SelectActionModeCallback. 2002 SelectActionModeCallback.ActionHandler actionHandler = 2003 new SelectActionModeCallback.ActionHandler() { 2004 @Override 2005 public boolean selectAll() { 2006 return mImeAdapter.selectAll(); 2007 } 2008 2009 @Override 2010 public boolean cut() { 2011 return mImeAdapter.cut(); 2012 } 2013 2014 @Override 2015 public boolean copy() { 2016 return mImeAdapter.copy(); 2017 } 2018 2019 @Override 2020 public boolean paste() { 2021 return mImeAdapter.paste(); 2022 } 2023 2024 @Override 2025 public boolean isSelectionEditable() { 2026 return mSelectionEditable; 2027 } 2028 2029 @Override 2030 public String getSelectedText() { 2031 return ContentViewCore.this.getSelectedText(); 2032 } 2033 2034 @Override 2035 public void onDestroyActionMode() { 2036 mActionMode = null; 2037 if (mUnselectAllOnActionModeDismiss) mImeAdapter.unselect(); 2038 getContentViewClient().onContextualActionBarHidden(); 2039 } 2040 }; 2041 mActionMode = null; 2042 // On ICS, startActionMode throws an NPE when getParent() is null. 2043 if (mContainerView.getParent() != null) { 2044 mActionMode = mContainerView.startActionMode( 2045 getContentViewClient().getSelectActionModeCallback(getContext(), actionHandler, 2046 nativeIsIncognito(mNativeContentViewCore))); 2047 } 2048 mUnselectAllOnActionModeDismiss = true; 2049 if (mActionMode == null) { 2050 // There is no ActionMode, so remove the selection. 2051 mImeAdapter.unselect(); 2052 } else { 2053 getContentViewClient().onContextualActionBarShown(); 2054 } 2055 } 2056 2057 public boolean getUseDesktopUserAgent() { 2058 if (mNativeContentViewCore != 0) { 2059 return nativeGetUseDesktopUserAgent(mNativeContentViewCore); 2060 } 2061 return false; 2062 } 2063 2064 /** 2065 * Set whether or not we're using a desktop user agent for the currently loaded page. 2066 * @param override If true, use a desktop user agent. Use a mobile one otherwise. 2067 * @param reloadOnChange Reload the page if the UA has changed. 2068 */ 2069 public void setUseDesktopUserAgent(boolean override, boolean reloadOnChange) { 2070 if (mNativeContentViewCore != 0) { 2071 nativeSetUseDesktopUserAgent(mNativeContentViewCore, override, reloadOnChange); 2072 } 2073 } 2074 2075 public void clearSslPreferences() { 2076 nativeClearSslPreferences(mNativeContentViewCore); 2077 } 2078 2079 /** 2080 * @return Whether the native ContentView has crashed. 2081 */ 2082 public boolean isCrashed() { 2083 if (mNativeContentViewCore == 0) return false; 2084 return nativeCrashed(mNativeContentViewCore); 2085 } 2086 2087 private boolean isSelectionHandleShowing() { 2088 return mSelectionHandleController != null && mSelectionHandleController.isShowing(); 2089 } 2090 2091 private boolean isInsertionHandleShowing() { 2092 return mInsertionHandleController != null && mInsertionHandleController.isShowing(); 2093 } 2094 2095 private void updateTextHandlesForGesture(int type) { 2096 switch(type) { 2097 case ContentViewGestureHandler.GESTURE_DOUBLE_TAP: 2098 case ContentViewGestureHandler.GESTURE_SCROLL_START: 2099 case ContentViewGestureHandler.GESTURE_FLING_START: 2100 case ContentViewGestureHandler.GESTURE_PINCH_BEGIN: 2101 temporarilyHideTextHandles(); 2102 break; 2103 2104 default: 2105 break; 2106 } 2107 } 2108 2109 // Makes the insertion/selection handles invisible. They will fade back in shortly after the 2110 // last call to scheduleTextHandleFadeIn (or temporarilyHideTextHandles). 2111 private void temporarilyHideTextHandles() { 2112 if (isSelectionHandleShowing()) { 2113 mSelectionHandleController.setHandleVisibility(HandleView.INVISIBLE); 2114 } 2115 if (isInsertionHandleShowing()) { 2116 mInsertionHandleController.setHandleVisibility(HandleView.INVISIBLE); 2117 } 2118 scheduleTextHandleFadeIn(); 2119 } 2120 2121 // Cancels any pending fade in and schedules a new one. 2122 private void scheduleTextHandleFadeIn() { 2123 if (!isInsertionHandleShowing() && !isSelectionHandleShowing()) return; 2124 2125 if (mDeferredHandleFadeInRunnable == null) { 2126 mDeferredHandleFadeInRunnable = new Runnable() { 2127 @Override 2128 public void run() { 2129 if (mContentViewGestureHandler.isNativeScrolling() || 2130 mContentViewGestureHandler.isNativePinching()) { 2131 // Delay fade in until no longer scrolling or pinching. 2132 scheduleTextHandleFadeIn(); 2133 } else { 2134 if (isSelectionHandleShowing()) { 2135 mSelectionHandleController.beginHandleFadeIn(); 2136 } 2137 if (isInsertionHandleShowing()) { 2138 mInsertionHandleController.beginHandleFadeIn(); 2139 } 2140 } 2141 } 2142 }; 2143 } 2144 2145 mContainerView.removeCallbacks(mDeferredHandleFadeInRunnable); 2146 mContainerView.postDelayed(mDeferredHandleFadeInRunnable, TEXT_HANDLE_FADE_IN_DELAY); 2147 } 2148 2149 /** 2150 * Shows the IME if the focused widget could accept text input. 2151 */ 2152 public void showImeIfNeeded() { 2153 if (mNativeContentViewCore != 0) nativeShowImeIfNeeded(mNativeContentViewCore); 2154 } 2155 2156 public void setUpdateFrameInfoListener(UpdateFrameInfoListener updateFrameInfoListener) { 2157 mUpdateFrameInfoListener = updateFrameInfoListener; 2158 } 2159 2160 @SuppressWarnings("unused") 2161 @CalledByNative 2162 private void updateFrameInfo( 2163 float scrollOffsetX, float scrollOffsetY, 2164 float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor, 2165 float contentWidth, float contentHeight, 2166 float viewportWidth, float viewportHeight, 2167 float controlsOffsetYCss, float contentOffsetYCss, 2168 float overdrawBottomHeightCss) { 2169 TraceEvent.instant("ContentViewCore:updateFrameInfo"); 2170 // Adjust contentWidth/Height to be always at least as big as 2171 // the actual viewport (as set by onSizeChanged). 2172 contentWidth = Math.max(contentWidth, 2173 mRenderCoordinates.fromPixToLocalCss(mViewportWidthPix)); 2174 contentHeight = Math.max(contentHeight, 2175 mRenderCoordinates.fromPixToLocalCss(mViewportHeightPix)); 2176 2177 final float contentOffsetYPix = mRenderCoordinates.fromDipToPix(contentOffsetYCss); 2178 2179 final boolean contentSizeChanged = 2180 contentWidth != mRenderCoordinates.getContentWidthCss() 2181 || contentHeight != mRenderCoordinates.getContentHeightCss(); 2182 final boolean scaleLimitsChanged = 2183 minPageScaleFactor != mRenderCoordinates.getMinPageScaleFactor() 2184 || maxPageScaleFactor != mRenderCoordinates.getMaxPageScaleFactor(); 2185 final boolean pageScaleChanged = 2186 pageScaleFactor != mRenderCoordinates.getPageScaleFactor(); 2187 final boolean scrollChanged = 2188 pageScaleChanged 2189 || scrollOffsetX != mRenderCoordinates.getScrollX() 2190 || scrollOffsetY != mRenderCoordinates.getScrollY(); 2191 final boolean contentOffsetChanged = 2192 contentOffsetYPix != mRenderCoordinates.getContentOffsetYPix(); 2193 2194 final boolean needHidePopupZoomer = contentSizeChanged || scrollChanged; 2195 final boolean needUpdateZoomControls = scaleLimitsChanged || scrollChanged; 2196 final boolean needTemporarilyHideHandles = scrollChanged; 2197 2198 if (needHidePopupZoomer) mPopupZoomer.hide(true); 2199 2200 if (pageScaleChanged) { 2201 // This function should be called back from native as soon 2202 // as the scroll is applied to the backbuffer. We should only 2203 // update mNativeScrollX/Y here for consistency. 2204 getContentViewClient().onScaleChanged( 2205 mRenderCoordinates.getPageScaleFactor(), pageScaleFactor); 2206 } 2207 2208 mRenderCoordinates.updateFrameInfo( 2209 scrollOffsetX, scrollOffsetY, 2210 contentWidth, contentHeight, 2211 viewportWidth, viewportHeight, 2212 pageScaleFactor, minPageScaleFactor, maxPageScaleFactor, 2213 contentOffsetYPix); 2214 2215 if ((contentSizeChanged || pageScaleChanged) && mUpdateFrameInfoListener != null) { 2216 mUpdateFrameInfoListener.onFrameInfoUpdated( 2217 contentWidth, contentHeight, pageScaleFactor); 2218 } 2219 2220 if (needTemporarilyHideHandles) temporarilyHideTextHandles(); 2221 if (needUpdateZoomControls) mZoomControlsDelegate.updateZoomControls(); 2222 if (contentOffsetChanged) updateHandleScreenPositions(); 2223 2224 // Update offsets for fullscreen. 2225 final float deviceScale = mRenderCoordinates.getDeviceScaleFactor(); 2226 final float controlsOffsetPix = controlsOffsetYCss * deviceScale; 2227 final float overdrawBottomHeightPix = overdrawBottomHeightCss * deviceScale; 2228 getContentViewClient().onOffsetsForFullscreenChanged( 2229 controlsOffsetPix, contentOffsetYPix, overdrawBottomHeightPix); 2230 2231 mPendingRendererFrame = true; 2232 if (mBrowserAccessibilityManager != null) { 2233 mBrowserAccessibilityManager.notifyFrameInfoInitialized(); 2234 } 2235 } 2236 2237 @SuppressWarnings("unused") 2238 @CalledByNative 2239 private void updateImeAdapter(int nativeImeAdapterAndroid, int textInputType, 2240 String text, int selectionStart, int selectionEnd, 2241 int compositionStart, int compositionEnd, boolean showImeIfNeeded) { 2242 TraceEvent.begin(); 2243 mSelectionEditable = (textInputType != ImeAdapter.getTextInputTypeNone()); 2244 2245 if (mActionMode != null) mActionMode.invalidate(); 2246 2247 mImeAdapter.attachAndShowIfNeeded(nativeImeAdapterAndroid, textInputType, 2248 selectionStart, selectionEnd, showImeIfNeeded); 2249 2250 if (mInputConnection != null) { 2251 mInputConnection.setEditableText(text, selectionStart, selectionEnd, 2252 compositionStart, compositionEnd); 2253 } 2254 TraceEvent.end(); 2255 } 2256 2257 @SuppressWarnings("unused") 2258 @CalledByNative 2259 private void processImeBatchStateAck(boolean isBegin) { 2260 if (mInputConnection == null) return; 2261 mInputConnection.setIgnoreTextInputStateUpdates(isBegin); 2262 } 2263 2264 @SuppressWarnings("unused") 2265 @CalledByNative 2266 private void setTitle(String title) { 2267 getContentViewClient().onUpdateTitle(title); 2268 } 2269 2270 /** 2271 * Called (from native) when the <select> popup needs to be shown. 2272 * @param items Items to show. 2273 * @param enabled POPUP_ITEM_TYPEs for items. 2274 * @param multiple Whether the popup menu should support multi-select. 2275 * @param selectedIndices Indices of selected items. 2276 */ 2277 @SuppressWarnings("unused") 2278 @CalledByNative 2279 private void showSelectPopup(String[] items, int[] enabled, boolean multiple, 2280 int[] selectedIndices) { 2281 SelectPopupDialog.show(this, items, enabled, multiple, selectedIndices); 2282 } 2283 2284 @SuppressWarnings("unused") 2285 @CalledByNative 2286 private void showDisambiguationPopup(Rect targetRect, Bitmap zoomedBitmap) { 2287 mPopupZoomer.setBitmap(zoomedBitmap); 2288 mPopupZoomer.show(targetRect); 2289 } 2290 2291 @SuppressWarnings("unused") 2292 @CalledByNative 2293 private SmoothScroller createSmoothScroller(boolean scrollDown, int mouseEventX, 2294 int mouseEventY) { 2295 return new SmoothScroller(this, scrollDown, mouseEventX, mouseEventY); 2296 } 2297 2298 @SuppressWarnings("unused") 2299 @CalledByNative 2300 private void onSelectionChanged(String text) { 2301 mLastSelectedText = text; 2302 } 2303 2304 @SuppressWarnings("unused") 2305 @CalledByNative 2306 private void onSelectionBoundsChanged(Rect anchorRectDip, int anchorDir, Rect focusRectDip, 2307 int focusDir, boolean isAnchorFirst) { 2308 // All coordinates are in DIP. 2309 int x1 = anchorRectDip.left; 2310 int y1 = anchorRectDip.bottom; 2311 int x2 = focusRectDip.left; 2312 int y2 = focusRectDip.bottom; 2313 2314 if (x1 != x2 || y1 != y2 || 2315 (mSelectionHandleController != null && mSelectionHandleController.isDragging())) { 2316 if (mInsertionHandleController != null) { 2317 mInsertionHandleController.hide(); 2318 } 2319 if (isAnchorFirst) { 2320 mStartHandlePoint.setLocalDip(x1, y1); 2321 mEndHandlePoint.setLocalDip(x2, y2); 2322 } else { 2323 mStartHandlePoint.setLocalDip(x2, y2); 2324 mEndHandlePoint.setLocalDip(x1, y1); 2325 } 2326 2327 getSelectionHandleController().onSelectionChanged(anchorDir, focusDir); 2328 updateHandleScreenPositions(); 2329 mHasSelection = true; 2330 } else { 2331 mUnselectAllOnActionModeDismiss = false; 2332 hideSelectActionBar(); 2333 if (x1 != 0 && y1 != 0 && mSelectionEditable) { 2334 // Selection is a caret, and a text field is focused. 2335 if (mSelectionHandleController != null) { 2336 mSelectionHandleController.hide(); 2337 } 2338 mInsertionHandlePoint.setLocalDip(x1, y1); 2339 2340 getInsertionHandleController().onCursorPositionChanged(); 2341 updateHandleScreenPositions(); 2342 InputMethodManager manager = (InputMethodManager) 2343 getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 2344 if (manager.isWatchingCursor(mContainerView)) { 2345 final int xPix = (int) mInsertionHandlePoint.getXPix(); 2346 final int yPix = (int) mInsertionHandlePoint.getYPix(); 2347 manager.updateCursor(mContainerView, xPix, yPix, xPix, yPix); 2348 } 2349 } else { 2350 // Deselection 2351 if (mSelectionHandleController != null) { 2352 mSelectionHandleController.hideAndDisallowAutomaticShowing(); 2353 } 2354 if (mInsertionHandleController != null) { 2355 mInsertionHandleController.hideAndDisallowAutomaticShowing(); 2356 } 2357 } 2358 mHasSelection = false; 2359 } 2360 } 2361 2362 @SuppressWarnings("unused") 2363 @CalledByNative 2364 private static void onEvaluateJavaScriptResult( 2365 String jsonResult, JavaScriptCallback callback) { 2366 callback.handleJavaScriptResult(jsonResult); 2367 } 2368 2369 @SuppressWarnings("unused") 2370 @CalledByNative 2371 private void showPastePopup(int xDip, int yDip) { 2372 mInsertionHandlePoint.setLocalDip(xDip, yDip); 2373 getInsertionHandleController().showHandle(); 2374 updateHandleScreenPositions(); 2375 getInsertionHandleController().showHandleWithPastePopup(); 2376 } 2377 2378 @SuppressWarnings("unused") 2379 @CalledByNative 2380 private void onRenderProcessSwap(int oldPid, int newPid) { 2381 if (mAttachedToWindow && oldPid != newPid) { 2382 ChildProcessLauncher.unbindAsHighPriority(oldPid); 2383 ChildProcessLauncher.bindAsHighPriority(newPid); 2384 } 2385 2386 // We want to remove the initial binding even if the ContentView is not attached, so that 2387 // renderers for ContentViews loading in background do not retain the high priority. 2388 ChildProcessLauncher.removeInitialBinding(newPid); 2389 } 2390 2391 @SuppressWarnings("unused") 2392 @CalledByNative 2393 private void onWebContentsConnected() { 2394 if (mImeAdapter != null && 2395 !mImeAdapter.isNativeImeAdapterAttached() && mNativeContentViewCore != 0) { 2396 mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore)); 2397 } 2398 } 2399 2400 @SuppressWarnings("unused") 2401 @CalledByNative 2402 private void onWebContentsSwapped() { 2403 if (mImeAdapter != null && mNativeContentViewCore != 0) { 2404 mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore)); 2405 } 2406 } 2407 2408 /** 2409 * @return Whether a reload happens when this ContentView is activated. 2410 */ 2411 public boolean needsReload() { 2412 return mNativeContentViewCore != 0 && nativeNeedsReload(mNativeContentViewCore); 2413 } 2414 2415 /** 2416 * @see View#hasFocus() 2417 */ 2418 @CalledByNative 2419 public boolean hasFocus() { 2420 return mContainerView.hasFocus(); 2421 } 2422 2423 /** 2424 * Checks whether the ContentViewCore can be zoomed in. 2425 * 2426 * @return True if the ContentViewCore can be zoomed in. 2427 */ 2428 // This method uses the term 'zoom' for legacy reasons, but relates 2429 // to what chrome calls the 'page scale factor'. 2430 public boolean canZoomIn() { 2431 final float zoomInExtent = mRenderCoordinates.getMaxPageScaleFactor() 2432 - mRenderCoordinates.getPageScaleFactor(); 2433 return zoomInExtent > ZOOM_CONTROLS_EPSILON; 2434 } 2435 2436 /** 2437 * Checks whether the ContentViewCore can be zoomed out. 2438 * 2439 * @return True if the ContentViewCore can be zoomed out. 2440 */ 2441 // This method uses the term 'zoom' for legacy reasons, but relates 2442 // to what chrome calls the 'page scale factor'. 2443 public boolean canZoomOut() { 2444 final float zoomOutExtent = mRenderCoordinates.getPageScaleFactor() 2445 - mRenderCoordinates.getMinPageScaleFactor(); 2446 return zoomOutExtent > ZOOM_CONTROLS_EPSILON; 2447 } 2448 2449 /** 2450 * Zooms in the ContentViewCore by 25% (or less if that would result in 2451 * zooming in more than possible). 2452 * 2453 * @return True if there was a zoom change, false otherwise. 2454 */ 2455 // This method uses the term 'zoom' for legacy reasons, but relates 2456 // to what chrome calls the 'page scale factor'. 2457 public boolean zoomIn() { 2458 if (!canZoomIn()) { 2459 return false; 2460 } 2461 return zoomByDelta(1.25f); 2462 } 2463 2464 /** 2465 * Zooms out the ContentViewCore by 20% (or less if that would result in 2466 * zooming out more than possible). 2467 * 2468 * @return True if there was a zoom change, false otherwise. 2469 */ 2470 // This method uses the term 'zoom' for legacy reasons, but relates 2471 // to what chrome calls the 'page scale factor'. 2472 public boolean zoomOut() { 2473 if (!canZoomOut()) { 2474 return false; 2475 } 2476 return zoomByDelta(0.8f); 2477 } 2478 2479 /** 2480 * Resets the zoom factor of the ContentViewCore. 2481 * 2482 * @return True if there was a zoom change, false otherwise. 2483 */ 2484 // This method uses the term 'zoom' for legacy reasons, but relates 2485 // to what chrome calls the 'page scale factor'. 2486 public boolean zoomReset() { 2487 // The page scale factor is initialized to mNativeMinimumScale when 2488 // the page finishes loading. Thus sets it back to mNativeMinimumScale. 2489 if (!canZoomOut()) return false; 2490 return zoomByDelta( 2491 mRenderCoordinates.getMinPageScaleFactor() 2492 / mRenderCoordinates.getPageScaleFactor()); 2493 } 2494 2495 private boolean zoomByDelta(float delta) { 2496 if (mNativeContentViewCore == 0) { 2497 return false; 2498 } 2499 2500 long timeMs = System.currentTimeMillis(); 2501 int xPix = getViewportWidthPix() / 2; 2502 int yPix = getViewportHeightPix() / 2; 2503 2504 getContentViewGestureHandler().pinchBegin(timeMs, xPix, yPix); 2505 getContentViewGestureHandler().pinchBy(timeMs, xPix, yPix, delta); 2506 getContentViewGestureHandler().pinchEnd(timeMs); 2507 2508 return true; 2509 } 2510 2511 /** 2512 * Invokes the graphical zoom picker widget for this ContentView. 2513 */ 2514 @Override 2515 public void invokeZoomPicker() { 2516 mZoomControlsDelegate.invokeZoomPicker(); 2517 } 2518 2519 /** 2520 * This will mimic {@link #addPossiblyUnsafeJavascriptInterface(Object, String, Class)} 2521 * and automatically pass in {@link JavascriptInterface} as the required annotation. 2522 * 2523 * @param object The Java object to inject into the ContentViewCore's JavaScript context. Null 2524 * values are ignored. 2525 * @param name The name used to expose the instance in JavaScript. 2526 */ 2527 public void addJavascriptInterface(Object object, String name) { 2528 addPossiblyUnsafeJavascriptInterface(object, name, JavascriptInterface.class); 2529 } 2530 2531 /** 2532 * This method injects the supplied Java object into the ContentViewCore. 2533 * The object is injected into the JavaScript context of the main frame, 2534 * using the supplied name. This allows the Java object to be accessed from 2535 * JavaScript. Note that that injected objects will not appear in 2536 * JavaScript until the page is next (re)loaded. For example: 2537 * <pre> view.addJavascriptInterface(new Object(), "injectedObject"); 2538 * view.loadData("<!DOCTYPE html><title></title>", "text/html", null); 2539 * view.loadUrl("javascript:alert(injectedObject.toString())");</pre> 2540 * <p><strong>IMPORTANT:</strong> 2541 * <ul> 2542 * <li> addJavascriptInterface() can be used to allow JavaScript to control 2543 * the host application. This is a powerful feature, but also presents a 2544 * security risk. Use of this method in a ContentViewCore containing 2545 * untrusted content could allow an attacker to manipulate the host 2546 * application in unintended ways, executing Java code with the permissions 2547 * of the host application. Use extreme care when using this method in a 2548 * ContentViewCore which could contain untrusted content. Particular care 2549 * should be taken to avoid unintentional access to inherited methods, such 2550 * as {@link Object#getClass()}. To prevent access to inherited methods, 2551 * pass an annotation for {@code requiredAnnotation}. This will ensure 2552 * that only methods with {@code requiredAnnotation} are exposed to the 2553 * Javascript layer. {@code requiredAnnotation} will be passed to all 2554 * subsequently injected Java objects if any methods return an object. This 2555 * means the same restrictions (or lack thereof) will apply. Alternatively, 2556 * {@link #addJavascriptInterface(Object, String)} can be called, which 2557 * automatically uses the {@link JavascriptInterface} annotation. 2558 * <li> JavaScript interacts with Java objects on a private, background 2559 * thread of the ContentViewCore. Care is therefore required to maintain 2560 * thread safety.</li> 2561 * </ul></p> 2562 * 2563 * @param object The Java object to inject into the 2564 * ContentViewCore's JavaScript context. Null 2565 * values are ignored. 2566 * @param name The name used to expose the instance in 2567 * JavaScript. 2568 * @param requiredAnnotation Restrict exposed methods to ones with this 2569 * annotation. If {@code null} all methods are 2570 * exposed. 2571 * 2572 */ 2573 public void addPossiblyUnsafeJavascriptInterface(Object object, String name, 2574 Class<? extends Annotation> requiredAnnotation) { 2575 if (mNativeContentViewCore != 0 && object != null) { 2576 mJavaScriptInterfaces.put(name, object); 2577 nativeAddJavascriptInterface(mNativeContentViewCore, object, name, requiredAnnotation, 2578 mRetainedJavaScriptObjects); 2579 } 2580 } 2581 2582 /** 2583 * Removes a previously added JavaScript interface with the given name. 2584 * 2585 * @param name The name of the interface to remove. 2586 */ 2587 public void removeJavascriptInterface(String name) { 2588 mJavaScriptInterfaces.remove(name); 2589 if (mNativeContentViewCore != 0) { 2590 nativeRemoveJavascriptInterface(mNativeContentViewCore, name); 2591 } 2592 } 2593 2594 /** 2595 * Return the current scale of the ContentView. 2596 * @return The current page scale factor. 2597 */ 2598 public float getScale() { 2599 return mRenderCoordinates.getPageScaleFactor(); 2600 } 2601 2602 /** 2603 * If the view is ready to draw contents to the screen. In hardware mode, 2604 * the initialization of the surface texture may not occur until after the 2605 * view has been added to the layout. This method will return {@code true} 2606 * once the texture is actually ready. 2607 */ 2608 public boolean isReady() { 2609 return nativeIsRenderWidgetHostViewReady(mNativeContentViewCore); 2610 } 2611 2612 @CalledByNative 2613 private void startContentIntent(String contentUrl) { 2614 getContentViewClient().onStartContentIntent(getContext(), contentUrl); 2615 } 2616 2617 @Override 2618 public void onAccessibilityStateChanged(boolean enabled) { 2619 setAccessibilityState(enabled); 2620 } 2621 2622 /** 2623 * Determines whether or not this ContentViewCore can handle this accessibility action. 2624 * @param action The action to perform. 2625 * @return Whether or not this action is supported. 2626 */ 2627 public boolean supportsAccessibilityAction(int action) { 2628 return mAccessibilityInjector.supportsAccessibilityAction(action); 2629 } 2630 2631 /** 2632 * Attempts to perform an accessibility action on the web content. If the accessibility action 2633 * cannot be processed, it returns {@code null}, allowing the caller to know to call the 2634 * super {@link View#performAccessibilityAction(int, Bundle)} method and use that return value. 2635 * Otherwise the return value from this method should be used. 2636 * @param action The action to perform. 2637 * @param arguments Optional action arguments. 2638 * @return Whether the action was performed or {@code null} if the call should be delegated to 2639 * the super {@link View} class. 2640 */ 2641 public boolean performAccessibilityAction(int action, Bundle arguments) { 2642 if (mAccessibilityInjector.supportsAccessibilityAction(action)) { 2643 return mAccessibilityInjector.performAccessibilityAction(action, arguments); 2644 } 2645 2646 return false; 2647 } 2648 2649 /** 2650 * Set the BrowserAccessibilityManager, used for native accessibility 2651 * (not script injection). This is only set when system accessibility 2652 * has been enabled. 2653 * @param manager The new BrowserAccessibilityManager. 2654 */ 2655 public void setBrowserAccessibilityManager(BrowserAccessibilityManager manager) { 2656 mBrowserAccessibilityManager = manager; 2657 } 2658 2659 /** 2660 * Get the BrowserAccessibilityManager, used for native accessibility 2661 * (not script injection). This will return null when system accessibility 2662 * is not enabled. 2663 * @return This view's BrowserAccessibilityManager. 2664 */ 2665 public BrowserAccessibilityManager getBrowserAccessibilityManager() { 2666 return mBrowserAccessibilityManager; 2667 } 2668 2669 /** 2670 * If native accessibility (not script injection) is enabled, and if this is 2671 * running on JellyBean or later, returns an AccessibilityNodeProvider that 2672 * implements native accessibility for this view. Returns null otherwise. 2673 * @return The AccessibilityNodeProvider, if available, or null otherwise. 2674 */ 2675 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 2676 if (mBrowserAccessibilityManager != null) { 2677 return mBrowserAccessibilityManager.getAccessibilityNodeProvider(); 2678 } else { 2679 return null; 2680 } 2681 } 2682 2683 /** 2684 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 2685 */ 2686 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 2687 // Note: this is only used by the script-injecting accessibility code. 2688 mAccessibilityInjector.onInitializeAccessibilityNodeInfo(info); 2689 } 2690 2691 /** 2692 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 2693 */ 2694 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 2695 // Note: this is only used by the script-injecting accessibility code. 2696 event.setClassName(this.getClass().getName()); 2697 2698 // Identify where the top-left of the screen currently points to. 2699 event.setScrollX(mRenderCoordinates.getScrollXPixInt()); 2700 event.setScrollY(mRenderCoordinates.getScrollYPixInt()); 2701 2702 // The maximum scroll values are determined by taking the content dimensions and 2703 // subtracting off the actual dimensions of the ChromeView. 2704 int maxScrollXPix = Math.max(0, mRenderCoordinates.getMaxHorizontalScrollPixInt()); 2705 int maxScrollYPix = Math.max(0, mRenderCoordinates.getMaxVerticalScrollPixInt()); 2706 event.setScrollable(maxScrollXPix > 0 || maxScrollYPix > 0); 2707 2708 // Setting the maximum scroll values requires API level 15 or higher. 2709 final int SDK_VERSION_REQUIRED_TO_SET_SCROLL = 15; 2710 if (Build.VERSION.SDK_INT >= SDK_VERSION_REQUIRED_TO_SET_SCROLL) { 2711 event.setMaxScrollX(maxScrollXPix); 2712 event.setMaxScrollY(maxScrollYPix); 2713 } 2714 } 2715 2716 /** 2717 * Returns whether accessibility script injection is enabled on the device 2718 */ 2719 public boolean isDeviceAccessibilityScriptInjectionEnabled() { 2720 try { 2721 if (!mContentSettings.getJavaScriptEnabled()) { 2722 return false; 2723 } 2724 2725 int result = getContext().checkCallingOrSelfPermission( 2726 android.Manifest.permission.INTERNET); 2727 if (result != PackageManager.PERMISSION_GRANTED) { 2728 return false; 2729 } 2730 2731 Field field = Settings.Secure.class.getField("ACCESSIBILITY_SCRIPT_INJECTION"); 2732 field.setAccessible(true); 2733 String accessibilityScriptInjection = (String) field.get(null); 2734 ContentResolver contentResolver = getContext().getContentResolver(); 2735 2736 if (mAccessibilityScriptInjectionObserver == null) { 2737 ContentObserver contentObserver = new ContentObserver(new Handler()) { 2738 public void onChange(boolean selfChange, Uri uri) { 2739 setAccessibilityState(mAccessibilityManager.isEnabled()); 2740 } 2741 }; 2742 contentResolver.registerContentObserver( 2743 Settings.Secure.getUriFor(accessibilityScriptInjection), 2744 false, 2745 contentObserver); 2746 mAccessibilityScriptInjectionObserver = contentObserver; 2747 } 2748 2749 return Settings.Secure.getInt(contentResolver, accessibilityScriptInjection, 0) == 1; 2750 } catch (NoSuchFieldException e) { 2751 } catch (IllegalAccessException e) { 2752 } 2753 return false; 2754 } 2755 2756 /** 2757 * Returns whether or not accessibility injection is being used. 2758 */ 2759 public boolean isInjectingAccessibilityScript() { 2760 return mAccessibilityInjector.accessibilityIsAvailable(); 2761 } 2762 2763 /** 2764 * Turns browser accessibility on or off. 2765 * If |state| is |false|, this turns off both native and injected accessibility. 2766 * Otherwise, if accessibility script injection is enabled, this will enable the injected 2767 * accessibility scripts, and if it is disabled this will enable the native accessibility. 2768 */ 2769 public void setAccessibilityState(boolean state) { 2770 boolean injectedAccessibility = false; 2771 boolean nativeAccessibility = false; 2772 if (state) { 2773 if (isDeviceAccessibilityScriptInjectionEnabled()) { 2774 injectedAccessibility = true; 2775 } else { 2776 nativeAccessibility = true; 2777 } 2778 } 2779 setInjectedAccessibility(injectedAccessibility); 2780 setNativeAccessibilityState(nativeAccessibility); 2781 } 2782 2783 /** 2784 * Enable or disable native accessibility features. 2785 */ 2786 public void setNativeAccessibilityState(boolean enabled) { 2787 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 2788 nativeSetAccessibilityEnabled(mNativeContentViewCore, enabled); 2789 } 2790 } 2791 2792 /** 2793 * Enable or disable injected accessibility features 2794 */ 2795 public void setInjectedAccessibility(boolean enabled) { 2796 mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary(); 2797 mAccessibilityInjector.setScriptEnabled(enabled); 2798 } 2799 2800 /** 2801 * Stop any TTS notifications that are currently going on. 2802 */ 2803 public void stopCurrentAccessibilityNotifications() { 2804 mAccessibilityInjector.onPageLostFocus(); 2805 } 2806 2807 /** 2808 * Inform WebKit that Fullscreen mode has been exited by the user. 2809 */ 2810 public void exitFullscreen() { 2811 nativeExitFullscreen(mNativeContentViewCore); 2812 } 2813 2814 /** 2815 * Changes whether hiding the top controls is enabled. 2816 * 2817 * @param enableHiding Whether hiding the top controls should be enabled or not. 2818 * @param enableShowing Whether showing the top controls should be enabled or not. 2819 * @param animate Whether the transition should be animated or not. 2820 */ 2821 public void updateTopControlsState(boolean enableHiding, boolean enableShowing, 2822 boolean animate) { 2823 nativeUpdateTopControlsState(mNativeContentViewCore, enableHiding, enableShowing, animate); 2824 } 2825 2826 /** 2827 * @See android.webkit.WebView#pageDown(boolean) 2828 */ 2829 public boolean pageDown(boolean bottom) { 2830 final int maxVerticalScrollPix = mRenderCoordinates.getMaxVerticalScrollPixInt(); 2831 if (computeVerticalScrollOffset() >= maxVerticalScrollPix) { 2832 // We seem to already be at the bottom of the page, so no scrolling will occur. 2833 return false; 2834 } 2835 2836 if (bottom) { 2837 scrollTo(computeHorizontalScrollOffset(), maxVerticalScrollPix); 2838 } else { 2839 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_PAGE_DOWN)); 2840 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_PAGE_DOWN)); 2841 } 2842 return true; 2843 } 2844 2845 /** 2846 * @See android.webkit.WebView#pageUp(boolean) 2847 */ 2848 public boolean pageUp(boolean top) { 2849 if (computeVerticalScrollOffset() == 0) { 2850 // We seem to already be at the top of the page, so no scrolling will occur. 2851 return false; 2852 } 2853 2854 if (top) { 2855 scrollTo(computeHorizontalScrollOffset(), 0); 2856 } else { 2857 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_PAGE_UP)); 2858 dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_PAGE_UP)); 2859 } 2860 return true; 2861 } 2862 2863 /** 2864 * Callback factory method for nativeGetNavigationHistory(). 2865 */ 2866 @CalledByNative 2867 private void addToNavigationHistory(Object history, int index, String url, String virtualUrl, 2868 String originalUrl, String title, Bitmap favicon) { 2869 NavigationEntry entry = new NavigationEntry( 2870 index, url, virtualUrl, originalUrl, title, favicon); 2871 ((NavigationHistory) history).addEntry(entry); 2872 } 2873 2874 /** 2875 * Get a copy of the navigation history of the view. 2876 */ 2877 public NavigationHistory getNavigationHistory() { 2878 NavigationHistory history = new NavigationHistory(); 2879 int currentIndex = nativeGetNavigationHistory(mNativeContentViewCore, history); 2880 history.setCurrentEntryIndex(currentIndex); 2881 return history; 2882 } 2883 2884 @Override 2885 public NavigationHistory getDirectedNavigationHistory(boolean isForward, int itemLimit) { 2886 NavigationHistory history = new NavigationHistory(); 2887 nativeGetDirectedNavigationHistory(mNativeContentViewCore, history, isForward, itemLimit); 2888 return history; 2889 } 2890 2891 /** 2892 * @return The original request URL for the current navigation entry, or null if there is no 2893 * current entry. 2894 */ 2895 public String getOriginalUrlForActiveNavigationEntry() { 2896 return nativeGetOriginalUrlForActiveNavigationEntry(mNativeContentViewCore); 2897 } 2898 2899 /** 2900 * @return The cached copy of render positions and scales. 2901 */ 2902 public RenderCoordinates getRenderCoordinates() { 2903 return mRenderCoordinates; 2904 } 2905 2906 @CalledByNative 2907 private static Rect createRect(int x, int y, int right, int bottom) { 2908 return new Rect(x, y, right, bottom); 2909 } 2910 2911 public void attachExternalVideoSurface(int playerId, Surface surface) { 2912 if (mNativeContentViewCore != 0) { 2913 nativeAttachExternalVideoSurface(mNativeContentViewCore, playerId, surface); 2914 } 2915 } 2916 2917 public void detachExternalVideoSurface(int playerId) { 2918 if (mNativeContentViewCore != 0) { 2919 nativeDetachExternalVideoSurface(mNativeContentViewCore, playerId); 2920 } 2921 } 2922 2923 private boolean onAnimate(long frameTimeMicros) { 2924 if (mNativeContentViewCore == 0) return false; 2925 return nativeOnAnimate(mNativeContentViewCore, frameTimeMicros); 2926 } 2927 2928 private void animateIfNecessary(long frameTimeMicros) { 2929 if (mNeedAnimate) { 2930 mNeedAnimate = onAnimate(frameTimeMicros); 2931 if (!mNeedAnimate) setVSyncNotificationEnabled(false); 2932 } 2933 } 2934 2935 @CalledByNative 2936 private void notifyExternalSurface( 2937 int playerId, boolean isRequest, float x, float y, float width, float height) { 2938 RenderCoordinates.NormalizedPoint topLeft = mRenderCoordinates.createNormalizedPoint(); 2939 RenderCoordinates.NormalizedPoint bottomRight = mRenderCoordinates.createNormalizedPoint(); 2940 topLeft.setLocalDip(x * getScale(), y * getScale()); 2941 bottomRight.setLocalDip((x + width) * getScale(), (y + height) * getScale()); 2942 2943 if (isRequest) getContentViewClient().onExternalVideoSurfaceRequested(playerId); 2944 getContentViewClient().onGeometryChanged( 2945 playerId, 2946 topLeft.getXPix(), 2947 topLeft.getYPix(), 2948 bottomRight.getXPix() - topLeft.getXPix(), 2949 bottomRight.getYPix() - topLeft.getYPix()); 2950 } 2951 2952 /** 2953 * Offer a subset of gesture events to the embedding View, 2954 * primarily for WebView compatibility. 2955 * 2956 * @param type The type of the event. 2957 * 2958 * @return true if the embedder handled the event. 2959 */ 2960 private boolean offerGestureToEmbedder(int type) { 2961 if (type == ContentViewGestureHandler.GESTURE_LONG_PRESS) { 2962 return mContainerView.performLongClick(); 2963 } 2964 return false; 2965 } 2966 2967 private native int nativeInit(boolean hardwareAccelerated, int webContentsPtr, 2968 int viewAndroidPtr, int windowAndroidPtr); 2969 2970 @CalledByNative 2971 private ContentVideoViewClient getContentVideoViewClient() { 2972 return mContentViewClient.getContentVideoViewClient(); 2973 } 2974 2975 private native void nativeOnJavaContentViewCoreDestroyed(int nativeContentViewCoreImpl); 2976 2977 private native void nativeLoadUrl( 2978 int nativeContentViewCoreImpl, 2979 String url, 2980 int loadUrlType, 2981 int transitionType, 2982 int uaOverrideOption, 2983 String extraHeaders, 2984 byte[] postData, 2985 String baseUrlForDataUrl, 2986 String virtualUrlForDataUrl, 2987 boolean canLoadLocalResources); 2988 2989 private native String nativeGetURL(int nativeContentViewCoreImpl); 2990 2991 private native String nativeGetTitle(int nativeContentViewCoreImpl); 2992 2993 private native void nativeShowInterstitialPage( 2994 int nativeContentViewCoreImpl, String url, int nativeInterstitialPageDelegateAndroid); 2995 private native boolean nativeIsShowingInterstitialPage(int nativeContentViewCoreImpl); 2996 2997 private native boolean nativeIsIncognito(int nativeContentViewCoreImpl); 2998 2999 // Returns true if the native side crashed so that java side can draw a sad tab. 3000 private native boolean nativeCrashed(int nativeContentViewCoreImpl); 3001 3002 private native void nativeSetFocus(int nativeContentViewCoreImpl, boolean focused); 3003 3004 private native void nativeSendOrientationChangeEvent( 3005 int nativeContentViewCoreImpl, int orientation); 3006 3007 // All touch events (including flings, scrolls etc) accept coordinates in physical pixels. 3008 private native boolean nativeSendTouchEvent( 3009 int nativeContentViewCoreImpl, long timeMs, int action, TouchPoint[] pts); 3010 3011 private native int nativeSendMouseMoveEvent( 3012 int nativeContentViewCoreImpl, long timeMs, float x, float y); 3013 3014 private native int nativeSendMouseWheelEvent( 3015 int nativeContentViewCoreImpl, long timeMs, float x, float y, float verticalAxis); 3016 3017 private native void nativeScrollBegin( 3018 int nativeContentViewCoreImpl, long timeMs, float x, float y); 3019 3020 private native void nativeScrollEnd(int nativeContentViewCoreImpl, long timeMs); 3021 3022 private native void nativeScrollBy( 3023 int nativeContentViewCoreImpl, long timeMs, float x, float y, 3024 float deltaX, float deltaY, boolean lastInputEventForVSync); 3025 3026 private native void nativeFlingStart( 3027 int nativeContentViewCoreImpl, long timeMs, float x, float y, float vx, float vy); 3028 3029 private native void nativeFlingCancel(int nativeContentViewCoreImpl, long timeMs); 3030 3031 private native void nativeSingleTap( 3032 int nativeContentViewCoreImpl, long timeMs, float x, float y, boolean linkPreviewTap); 3033 3034 private native void nativeSingleTapUnconfirmed( 3035 int nativeContentViewCoreImpl, long timeMs, float x, float y); 3036 3037 private native void nativeShowPressState( 3038 int nativeContentViewCoreImpl, long timeMs, float x, float y); 3039 3040 private native void nativeShowPressCancel( 3041 int nativeContentViewCoreImpl, long timeMs, float x, float y); 3042 3043 private native void nativeDoubleTap( 3044 int nativeContentViewCoreImpl, long timeMs, float x, float y); 3045 3046 private native void nativeLongPress( 3047 int nativeContentViewCoreImpl, long timeMs, float x, float y, boolean linkPreviewTap); 3048 3049 private native void nativeLongTap( 3050 int nativeContentViewCoreImpl, long timeMs, float x, float y, boolean linkPreviewTap); 3051 3052 private native void nativePinchBegin( 3053 int nativeContentViewCoreImpl, long timeMs, float x, float y); 3054 3055 private native void nativePinchEnd(int nativeContentViewCoreImpl, long timeMs); 3056 3057 private native void nativePinchBy(int nativeContentViewCoreImpl, long timeMs, 3058 float anchorX, float anchorY, float deltaScale, boolean lastInputEventForVSync); 3059 3060 private native void nativeSelectBetweenCoordinates( 3061 int nativeContentViewCoreImpl, float x1, float y1, float x2, float y2); 3062 3063 private native void nativeMoveCaret(int nativeContentViewCoreImpl, float x, float y); 3064 3065 private native boolean nativeCanGoBack(int nativeContentViewCoreImpl); 3066 private native boolean nativeCanGoForward(int nativeContentViewCoreImpl); 3067 private native boolean nativeCanGoToOffset(int nativeContentViewCoreImpl, int offset); 3068 private native void nativeGoBack(int nativeContentViewCoreImpl); 3069 private native void nativeGoForward(int nativeContentViewCoreImpl); 3070 private native void nativeGoToOffset(int nativeContentViewCoreImpl, int offset); 3071 private native void nativeGoToNavigationIndex(int nativeContentViewCoreImpl, int index); 3072 3073 private native void nativeStopLoading(int nativeContentViewCoreImpl); 3074 3075 private native void nativeReload(int nativeContentViewCoreImpl); 3076 3077 private native void nativeCancelPendingReload(int nativeContentViewCoreImpl); 3078 3079 private native void nativeContinuePendingReload(int nativeContentViewCoreImpl); 3080 3081 private native void nativeSelectPopupMenuItems(int nativeContentViewCoreImpl, int[] indices); 3082 3083 private native void nativeScrollFocusedEditableNodeIntoView(int nativeContentViewCoreImpl); 3084 private native void nativeUndoScrollFocusedEditableNodeIntoView(int nativeContentViewCoreImpl); 3085 private native boolean nativeNeedsReload(int nativeContentViewCoreImpl); 3086 3087 private native void nativeClearHistory(int nativeContentViewCoreImpl); 3088 3089 private native void nativeEvaluateJavaScript(int nativeContentViewCoreImpl, 3090 String script, JavaScriptCallback callback); 3091 3092 private native int nativeGetNativeImeAdapter(int nativeContentViewCoreImpl); 3093 3094 private native int nativeGetCurrentRenderProcessId(int nativeContentViewCoreImpl); 3095 3096 private native int nativeGetBackgroundColor(int nativeContentViewCoreImpl); 3097 3098 private native void nativeOnShow(int nativeContentViewCoreImpl); 3099 private native void nativeOnHide(int nativeContentViewCoreImpl); 3100 3101 private native void nativeSetUseDesktopUserAgent(int nativeContentViewCoreImpl, 3102 boolean enabled, boolean reloadOnChange); 3103 private native boolean nativeGetUseDesktopUserAgent(int nativeContentViewCoreImpl); 3104 3105 private native void nativeClearSslPreferences(int nativeContentViewCoreImpl); 3106 3107 private native void nativeAddJavascriptInterface(int nativeContentViewCoreImpl, Object object, 3108 String name, Class requiredAnnotation, HashSet<Object> retainedObjectSet); 3109 3110 private native void nativeRemoveJavascriptInterface(int nativeContentViewCoreImpl, String name); 3111 3112 private native int nativeGetNavigationHistory(int nativeContentViewCoreImpl, Object context); 3113 private native void nativeGetDirectedNavigationHistory(int nativeContentViewCoreImpl, 3114 Object context, boolean isForward, int maxEntries); 3115 private native String nativeGetOriginalUrlForActiveNavigationEntry( 3116 int nativeContentViewCoreImpl); 3117 3118 private native void nativeUpdateVSyncParameters(int nativeContentViewCoreImpl, 3119 long timebaseMicros, long intervalMicros); 3120 3121 private native void nativeOnVSync(int nativeContentViewCoreImpl, long frameTimeMicros); 3122 3123 private native boolean nativeOnAnimate(int nativeContentViewCoreImpl, long frameTimeMicros); 3124 3125 private native boolean nativePopulateBitmapFromCompositor(int nativeContentViewCoreImpl, 3126 Bitmap bitmap); 3127 3128 private native void nativeWasResized(int nativeContentViewCoreImpl); 3129 3130 private native boolean nativeIsRenderWidgetHostViewReady(int nativeContentViewCoreImpl); 3131 3132 private native void nativeExitFullscreen(int nativeContentViewCoreImpl); 3133 private native void nativeUpdateTopControlsState(int nativeContentViewCoreImpl, 3134 boolean enableHiding, boolean enableShowing, boolean animate); 3135 3136 private native void nativeShowImeIfNeeded(int nativeContentViewCoreImpl); 3137 3138 private native void nativeAttachExternalVideoSurface( 3139 int nativeContentViewCoreImpl, int playerId, Surface surface); 3140 3141 private native void nativeDetachExternalVideoSurface( 3142 int nativeContentViewCoreImpl, int playerId); 3143 3144 private native void nativeSetAccessibilityEnabled( 3145 int nativeContentViewCoreImpl, boolean enabled); 3146} 3147