ContentViewCore.java revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
1e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// Copyright 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)package org.chromium.content.browser; 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.annotation.SuppressLint; 89ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochimport android.app.Activity; 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.app.SearchManager; 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.content.ContentResolver; 1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import android.content.Context; 12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import android.content.Intent; 1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import android.content.pm.PackageManager; 14e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochimport android.content.res.Configuration; 1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import android.database.ContentObserver; 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.graphics.Bitmap; 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.graphics.Canvas; 18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.graphics.Color; 19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.graphics.Rect; 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.net.Uri; 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.os.Build; 22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.os.Bundle; 23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.os.Handler; 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.os.ResultReceiver; 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.os.SystemClock; 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.provider.Browser; 27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.provider.Settings; 28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.text.Editable; 29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.text.Selection; 30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.text.TextUtils; 31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.util.Log; 32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.view.ActionMode; 33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.view.HapticFeedbackConstants; 34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import android.view.InputDevice; 35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.view.KeyEvent; 36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.view.MotionEvent; 37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.view.View; 38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.view.ViewGroup; 39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.view.accessibility.AccessibilityEvent; 40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import android.view.accessibility.AccessibilityManager; 41d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; 42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.view.accessibility.AccessibilityNodeInfo; 43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.view.accessibility.AccessibilityNodeProvider; 44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.view.inputmethod.EditorInfo; 45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.view.inputmethod.InputConnection; 46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.view.inputmethod.InputMethodManager; 47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.widget.FrameLayout; 4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import com.google.common.annotations.VisibleForTesting; 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.base.CalledByNative; 52e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochimport org.chromium.base.CommandLine; 53e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochimport org.chromium.base.JNINamespace; 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.base.ObserverList; 55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import org.chromium.base.ObserverList.RewindableIterator; 56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import org.chromium.base.TraceEvent; 5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import org.chromium.content.R; 5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import org.chromium.content.browser.ScreenOrientationListener.ScreenOrientationObserver; 5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import org.chromium.content.browser.accessibility.AccessibilityInjector; 6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import org.chromium.content.browser.accessibility.BrowserAccessibilityManager; 6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import org.chromium.content.browser.input.AdapterInputConnection; 6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import org.chromium.content.browser.input.HandleView; 63e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochimport org.chromium.content.browser.input.ImeAdapter; 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.content.browser.input.ImeAdapter.AdapterInputConnectionFactory; 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.content.browser.input.InputMethodManagerWrapper; 66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import org.chromium.content.browser.input.InsertionHandleController; 67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import org.chromium.content.browser.input.SelectPopupDialog; 68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import org.chromium.content.browser.input.SelectPopupItem; 69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import org.chromium.content.browser.input.SelectionHandleController; 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.chromium.content.common.ContentSwitches; 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.content_public.browser.GestureStateListener; 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.content_public.browser.WebContents; 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.ui.base.ViewAndroid; 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.ui.base.ViewAndroidDelegate; 75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import org.chromium.ui.base.WindowAndroid; 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.ui.gfx.DeviceDisplayInfo; 77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import java.lang.annotation.Annotation; 79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import java.lang.reflect.Field; 801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.ArrayList; 811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.HashMap; 821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.HashSet; 831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.util.List; 84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import java.util.Map; 85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/** 87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Provides a Java-side 'wrapper' around a WebContent (native) instance. 88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Contains all the major functionality necessary to manage the lifecycle of a ContentView without 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * being tied to the view system. 90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */ 91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)@JNINamespace("content") 92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)public class ContentViewCore 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) implements NavigationClient, AccessibilityStateChangeListener, ScreenOrientationObserver { 94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private static final String TAG = "ContentViewCore"; 96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Used to avoid enabling zooming in / out if resulting zooming will 98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // produce little visible difference. 99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private static final float ZOOM_CONTROLS_EPSILON = 0.007f; 100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Used to represent gestures for long press and long tap. 102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private static final int IS_LONG_PRESS = 1; 103effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch private static final int IS_LONG_TAP = 2; 104effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 105effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Length of the delay (in ms) before fading in handles after the last page movement. 106effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch private static final int TEXT_HANDLE_FADE_IN_DELAY = 300; 107effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 108effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // If the embedder adds a JavaScript interface object that contains an indirect reference to 109effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // the ContentViewCore, then storing a strong ref to the interface object on the native 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // side would prevent garbage collection of the ContentViewCore (as that strong ref would 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // create a new GC root). 112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // For that reason, we store only a weak reference to the interface object on the 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // native side. However we still need a strong reference on the Java side to 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // prevent garbage collection if the embedder doesn't maintain their own ref to the 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // interface object - the Java side ref won't create a new GC root. 116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // This map stores those refernces. We put into the map on addJavaScriptInterface() 117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // and remove from it in removeJavaScriptInterface(). 118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private final Map<String, Object> mJavaScriptInterfaces = new HashMap<String, Object>(); 119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Additionally, we keep track of all Java bound JS objects that are in use on the 12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // current page to ensure that they are not garbage collected until the page is 122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // navigated. This includes interface objects that have been removed 12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // via the removeJavaScriptInterface API and transient objects returned from methods 12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // on the interface object. Note we use HashSet rather than Set as the native side 125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // expects HashSet (no bindings for interfaces). 12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private final HashSet<Object> mRetainedJavaScriptObjects = new HashSet<Object>(); 127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) /** 129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Interface that consumers of {@link ContentViewCore} must implement to allow the proper 130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * dispatching of view methods through the containing view. 131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * 13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * <p> 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * All methods with the "super_" prefix should be routed to the parent of the 134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * implementing container view. 135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */ 136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) @SuppressWarnings("javadoc") 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public interface InternalAccessDelegate { 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /** 139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @see View#drawChild(Canvas, View, long) 140e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch */ 141e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch boolean drawChild(Canvas canvas, View child, long drawingTime); 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /** 144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @see View#onKeyUp(keyCode, KeyEvent) 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) boolean super_onKeyUp(int keyCode, KeyEvent event); 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) /** 149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @see View#dispatchKeyEventPreIme(KeyEvent) 150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */ 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) boolean super_dispatchKeyEventPreIme(KeyEvent event); 152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /** 154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @see View#dispatchKeyEvent(KeyEvent) 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) boolean super_dispatchKeyEvent(KeyEvent event); 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 15890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) /** 15990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * @see View#onGenericMotionEvent(MotionEvent) 16090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) */ 16190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) boolean super_onGenericMotionEvent(MotionEvent event); 16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) /** 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @see View#onConfigurationChanged(Configuration) 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void super_onConfigurationChanged(Configuration newConfig); 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) /** 169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @see View#onScrollChanged(int, int, int, int) 170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */ 171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) void onScrollChanged(int lPix, int tPix, int oldlPix, int oldtPix); 172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) /** 174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @see View#awakenScrollBars() 175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */ 176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) boolean awakenScrollBars(); 177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) /** 179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @see View#awakenScrollBars(int, boolean) 1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */ 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) boolean super_awakenScrollBars(int startDelay, boolean invalidate); 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch /** 18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * An interface for controlling visibility and state of embedder-provided zoom controls. 18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) */ 18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public interface ZoomControlsDelegate { 18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) /** 18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * Called when it's reasonable to show zoom controls. 19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) */ 19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) void invokeZoomPicker(); 19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) /** 194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Called when zoom controls need to be hidden (e.g. when the view hides). 19590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) */ 196f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) void dismissZoomPicker(); 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 199f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Called when page scale has been changed, so the controls can update their state. 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void updateZoomControls(); 202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 203e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 204e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch /** 205d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) * An interface that allows the embedder to be notified when the results of 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * extractSmartClipData are available. 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public interface SmartClipDataListener { 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public void onSmartClipDataExtracted(String result); 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private VSyncManager.Provider mVSyncProvider; 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private VSyncManager.Listener mVSyncListener; 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private int mVSyncSubscriberCount; 215 private boolean mVSyncListenerRegistered; 216 217 // To avoid IPC delay we use input events to directly trigger a vsync signal in the renderer. 218 // When we do this, we also need to avoid sending the real vsync signal for the current 219 // frame to avoid double-ticking. This flag is used to inhibit the next vsync notification. 220 private boolean mDidSignalVSyncUsingInputEvent; 221 222 public VSyncManager.Listener getVSyncListener(VSyncManager.Provider vsyncProvider) { 223 if (mVSyncProvider != null && mVSyncListenerRegistered) { 224 mVSyncProvider.unregisterVSyncListener(mVSyncListener); 225 mVSyncListenerRegistered = false; 226 } 227 228 mVSyncProvider = vsyncProvider; 229 mVSyncListener = new VSyncManager.Listener() { 230 @Override 231 public void updateVSync(long tickTimeMicros, long intervalMicros) { 232 if (mNativeContentViewCore != 0) { 233 nativeUpdateVSyncParameters(mNativeContentViewCore, tickTimeMicros, 234 intervalMicros); 235 } 236 } 237 238 @Override 239 public void onVSync(long frameTimeMicros) { 240 animateIfNecessary(frameTimeMicros); 241 242 if (mRequestedVSyncForInput) { 243 mRequestedVSyncForInput = false; 244 removeVSyncSubscriber(); 245 } 246 if (mNativeContentViewCore != 0) { 247 nativeOnVSync(mNativeContentViewCore, frameTimeMicros); 248 } 249 } 250 }; 251 252 if (mVSyncSubscriberCount > 0) { 253 // addVSyncSubscriber() is called before getVSyncListener. 254 vsyncProvider.registerVSyncListener(mVSyncListener); 255 mVSyncListenerRegistered = true; 256 } 257 258 return mVSyncListener; 259 } 260 261 @CalledByNative 262 void addVSyncSubscriber() { 263 if (!isVSyncNotificationEnabled()) { 264 mDidSignalVSyncUsingInputEvent = false; 265 } 266 if (mVSyncProvider != null && !mVSyncListenerRegistered) { 267 mVSyncProvider.registerVSyncListener(mVSyncListener); 268 mVSyncListenerRegistered = true; 269 } 270 mVSyncSubscriberCount++; 271 } 272 273 @CalledByNative 274 void removeVSyncSubscriber() { 275 if (mVSyncProvider != null && mVSyncSubscriberCount == 1) { 276 assert mVSyncListenerRegistered; 277 mVSyncProvider.unregisterVSyncListener(mVSyncListener); 278 mVSyncListenerRegistered = false; 279 } 280 mVSyncSubscriberCount--; 281 assert mVSyncSubscriberCount >= 0; 282 } 283 284 @CalledByNative 285 private void resetVSyncNotification() { 286 while (isVSyncNotificationEnabled()) removeVSyncSubscriber(); 287 mVSyncSubscriberCount = 0; 288 mVSyncListenerRegistered = false; 289 mNeedAnimate = false; 290 } 291 292 private boolean isVSyncNotificationEnabled() { 293 return mVSyncProvider != null && mVSyncListenerRegistered; 294 } 295 296 @CalledByNative 297 private void setNeedsAnimate() { 298 if (!mNeedAnimate) { 299 mNeedAnimate = true; 300 addVSyncSubscriber(); 301 } 302 } 303 304 private final Context mContext; 305 private ViewGroup mContainerView; 306 private InternalAccessDelegate mContainerViewInternals; 307 private WebContents mWebContents; 308 private WebContentsObserverAndroid mWebContentsObserver; 309 310 private ContentViewClient mContentViewClient; 311 312 private ContentSettings mContentSettings; 313 314 // Native pointer to C++ ContentViewCoreImpl object which will be set by nativeInit(). 315 private long mNativeContentViewCore = 0; 316 317 private boolean mInForeground = false; 318 319 private final ObserverList<GestureStateListener> mGestureStateListeners; 320 private final RewindableIterator<GestureStateListener> mGestureStateListenersIterator; 321 private ZoomControlsDelegate mZoomControlsDelegate; 322 323 private PopupZoomer mPopupZoomer; 324 private SelectPopupDialog mSelectPopupDialog; 325 326 private Runnable mFakeMouseMoveRunnable = null; 327 328 // Only valid when focused on a text / password field. 329 private ImeAdapter mImeAdapter; 330 private ImeAdapter.AdapterInputConnectionFactory mAdapterInputConnectionFactory; 331 private AdapterInputConnection mInputConnection; 332 private InputMethodManagerWrapper mInputMethodManagerWrapper; 333 334 private SelectionHandleController mSelectionHandleController; 335 private InsertionHandleController mInsertionHandleController; 336 337 private Runnable mDeferredHandleFadeInRunnable; 338 339 private PositionObserver mPositionObserver; 340 private PositionObserver.Listener mPositionListener; 341 342 // Size of the viewport in physical pixels as set from onSizeChanged. 343 private int mViewportWidthPix; 344 private int mViewportHeightPix; 345 private int mPhysicalBackingWidthPix; 346 private int mPhysicalBackingHeightPix; 347 private int mOverdrawBottomHeightPix; 348 private int mViewportSizeOffsetWidthPix; 349 private int mViewportSizeOffsetHeightPix; 350 private int mLocationInWindowX; 351 private int mLocationInWindowY; 352 353 // Cached copy of all positions and scales as reported by the renderer. 354 private final RenderCoordinates mRenderCoordinates; 355 356 private final RenderCoordinates.NormalizedPoint mStartHandlePoint; 357 private final RenderCoordinates.NormalizedPoint mEndHandlePoint; 358 private final RenderCoordinates.NormalizedPoint mInsertionHandlePoint; 359 360 // Cached copy of the visible rectangle defined by two points. Needed to determine 361 // visibility of insertion/selection handles. 362 private final RenderCoordinates.NormalizedPoint mTopLeftVisibilityClippingPoint; 363 private final RenderCoordinates.NormalizedPoint mBottomRightVisibilityClippingPoint; 364 365 // Tracks whether a selection is currently active. When applied to selected text, indicates 366 // whether the last selected text is still highlighted. 367 private boolean mHasSelection; 368 private String mLastSelectedText; 369 private boolean mSelectionEditable; 370 private ActionMode mActionMode; 371 private boolean mUnselectAllOnActionModeDismiss; 372 373 // Delegate that will handle GET downloads, and be notified of completion of POST downloads. 374 private ContentViewDownloadDelegate mDownloadDelegate; 375 376 // The AccessibilityInjector that handles loading Accessibility scripts into the web page. 377 private AccessibilityInjector mAccessibilityInjector; 378 379 // Whether native accessibility, i.e. without any script injection, is allowed. 380 private boolean mNativeAccessibilityAllowed; 381 382 // Whether native accessibility, i.e. without any script injection, has been enabled. 383 private boolean mNativeAccessibilityEnabled; 384 385 // Handles native accessibility, i.e. without any script injection. 386 private BrowserAccessibilityManager mBrowserAccessibilityManager; 387 388 // System accessibility service. 389 private final AccessibilityManager mAccessibilityManager; 390 391 // Accessibility touch exploration state. 392 private boolean mTouchExplorationEnabled; 393 394 // Allows us to dynamically respond when the accessibility script injection flag changes. 395 private ContentObserver mAccessibilityScriptInjectionObserver; 396 397 // Temporary notification to tell onSizeChanged to focus a form element, 398 // because the OSK was just brought up. 399 private final Rect mFocusPreOSKViewportRect = new Rect(); 400 401 // Whether we received a new frame since consumePendingRendererFrame() was last called. 402 private boolean mPendingRendererFrame = false; 403 404 // Whether we should animate at the next vsync tick. 405 private boolean mNeedAnimate = false; 406 407 // Whether we requested a proactive vsync event in response to touch input. 408 // This reduces the latency of responding to input by ensuring the renderer 409 // is sent a BeginFrame for every touch event we receive. Otherwise the 410 // renderer's SetNeedsBeginFrame message would get serviced at the next 411 // vsync. 412 private boolean mRequestedVSyncForInput = false; 413 414 // On single tap this will store the x, y coordinates of the touch. 415 private int mSingleTapX; 416 private int mSingleTapY; 417 418 // Whether a touch scroll sequence is active, used to hide text selection 419 // handles. Note that a scroll sequence will *always* bound a pinch 420 // sequence, so this will also be true for the duration of a pinch gesture. 421 private boolean mTouchScrollInProgress; 422 423 // The outstanding fling start events that hasn't got fling end yet. It may be > 1 because 424 // onNativeFlingStopped() is called asynchronously. 425 private int mPotentiallyActiveFlingCount; 426 427 private ViewAndroid mViewAndroid; 428 429 private SmartClipDataListener mSmartClipDataListener = null; 430 431 // This holds the state of editable text (e.g. contents of <input>, contenteditable) of 432 // a focused element. 433 // Every time the user, IME, javascript (Blink), autofill etc. modifies the content, the new 434 // state must be reflected to this to keep consistency. 435 private Editable mEditable; 436 437 /** 438 * PID used to indicate an invalid render process. 439 */ 440 // Keep in sync with the value returned from ContentViewCoreImpl::GetCurrentRendererProcessId() 441 // if there is no render process. 442 public static final int INVALID_RENDER_PROCESS_PID = 0; 443 444 /** 445 * Constructs a new ContentViewCore. Embedders must call initialize() after constructing 446 * a ContentViewCore and before using it. 447 * 448 * @param context The context used to create this. 449 */ 450 public ContentViewCore(Context context) { 451 mContext = context; 452 453 mAdapterInputConnectionFactory = new AdapterInputConnectionFactory(); 454 mInputMethodManagerWrapper = new InputMethodManagerWrapper(mContext); 455 456 mRenderCoordinates = new RenderCoordinates(); 457 float deviceScaleFactor = getContext().getResources().getDisplayMetrics().density; 458 String forceScaleFactor = CommandLine.getInstance().getSwitchValue( 459 ContentSwitches.FORCE_DEVICE_SCALE_FACTOR); 460 if (forceScaleFactor != null) { 461 deviceScaleFactor = Float.valueOf(forceScaleFactor); 462 } 463 mRenderCoordinates.setDeviceScaleFactor(deviceScaleFactor); 464 mStartHandlePoint = mRenderCoordinates.createNormalizedPoint(); 465 mEndHandlePoint = mRenderCoordinates.createNormalizedPoint(); 466 mInsertionHandlePoint = mRenderCoordinates.createNormalizedPoint(); 467 mTopLeftVisibilityClippingPoint = mRenderCoordinates.createNormalizedPoint(); 468 mBottomRightVisibilityClippingPoint = mRenderCoordinates.createNormalizedPoint(); 469 mAccessibilityManager = (AccessibilityManager) 470 getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); 471 mGestureStateListeners = new ObserverList<GestureStateListener>(); 472 mGestureStateListenersIterator = mGestureStateListeners.rewindableIterator(); 473 474 mEditable = Editable.Factory.getInstance().newEditable(""); 475 Selection.setSelection(mEditable, 0); 476 } 477 478 /** 479 * @return The context used for creating this ContentViewCore. 480 */ 481 @CalledByNative 482 public Context getContext() { 483 return mContext; 484 } 485 486 /** 487 * @return The ViewGroup that all view actions of this ContentViewCore should interact with. 488 */ 489 public ViewGroup getContainerView() { 490 return mContainerView; 491 } 492 493 /** 494 * @return The WebContents currently being rendered. 495 */ 496 public WebContents getWebContents() { 497 return mWebContents; 498 } 499 500 /** 501 * Specifies how much smaller the WebKit layout size should be relative to the size of this 502 * view. 503 * @param offsetXPix The X amount in pixels to shrink the viewport by. 504 * @param offsetYPix The Y amount in pixels to shrink the viewport by. 505 */ 506 public void setViewportSizeOffset(int offsetXPix, int offsetYPix) { 507 if (offsetXPix != mViewportSizeOffsetWidthPix || 508 offsetYPix != mViewportSizeOffsetHeightPix) { 509 mViewportSizeOffsetWidthPix = offsetXPix; 510 mViewportSizeOffsetHeightPix = offsetYPix; 511 if (mNativeContentViewCore != 0) nativeWasResized(mNativeContentViewCore); 512 } 513 } 514 515 /** 516 * Returns a delegate that can be used to add and remove views from the ContainerView. 517 * 518 * NOTE: Use with care, as not all ContentViewCore users setup their ContainerView in the same 519 * way. In particular, the Android WebView has limitations on what implementation details can 520 * be provided via a child view, as they are visible in the API and could introduce 521 * compatibility breaks with existing applications. If in doubt, contact the 522 * android_webview/OWNERS 523 * 524 * @return A ViewAndroidDelegate that can be used to add and remove views. 525 */ 526 @VisibleForTesting 527 public ViewAndroidDelegate getViewAndroidDelegate() { 528 return new ViewAndroidDelegate() { 529 @Override 530 public View acquireAnchorView() { 531 View anchorView = new View(getContext()); 532 mContainerView.addView(anchorView); 533 return anchorView; 534 } 535 536 @Override 537 @SuppressWarnings("deprecation") // AbsoluteLayout 538 public void setAnchorViewPosition( 539 View view, float x, float y, float width, float height) { 540 assert view.getParent() == mContainerView; 541 542 float scale = (float) DeviceDisplayInfo.create(getContext()).getDIPScale(); 543 544 // The anchor view should not go outside the bounds of the ContainerView. 545 int leftMargin = Math.round(x * scale); 546 int topMargin = Math.round(mRenderCoordinates.getContentOffsetYPix() + y * scale); 547 int scaledWidth = Math.round(width * scale); 548 // ContentViewCore currently only supports these two container view types. 549 if (mContainerView instanceof FrameLayout) { 550 if (scaledWidth + leftMargin > mContainerView.getWidth()) { 551 scaledWidth = mContainerView.getWidth() - leftMargin; 552 } 553 FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( 554 scaledWidth, Math.round(height * scale)); 555 lp.leftMargin = leftMargin; 556 lp.topMargin = topMargin; 557 view.setLayoutParams(lp); 558 } else if (mContainerView instanceof android.widget.AbsoluteLayout) { 559 // This fixes the offset due to a difference in 560 // scrolling model of WebView vs. Chrome. 561 // TODO(sgurun) fix this to use mContainerView.getScroll[X/Y]() 562 // as it naturally accounts for scroll differences between 563 // these models. 564 leftMargin += mRenderCoordinates.getScrollXPixInt(); 565 topMargin += mRenderCoordinates.getScrollYPixInt(); 566 567 android.widget.AbsoluteLayout.LayoutParams lp = 568 new android.widget.AbsoluteLayout.LayoutParams( 569 scaledWidth, (int) (height * scale), leftMargin, topMargin); 570 view.setLayoutParams(lp); 571 } else { 572 Log.e(TAG, "Unknown layout " + mContainerView.getClass().getName()); 573 } 574 } 575 576 @Override 577 public void releaseAnchorView(View anchorView) { 578 mContainerView.removeView(anchorView); 579 } 580 }; 581 } 582 583 @VisibleForTesting 584 public void setImeAdapterForTest(ImeAdapter imeAdapter) { 585 mImeAdapter = imeAdapter; 586 } 587 588 @VisibleForTesting 589 public ImeAdapter getImeAdapterForTest() { 590 return mImeAdapter; 591 } 592 593 @VisibleForTesting 594 public void setAdapterInputConnectionFactory(AdapterInputConnectionFactory factory) { 595 mAdapterInputConnectionFactory = factory; 596 } 597 598 @VisibleForTesting 599 public void setInputMethodManagerWrapperForTest(InputMethodManagerWrapper immw) { 600 mInputMethodManagerWrapper = immw; 601 } 602 603 @VisibleForTesting 604 public AdapterInputConnection getInputConnectionForTest() { 605 return mInputConnection; 606 } 607 608 @VisibleForTesting 609 public void setContainerViewForTest(ViewGroup view) { 610 mContainerView = view; 611 } 612 613 private ImeAdapter createImeAdapter(Context context) { 614 return new ImeAdapter(mInputMethodManagerWrapper, 615 new ImeAdapter.ImeAdapterDelegate() { 616 @Override 617 public void onImeEvent(boolean isFinish) { 618 getContentViewClient().onImeEvent(); 619 if (!isFinish) { 620 hideHandles(); 621 } 622 } 623 624 @Override 625 public void onSetFieldValue() { 626 scrollFocusedEditableNodeIntoView(); 627 } 628 629 @Override 630 public void onDismissInput() { 631 getContentViewClient().onImeStateChangeRequested(false); 632 } 633 634 @Override 635 public View getAttachedView() { 636 return mContainerView; 637 } 638 639 @Override 640 public ResultReceiver getNewShowKeyboardReceiver() { 641 return new ResultReceiver(new Handler()) { 642 @Override 643 public void onReceiveResult(int resultCode, Bundle resultData) { 644 getContentViewClient().onImeStateChangeRequested( 645 resultCode == InputMethodManager.RESULT_SHOWN || 646 resultCode == InputMethodManager.RESULT_UNCHANGED_SHOWN); 647 if (resultCode == InputMethodManager.RESULT_SHOWN) { 648 // If OSK is newly shown, delay the form focus until 649 // the onSizeChanged (in order to adjust relative to the 650 // new size). 651 // TODO(jdduke): We should not assume that onSizeChanged will 652 // always be called, crbug.com/294908. 653 getContainerView().getWindowVisibleDisplayFrame( 654 mFocusPreOSKViewportRect); 655 } else if (resultCode == 656 InputMethodManager.RESULT_UNCHANGED_SHOWN) { 657 // If the OSK was already there, focus the form immediately. 658 scrollFocusedEditableNodeIntoView(); 659 } 660 } 661 }; 662 } 663 } 664 ); 665 } 666 667 /** 668 * 669 * @param containerView The view that will act as a container for all views created by this. 670 * @param internalDispatcher Handles dispatching all hidden or super methods to the 671 * containerView. 672 * @param nativeWebContents A pointer to the native web contents. 673 * @param windowAndroid An instance of the WindowAndroid. 674 */ 675 // Perform important post-construction set up of the ContentViewCore. 676 // We do not require the containing view in the constructor to allow embedders to create a 677 // ContentViewCore without having fully created its containing view. The containing view 678 // is a vital component of the ContentViewCore, so embedders must exercise caution in what 679 // they do with the ContentViewCore before calling initialize(). 680 // We supply the nativeWebContents pointer here rather than in the constructor to allow us 681 // to set the private browsing mode at a later point for the WebView implementation. 682 // Note that the caller remains the owner of the nativeWebContents and is responsible for 683 // deleting it after destroying the ContentViewCore. 684 public void initialize(ViewGroup containerView, InternalAccessDelegate internalDispatcher, 685 long nativeWebContents, WindowAndroid windowAndroid) { 686 mContainerView = containerView; 687 mPositionObserver = new ViewPositionObserver(mContainerView); 688 mPositionListener = new PositionObserver.Listener() { 689 @Override 690 public void onPositionChanged(int x, int y) { 691 if (isSelectionHandleShowing() || isInsertionHandleShowing()) { 692 temporarilyHideTextHandles(); 693 } 694 } 695 }; 696 697 long windowNativePointer = windowAndroid != null ? windowAndroid.getNativePointer() : 0; 698 699 long viewAndroidNativePointer = 0; 700 if (windowNativePointer != 0) { 701 mViewAndroid = new ViewAndroid(windowAndroid, getViewAndroidDelegate()); 702 viewAndroidNativePointer = mViewAndroid.getNativePointer(); 703 } 704 705 mZoomControlsDelegate = new ZoomControlsDelegate() { 706 @Override 707 public void invokeZoomPicker() {} 708 @Override 709 public void dismissZoomPicker() {} 710 @Override 711 public void updateZoomControls() {} 712 }; 713 714 mNativeContentViewCore = nativeInit( 715 nativeWebContents, viewAndroidNativePointer, windowNativePointer); 716 mWebContents = nativeGetWebContentsAndroid(mNativeContentViewCore); 717 mContentSettings = new ContentSettings(this, mNativeContentViewCore); 718 initializeContainerView(internalDispatcher); 719 720 mAccessibilityInjector = AccessibilityInjector.newInstance(this); 721 722 String contentDescription = "Web View"; 723 if (R.string.accessibility_content_view == 0) { 724 Log.w(TAG, "Setting contentDescription to 'Web View' as no value was specified."); 725 } else { 726 contentDescription = mContext.getResources().getString( 727 R.string.accessibility_content_view); 728 } 729 mContainerView.setContentDescription(contentDescription); 730 mWebContentsObserver = new WebContentsObserverAndroid(this) { 731 @Override 732 public void didStartLoading(String url) { 733 hidePopupDialog(); 734 resetScrollInProgress(); 735 resetGestureDetectors(); 736 } 737 }; 738 } 739 740 @CalledByNative 741 void onNativeContentViewCoreDestroyed(long nativeContentViewCore) { 742 assert nativeContentViewCore == mNativeContentViewCore; 743 mNativeContentViewCore = 0; 744 } 745 746 /** 747 * Set the Container view Internals. 748 * @param internalDispatcher Handles dispatching all hidden or super methods to the 749 * containerView. 750 */ 751 public void setContainerViewInternals(InternalAccessDelegate internalDispatcher) { 752 mContainerViewInternals = internalDispatcher; 753 } 754 755 /** 756 * Initializes the View that will contain all Views created by the ContentViewCore. 757 * 758 * @param internalDispatcher Handles dispatching all hidden or super methods to the 759 * containerView. 760 */ 761 private void initializeContainerView(InternalAccessDelegate internalDispatcher) { 762 TraceEvent.begin(); 763 mContainerViewInternals = internalDispatcher; 764 765 mContainerView.setWillNotDraw(false); 766 mContainerView.setClickable(true); 767 768 mRenderCoordinates.reset(); 769 onRenderCoordinatesUpdated(); 770 771 initPopupZoomer(mContext); 772 mImeAdapter = createImeAdapter(mContext); 773 TraceEvent.end(); 774 } 775 776 private void initPopupZoomer(Context context) { 777 mPopupZoomer = new PopupZoomer(context); 778 mPopupZoomer.setOnVisibilityChangedListener(new PopupZoomer.OnVisibilityChangedListener() { 779 @Override 780 public void onPopupZoomerShown(final PopupZoomer zoomer) { 781 mContainerView.post(new Runnable() { 782 @Override 783 public void run() { 784 if (mContainerView.indexOfChild(zoomer) == -1) { 785 mContainerView.addView(zoomer); 786 } else { 787 assert false : "PopupZoomer should never be shown without being hidden"; 788 } 789 } 790 }); 791 } 792 793 @Override 794 public void onPopupZoomerHidden(final PopupZoomer zoomer) { 795 mContainerView.post(new Runnable() { 796 @Override 797 public void run() { 798 if (mContainerView.indexOfChild(zoomer) != -1) { 799 mContainerView.removeView(zoomer); 800 mContainerView.invalidate(); 801 } else { 802 assert false : "PopupZoomer should never be hidden without being shown"; 803 } 804 } 805 }); 806 } 807 }); 808 // TODO(yongsheng): LONG_TAP is not enabled in PopupZoomer. So need to dispatch a LONG_TAP 809 // gesture if a user completes a tap on PopupZoomer UI after a LONG_PRESS gesture. 810 PopupZoomer.OnTapListener listener = new PopupZoomer.OnTapListener() { 811 @Override 812 public boolean onSingleTap(View v, MotionEvent e) { 813 mContainerView.requestFocus(); 814 if (mNativeContentViewCore != 0) { 815 nativeSingleTap(mNativeContentViewCore, e.getEventTime(), e.getX(), e.getY()); 816 } 817 return true; 818 } 819 820 @Override 821 public boolean onLongPress(View v, MotionEvent e) { 822 if (mNativeContentViewCore != 0) { 823 nativeLongPress(mNativeContentViewCore, e.getEventTime(), e.getX(), e.getY()); 824 } 825 return true; 826 } 827 }; 828 mPopupZoomer.setOnTapListener(listener); 829 } 830 831 /** 832 * Destroy the internal state of the ContentView. This method may only be 833 * called after the ContentView has been removed from the view system. No 834 * other methods may be called on this ContentView after this method has 835 * been called. 836 */ 837 public void destroy() { 838 if (mNativeContentViewCore != 0) { 839 nativeOnJavaContentViewCoreDestroyed(mNativeContentViewCore); 840 } 841 mWebContents = null; 842 resetVSyncNotification(); 843 mVSyncProvider = null; 844 if (mViewAndroid != null) mViewAndroid.destroy(); 845 mNativeContentViewCore = 0; 846 mContentSettings = null; 847 mJavaScriptInterfaces.clear(); 848 mRetainedJavaScriptObjects.clear(); 849 unregisterAccessibilityContentObserver(); 850 mGestureStateListeners.clear(); 851 ScreenOrientationListener.getInstance().removeObserver(this); 852 } 853 854 private void unregisterAccessibilityContentObserver() { 855 if (mAccessibilityScriptInjectionObserver == null) { 856 return; 857 } 858 getContext().getContentResolver().unregisterContentObserver( 859 mAccessibilityScriptInjectionObserver); 860 mAccessibilityScriptInjectionObserver = null; 861 } 862 863 /** 864 * Returns true initially, false after destroy() has been called. 865 * It is illegal to call any other public method after destroy(). 866 */ 867 public boolean isAlive() { 868 return mNativeContentViewCore != 0; 869 } 870 871 /** 872 * This is only useful for passing over JNI to native code that requires ContentViewCore*. 873 * @return native ContentViewCore pointer. 874 */ 875 @CalledByNative 876 public long getNativeContentViewCore() { 877 return mNativeContentViewCore; 878 } 879 880 public void setContentViewClient(ContentViewClient client) { 881 if (client == null) { 882 throw new IllegalArgumentException("The client can't be null."); 883 } 884 mContentViewClient = client; 885 } 886 887 ContentViewClient getContentViewClient() { 888 if (mContentViewClient == null) { 889 // We use the Null Object pattern to avoid having to perform a null check in this class. 890 // We create it lazily because most of the time a client will be set almost immediately 891 // after ContentView is created. 892 mContentViewClient = new ContentViewClient(); 893 // We don't set the native ContentViewClient pointer here on purpose. The native 894 // implementation doesn't mind a null delegate and using one is better than passing a 895 // Null Object, since we cut down on the number of JNI calls. 896 } 897 return mContentViewClient; 898 } 899 900 public int getBackgroundColor() { 901 if (mNativeContentViewCore != 0) { 902 return nativeGetBackgroundColor(mNativeContentViewCore); 903 } 904 return Color.WHITE; 905 } 906 907 @CalledByNative 908 private void onBackgroundColorChanged(int color) { 909 getContentViewClient().onBackgroundColorChanged(color); 910 } 911 912 /** 913 * Load url without fixing up the url string. Consumers of ContentView are responsible for 914 * ensuring the URL passed in is properly formatted (i.e. the scheme has been added if left 915 * off during user input). 916 * 917 * @param params Parameters for this load. 918 */ 919 public void loadUrl(LoadUrlParams params) { 920 if (mNativeContentViewCore == 0) return; 921 922 nativeLoadUrl(mNativeContentViewCore, 923 params.mUrl, 924 params.mLoadUrlType, 925 params.mTransitionType, 926 params.mUaOverrideOption, 927 params.getExtraHeadersString(), 928 params.mPostData, 929 params.mBaseUrlForDataUrl, 930 params.mVirtualUrlForDataUrl, 931 params.mCanLoadLocalResources); 932 } 933 934 /** 935 * Stops loading the current web contents. 936 */ 937 public void stopLoading() { 938 if (mNativeContentViewCore != 0) nativeStopLoading(mNativeContentViewCore); 939 } 940 941 /** 942 * Get the URL of the current page. 943 * 944 * @return The URL of the current page. 945 */ 946 public String getUrl() { 947 if (mNativeContentViewCore != 0) return nativeGetURL(mNativeContentViewCore); 948 return null; 949 } 950 951 /** 952 * Get the title of the current page. 953 * 954 * @return The title of the current page. 955 */ 956 public String getTitle() { 957 if (mNativeContentViewCore != 0) return nativeGetTitle(mNativeContentViewCore); 958 return null; 959 } 960 961 /** 962 * Shows an interstitial page driven by the passed in delegate. 963 * 964 * @param url The URL being blocked by the interstitial. 965 * @param delegate The delegate handling the interstitial. 966 */ 967 @VisibleForTesting 968 public void showInterstitialPage( 969 String url, InterstitialPageDelegateAndroid delegate) { 970 if (mNativeContentViewCore == 0) return; 971 nativeShowInterstitialPage(mNativeContentViewCore, url, delegate.getNative()); 972 } 973 974 /** 975 * @return Whether the page is currently showing an interstitial, such as a bad HTTPS page. 976 */ 977 public boolean isShowingInterstitialPage() { 978 return mNativeContentViewCore == 0 ? 979 false : nativeIsShowingInterstitialPage(mNativeContentViewCore); 980 } 981 982 /** 983 * Mark any new frames that have arrived since this function was last called as non-pending. 984 * 985 * @return Whether there was a pending frame from the renderer. 986 */ 987 public boolean consumePendingRendererFrame() { 988 boolean hadPendingFrame = mPendingRendererFrame; 989 mPendingRendererFrame = false; 990 return hadPendingFrame; 991 } 992 993 /** 994 * @return Viewport width in physical pixels as set from onSizeChanged. 995 */ 996 @CalledByNative 997 public int getViewportWidthPix() { return mViewportWidthPix; } 998 999 /** 1000 * @return Viewport height in physical pixels as set from onSizeChanged. 1001 */ 1002 @CalledByNative 1003 public int getViewportHeightPix() { return mViewportHeightPix; } 1004 1005 /** 1006 * @return Width of underlying physical surface. 1007 */ 1008 @CalledByNative 1009 public int getPhysicalBackingWidthPix() { return mPhysicalBackingWidthPix; } 1010 1011 /** 1012 * @return Height of underlying physical surface. 1013 */ 1014 @CalledByNative 1015 public int getPhysicalBackingHeightPix() { return mPhysicalBackingHeightPix; } 1016 1017 /** 1018 * @return Amount the output surface extends past the bottom of the window viewport. 1019 */ 1020 @CalledByNative 1021 public int getOverdrawBottomHeightPix() { return mOverdrawBottomHeightPix; } 1022 1023 /** 1024 * @return The amount to shrink the viewport relative to {@link #getViewportWidthPix()}. 1025 */ 1026 @CalledByNative 1027 public int getViewportSizeOffsetWidthPix() { return mViewportSizeOffsetWidthPix; } 1028 1029 /** 1030 * @return The amount to shrink the viewport relative to {@link #getViewportHeightPix()}. 1031 */ 1032 @CalledByNative 1033 public int getViewportSizeOffsetHeightPix() { return mViewportSizeOffsetHeightPix; } 1034 1035 /** 1036 * @see android.webkit.WebView#getContentHeight() 1037 */ 1038 public float getContentHeightCss() { 1039 return mRenderCoordinates.getContentHeightCss(); 1040 } 1041 1042 /** 1043 * @see android.webkit.WebView#getContentWidth() 1044 */ 1045 public float getContentWidthCss() { 1046 return mRenderCoordinates.getContentWidthCss(); 1047 } 1048 1049 // TODO(teddchoc): Remove all these navigation controller methods from here and have the 1050 // embedders manage it. 1051 /** 1052 * @return Whether the current WebContents has a previous navigation entry. 1053 */ 1054 public boolean canGoBack() { 1055 return mWebContents != null && mWebContents.getNavigationController().canGoBack(); 1056 } 1057 1058 /** 1059 * @return Whether the current WebContents has a navigation entry after the current one. 1060 */ 1061 public boolean canGoForward() { 1062 return mWebContents != null && mWebContents.getNavigationController().canGoForward(); 1063 } 1064 1065 /** 1066 * @param offset The offset into the navigation history. 1067 * @return Whether we can move in history by given offset 1068 */ 1069 public boolean canGoToOffset(int offset) { 1070 return mWebContents != null && 1071 mWebContents.getNavigationController().canGoToOffset(offset); 1072 } 1073 1074 /** 1075 * Navigates to the specified offset from the "current entry". Does nothing if the offset is out 1076 * of bounds. 1077 * @param offset The offset into the navigation history. 1078 */ 1079 public void goToOffset(int offset) { 1080 if (mWebContents != null) mWebContents.getNavigationController().goToOffset(offset); 1081 } 1082 1083 @Override 1084 public void goToNavigationIndex(int index) { 1085 if (mWebContents != null) { 1086 mWebContents.getNavigationController().goToNavigationIndex(index); 1087 } 1088 } 1089 1090 /** 1091 * Goes to the navigation entry before the current one. 1092 */ 1093 public void goBack() { 1094 if (mWebContents != null) mWebContents.getNavigationController().goBack(); 1095 } 1096 1097 /** 1098 * Goes to the navigation entry following the current one. 1099 */ 1100 public void goForward() { 1101 if (mWebContents != null) mWebContents.getNavigationController().goForward(); 1102 } 1103 1104 /** 1105 * Loads the current navigation if there is a pending lazy load (after tab restore). 1106 */ 1107 public void loadIfNecessary() { 1108 if (mNativeContentViewCore != 0) nativeLoadIfNecessary(mNativeContentViewCore); 1109 } 1110 1111 /** 1112 * Requests the current navigation to be loaded upon the next call to loadIfNecessary(). 1113 */ 1114 public void requestRestoreLoad() { 1115 if (mNativeContentViewCore != 0) nativeRequestRestoreLoad(mNativeContentViewCore); 1116 } 1117 1118 /** 1119 * Reload the current page. 1120 */ 1121 public void reload(boolean checkForRepost) { 1122 mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary(); 1123 if (mNativeContentViewCore != 0) { 1124 nativeReload(mNativeContentViewCore, checkForRepost); 1125 } 1126 } 1127 1128 /** 1129 * Reload the current page, ignoring the contents of the cache. 1130 */ 1131 public void reloadIgnoringCache(boolean checkForRepost) { 1132 mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary(); 1133 if (mNativeContentViewCore != 0) { 1134 nativeReloadIgnoringCache(mNativeContentViewCore, checkForRepost); 1135 } 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 /** 1161 * @return The selected text (empty if no text selected). 1162 */ 1163 public String getSelectedText() { 1164 return mHasSelection ? mLastSelectedText : ""; 1165 } 1166 1167 /** 1168 * @return Whether the current selection is editable (false if no text selected). 1169 */ 1170 public boolean isSelectionEditable() { 1171 return mHasSelection ? mSelectionEditable : false; 1172 } 1173 1174 // End FrameLayout overrides. 1175 1176 /** 1177 * @see View#onTouchEvent(MotionEvent) 1178 */ 1179 public boolean onTouchEvent(MotionEvent event) { 1180 cancelRequestToScrollFocusedEditableNodeIntoView(); 1181 1182 if (!mRequestedVSyncForInput) { 1183 mRequestedVSyncForInput = true; 1184 addVSyncSubscriber(); 1185 } 1186 1187 final int eventAction = event.getActionMasked(); 1188 1189 // Only these actions have any effect on gesture detection. Other 1190 // actions have no corresponding WebTouchEvent type and may confuse the 1191 // touch pipline, so we ignore them entirely. 1192 if (eventAction != MotionEvent.ACTION_DOWN 1193 && eventAction != MotionEvent.ACTION_UP 1194 && eventAction != MotionEvent.ACTION_CANCEL 1195 && eventAction != MotionEvent.ACTION_MOVE 1196 && eventAction != MotionEvent.ACTION_POINTER_DOWN 1197 && eventAction != MotionEvent.ACTION_POINTER_UP) { 1198 return false; 1199 } 1200 1201 if (mNativeContentViewCore == 0) return false; 1202 final int pointerCount = event.getPointerCount(); 1203 return nativeOnTouchEvent(mNativeContentViewCore, event, 1204 event.getEventTime(), eventAction, 1205 pointerCount, event.getHistorySize(), event.getActionIndex(), 1206 event.getX(), event.getY(), 1207 pointerCount > 1 ? event.getX(1) : 0, 1208 pointerCount > 1 ? event.getY(1) : 0, 1209 event.getPointerId(0), pointerCount > 1 ? event.getPointerId(1) : -1, 1210 event.getTouchMajor(), pointerCount > 1 ? event.getTouchMajor(1) : 0); 1211 } 1212 1213 public void setIgnoreRemainingTouchEvents() { 1214 if (mNativeContentViewCore == 0) return; 1215 nativeIgnoreRemainingTouchEvents(mNativeContentViewCore); 1216 } 1217 1218 public boolean isScrollInProgress() { 1219 return mTouchScrollInProgress || mPotentiallyActiveFlingCount > 0; 1220 } 1221 1222 @SuppressWarnings("unused") 1223 @CalledByNative 1224 private void onFlingStartEventConsumed(int vx, int vy) { 1225 mTouchScrollInProgress = false; 1226 mPotentiallyActiveFlingCount++; 1227 temporarilyHideTextHandles(); 1228 for (mGestureStateListenersIterator.rewind(); 1229 mGestureStateListenersIterator.hasNext();) { 1230 mGestureStateListenersIterator.next().onFlingStartGesture( 1231 vx, vy, computeVerticalScrollOffset(), computeVerticalScrollExtent()); 1232 } 1233 } 1234 1235 @SuppressWarnings("unused") 1236 @CalledByNative 1237 private void onFlingStartEventHadNoConsumer(int vx, int vy) { 1238 mTouchScrollInProgress = false; 1239 for (mGestureStateListenersIterator.rewind(); 1240 mGestureStateListenersIterator.hasNext();) { 1241 mGestureStateListenersIterator.next().onUnhandledFlingStartEvent(vx, vy); 1242 } 1243 } 1244 1245 @SuppressWarnings("unused") 1246 @CalledByNative 1247 private void onFlingCancelEventAck() { 1248 updateGestureStateListener(GestureEventType.FLING_CANCEL); 1249 } 1250 1251 @SuppressWarnings("unused") 1252 @CalledByNative 1253 private void onScrollBeginEventAck() { 1254 mTouchScrollInProgress = true; 1255 temporarilyHideTextHandles(); 1256 mZoomControlsDelegate.invokeZoomPicker(); 1257 updateGestureStateListener(GestureEventType.SCROLL_START); 1258 } 1259 1260 @SuppressWarnings("unused") 1261 @CalledByNative 1262 private void onScrollUpdateGestureConsumed() { 1263 mZoomControlsDelegate.invokeZoomPicker(); 1264 for (mGestureStateListenersIterator.rewind(); 1265 mGestureStateListenersIterator.hasNext();) { 1266 mGestureStateListenersIterator.next().onScrollUpdateGestureConsumed(); 1267 } 1268 } 1269 1270 @SuppressWarnings("unused") 1271 @CalledByNative 1272 private void onScrollEndEventAck() { 1273 if (!mTouchScrollInProgress) return; 1274 mTouchScrollInProgress = false; 1275 updateGestureStateListener(GestureEventType.SCROLL_END); 1276 } 1277 1278 @SuppressWarnings("unused") 1279 @CalledByNative 1280 private void onPinchBeginEventAck() { 1281 temporarilyHideTextHandles(); 1282 updateGestureStateListener(GestureEventType.PINCH_BEGIN); 1283 } 1284 1285 @SuppressWarnings("unused") 1286 @CalledByNative 1287 private void onPinchEndEventAck() { 1288 updateGestureStateListener(GestureEventType.PINCH_END); 1289 } 1290 1291 @SuppressWarnings("unused") 1292 @CalledByNative 1293 private void onDoubleTapEventAck() { 1294 temporarilyHideTextHandles(); 1295 } 1296 1297 /** 1298 * Called just prior to a tap or press gesture being forwarded to the renderer. 1299 */ 1300 @SuppressWarnings("unused") 1301 @CalledByNative 1302 private boolean filterTapOrPressEvent(int type, int x, int y) { 1303 if (type == GestureEventType.LONG_PRESS && offerLongPressToEmbedder()) { 1304 return true; 1305 } 1306 updateForTapOrPress(type, x, y); 1307 return false; 1308 } 1309 1310 @VisibleForTesting 1311 public void sendDoubleTapForTest(long timeMs, int x, int y) { 1312 if (mNativeContentViewCore == 0) return; 1313 nativeDoubleTap(mNativeContentViewCore, timeMs, x, y); 1314 } 1315 1316 @VisibleForTesting 1317 public void flingForTest(long timeMs, int x, int y, int velocityX, int velocityY) { 1318 if (mNativeContentViewCore == 0) return; 1319 nativeFlingCancel(mNativeContentViewCore, timeMs); 1320 nativeScrollBegin(mNativeContentViewCore, timeMs, x, y, velocityX, velocityY); 1321 nativeFlingStart(mNativeContentViewCore, timeMs, x, y, velocityX, velocityY); 1322 } 1323 1324 /** 1325 * Add a listener that gets alerted on gesture state changes. 1326 * @param listener Listener to add. 1327 */ 1328 public void addGestureStateListener(GestureStateListener listener) { 1329 mGestureStateListeners.addObserver(listener); 1330 } 1331 1332 /** 1333 * Removes a listener that was added to watch for gesture state changes. 1334 * @param listener Listener to remove. 1335 */ 1336 public void removeGestureStateListener(GestureStateListener listener) { 1337 mGestureStateListeners.removeObserver(listener); 1338 } 1339 1340 void updateGestureStateListener(int gestureType) { 1341 for (mGestureStateListenersIterator.rewind(); 1342 mGestureStateListenersIterator.hasNext();) { 1343 GestureStateListener listener = mGestureStateListenersIterator.next(); 1344 switch (gestureType) { 1345 case GestureEventType.PINCH_BEGIN: 1346 listener.onPinchStarted(); 1347 break; 1348 case GestureEventType.PINCH_END: 1349 listener.onPinchEnded(); 1350 break; 1351 case GestureEventType.FLING_END: 1352 listener.onFlingEndGesture( 1353 computeVerticalScrollOffset(), 1354 computeVerticalScrollExtent()); 1355 break; 1356 case GestureEventType.FLING_CANCEL: 1357 listener.onFlingCancelGesture(); 1358 break; 1359 case GestureEventType.SCROLL_START: 1360 listener.onScrollStarted( 1361 computeVerticalScrollOffset(), 1362 computeVerticalScrollExtent()); 1363 break; 1364 case GestureEventType.SCROLL_END: 1365 listener.onScrollEnded( 1366 computeVerticalScrollOffset(), 1367 computeVerticalScrollExtent()); 1368 break; 1369 default: 1370 break; 1371 } 1372 } 1373 } 1374 1375 /** Callback interface for evaluateJavaScript(). */ 1376 public interface JavaScriptCallback { 1377 void handleJavaScriptResult(String jsonResult); 1378 } 1379 1380 /** 1381 * Injects the passed Javascript code in the current page and evaluates it. 1382 * If a result is required, pass in a callback. 1383 * Used in automation tests. 1384 * 1385 * @param script The Javascript to execute. 1386 * @param callback The callback to be fired off when a result is ready. The script's 1387 * result will be json encoded and passed as the parameter, and the call 1388 * will be made on the main thread. 1389 * If no result is required, pass null. 1390 */ 1391 public void evaluateJavaScript(String script, JavaScriptCallback callback) { 1392 if (mNativeContentViewCore == 0) return; 1393 nativeEvaluateJavaScript(mNativeContentViewCore, script, callback, false); 1394 } 1395 1396 /** 1397 * Injects the passed Javascript code in the current page and evaluates it. 1398 * If there is no page existing, a new one will be created. 1399 * 1400 * @param script The Javascript to execute. 1401 */ 1402 public void evaluateJavaScriptEvenIfNotYetNavigated(String script) { 1403 if (mNativeContentViewCore == 0) return; 1404 nativeEvaluateJavaScript(mNativeContentViewCore, script, null, true); 1405 } 1406 1407 /** 1408 * To be called when the ContentView is shown. 1409 */ 1410 public void onShow() { 1411 assert mNativeContentViewCore != 0; 1412 if (!mInForeground) { 1413 ChildProcessLauncher.getBindingManager().setInForeground(getCurrentRenderProcessId(), 1414 true); 1415 } 1416 mInForeground = true; 1417 nativeOnShow(mNativeContentViewCore); 1418 setAccessibilityState(mAccessibilityManager.isEnabled()); 1419 } 1420 1421 /** 1422 * @return The ID of the renderer process that backs this tab or 1423 * {@link #INVALID_RENDER_PROCESS_PID} if there is none. 1424 */ 1425 public int getCurrentRenderProcessId() { 1426 return nativeGetCurrentRenderProcessId(mNativeContentViewCore); 1427 } 1428 1429 /** 1430 * To be called when the ContentView is hidden. 1431 */ 1432 public void onHide() { 1433 assert mNativeContentViewCore != 0; 1434 if (mInForeground) { 1435 ChildProcessLauncher.getBindingManager().setInForeground(getCurrentRenderProcessId(), 1436 false); 1437 } 1438 mInForeground = false; 1439 hidePopupDialog(); 1440 setInjectedAccessibility(false); 1441 nativeOnHide(mNativeContentViewCore); 1442 } 1443 1444 /** 1445 * Return the ContentSettings object used to retrieve the settings for this 1446 * ContentViewCore. For modifications, ChromeNativePreferences is to be used. 1447 * @return A ContentSettings object that can be used to retrieve this 1448 * ContentViewCore's settings. 1449 */ 1450 public ContentSettings getContentSettings() { 1451 return mContentSettings; 1452 } 1453 1454 private void onRenderCoordinatesUpdated() { 1455 if (mNativeContentViewCore == 0) return; 1456 1457 // We disable double tap zoom for pages that have a width=device-width 1458 // or narrower viewport (indicating that this is a mobile-optimized or 1459 // responsive web design, so text will be legible without zooming). 1460 // We also disable it for pages that disallow the user from zooming in 1461 // or out (even if they don't have a device-width or narrower viewport). 1462 nativeSetDoubleTapSupportForPageEnabled(mNativeContentViewCore, 1463 !mRenderCoordinates.hasMobileViewport() && !mRenderCoordinates.hasFixedPageScale()); 1464 } 1465 1466 private void hidePopupDialog() { 1467 if (mSelectPopupDialog != null) { 1468 mSelectPopupDialog.hide(); 1469 mSelectPopupDialog = null; 1470 } 1471 hideHandles(); 1472 hideSelectActionBar(); 1473 } 1474 1475 void hideSelectActionBar() { 1476 if (mActionMode != null) { 1477 mActionMode.finish(); 1478 mActionMode = null; 1479 } 1480 } 1481 1482 public boolean isSelectActionBarShowing() { 1483 return mActionMode != null; 1484 } 1485 1486 private void resetGestureDetectors() { 1487 if (mNativeContentViewCore == 0) return; 1488 nativeResetGestureDetectors(mNativeContentViewCore); 1489 } 1490 1491 /** 1492 * @see View#onAttachedToWindow() 1493 */ 1494 @SuppressWarnings("javadoc") 1495 public void onAttachedToWindow() { 1496 setAccessibilityState(mAccessibilityManager.isEnabled()); 1497 1498 ScreenOrientationListener.getInstance().addObserver(this, mContext); 1499 } 1500 1501 /** 1502 * @see View#onDetachedFromWindow() 1503 */ 1504 @SuppressWarnings("javadoc") 1505 @SuppressLint("MissingSuperCall") 1506 public void onDetachedFromWindow() { 1507 setInjectedAccessibility(false); 1508 hidePopupDialog(); 1509 mZoomControlsDelegate.dismissZoomPicker(); 1510 unregisterAccessibilityContentObserver(); 1511 1512 ScreenOrientationListener.getInstance().removeObserver(this); 1513 } 1514 1515 /** 1516 * @see View#onVisibilityChanged(android.view.View, int) 1517 */ 1518 public void onVisibilityChanged(View changedView, int visibility) { 1519 if (visibility != View.VISIBLE) { 1520 mZoomControlsDelegate.dismissZoomPicker(); 1521 } 1522 } 1523 1524 /** 1525 * @see View#onCreateInputConnection(EditorInfo) 1526 */ 1527 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 1528 if (!mImeAdapter.hasTextInputType()) { 1529 // Although onCheckIsTextEditor will return false in this case, the EditorInfo 1530 // is still used by the InputMethodService. Need to make sure the IME doesn't 1531 // enter fullscreen mode. 1532 outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN; 1533 } 1534 mInputConnection = mAdapterInputConnectionFactory.get(mContainerView, mImeAdapter, 1535 mEditable, outAttrs); 1536 return mInputConnection; 1537 } 1538 1539 @VisibleForTesting 1540 public AdapterInputConnection getAdapterInputConnectionForTest() { 1541 return mInputConnection; 1542 } 1543 1544 @VisibleForTesting 1545 public Editable getEditableForTest() { 1546 return mEditable; 1547 } 1548 1549 /** 1550 * @see View#onCheckIsTextEditor() 1551 */ 1552 public boolean onCheckIsTextEditor() { 1553 return mImeAdapter.hasTextInputType(); 1554 } 1555 1556 /** 1557 * @see View#onConfigurationChanged(Configuration) 1558 */ 1559 @SuppressWarnings("javadoc") 1560 public void onConfigurationChanged(Configuration newConfig) { 1561 TraceEvent.begin(); 1562 1563 if (newConfig.keyboard != Configuration.KEYBOARD_NOKEYS) { 1564 mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore), 1565 ImeAdapter.getTextInputTypeNone()); 1566 mInputMethodManagerWrapper.restartInput(mContainerView); 1567 } 1568 mContainerViewInternals.super_onConfigurationChanged(newConfig); 1569 1570 // To request layout has side effect, but it seems OK as it only happen in 1571 // onConfigurationChange and layout has to be changed in most case. 1572 mContainerView.requestLayout(); 1573 TraceEvent.end(); 1574 } 1575 1576 /** 1577 * @see View#onSizeChanged(int, int, int, int) 1578 */ 1579 @SuppressWarnings("javadoc") 1580 public void onSizeChanged(int wPix, int hPix, int owPix, int ohPix) { 1581 if (getViewportWidthPix() == wPix && getViewportHeightPix() == hPix) return; 1582 1583 mViewportWidthPix = wPix; 1584 mViewportHeightPix = hPix; 1585 if (mNativeContentViewCore != 0) { 1586 nativeWasResized(mNativeContentViewCore); 1587 } 1588 1589 updateAfterSizeChanged(); 1590 } 1591 1592 /** 1593 * Called when the ContentView's position in the activity window changed. This information is 1594 * used for cropping screenshots. 1595 */ 1596 public void onLocationInWindowChanged(int x, int y) { 1597 mLocationInWindowX = x; 1598 mLocationInWindowY = y; 1599 } 1600 1601 /** 1602 * Called when the underlying surface the compositor draws to changes size. 1603 * This may be larger than the viewport size. 1604 */ 1605 public void onPhysicalBackingSizeChanged(int wPix, int hPix) { 1606 if (mPhysicalBackingWidthPix == wPix && mPhysicalBackingHeightPix == hPix) return; 1607 1608 mPhysicalBackingWidthPix = wPix; 1609 mPhysicalBackingHeightPix = hPix; 1610 1611 if (mNativeContentViewCore != 0) { 1612 nativeWasResized(mNativeContentViewCore); 1613 } 1614 } 1615 1616 /** 1617 * Called when the amount the surface is overdrawing off the bottom has changed. 1618 * @param overdrawHeightPix The overdraw height. 1619 */ 1620 public void onOverdrawBottomHeightChanged(int overdrawHeightPix) { 1621 if (mOverdrawBottomHeightPix == overdrawHeightPix) return; 1622 1623 mOverdrawBottomHeightPix = overdrawHeightPix; 1624 1625 if (mNativeContentViewCore != 0) { 1626 nativeWasResized(mNativeContentViewCore); 1627 } 1628 } 1629 1630 private void updateAfterSizeChanged() { 1631 mPopupZoomer.hide(false); 1632 1633 // Execute a delayed form focus operation because the OSK was brought 1634 // up earlier. 1635 if (!mFocusPreOSKViewportRect.isEmpty()) { 1636 Rect rect = new Rect(); 1637 getContainerView().getWindowVisibleDisplayFrame(rect); 1638 if (!rect.equals(mFocusPreOSKViewportRect)) { 1639 // Only assume the OSK triggered the onSizeChanged if width was preserved. 1640 if (rect.width() == mFocusPreOSKViewportRect.width()) { 1641 scrollFocusedEditableNodeIntoView(); 1642 } 1643 cancelRequestToScrollFocusedEditableNodeIntoView(); 1644 } 1645 } 1646 } 1647 1648 private void cancelRequestToScrollFocusedEditableNodeIntoView() { 1649 // Zero-ing the rect will prevent |updateAfterSizeChanged()| from 1650 // issuing the delayed form focus event. 1651 mFocusPreOSKViewportRect.setEmpty(); 1652 } 1653 1654 private void scrollFocusedEditableNodeIntoView() { 1655 if (mNativeContentViewCore == 0) return; 1656 // The native side keeps track of whether the zoom and scroll actually occurred. It is 1657 // more efficient to do it this way and sometimes fire an unnecessary message rather 1658 // than synchronize with the renderer and always have an additional message. 1659 nativeScrollFocusedEditableNodeIntoView(mNativeContentViewCore); 1660 } 1661 1662 /** 1663 * @see View#onWindowFocusChanged(boolean) 1664 */ 1665 public void onWindowFocusChanged(boolean hasWindowFocus) { 1666 if (!hasWindowFocus) { 1667 if (mNativeContentViewCore == 0) return; 1668 nativeOnWindowFocusLost(mNativeContentViewCore); 1669 } 1670 } 1671 1672 public void onFocusChanged(boolean gainFocus) { 1673 if (!gainFocus) { 1674 hideImeIfNeeded(); 1675 } 1676 if (mNativeContentViewCore != 0) nativeSetFocus(mNativeContentViewCore, gainFocus); 1677 } 1678 1679 /** 1680 * @see View#onKeyUp(int, KeyEvent) 1681 */ 1682 public boolean onKeyUp(int keyCode, KeyEvent event) { 1683 if (mPopupZoomer.isShowing() && keyCode == KeyEvent.KEYCODE_BACK) { 1684 mPopupZoomer.hide(true); 1685 return true; 1686 } 1687 return mContainerViewInternals.super_onKeyUp(keyCode, event); 1688 } 1689 1690 /** 1691 * @see View#dispatchKeyEventPreIme(KeyEvent) 1692 */ 1693 public boolean dispatchKeyEventPreIme(KeyEvent event) { 1694 try { 1695 TraceEvent.begin(); 1696 return mContainerViewInternals.super_dispatchKeyEventPreIme(event); 1697 } finally { 1698 TraceEvent.end(); 1699 } 1700 } 1701 1702 /** 1703 * @see View#dispatchKeyEvent(KeyEvent) 1704 */ 1705 public boolean dispatchKeyEvent(KeyEvent event) { 1706 if (getContentViewClient().shouldOverrideKeyEvent(event)) { 1707 return mContainerViewInternals.super_dispatchKeyEvent(event); 1708 } 1709 1710 if (mImeAdapter.dispatchKeyEvent(event)) return true; 1711 1712 return mContainerViewInternals.super_dispatchKeyEvent(event); 1713 } 1714 1715 /** 1716 * @see View#onHoverEvent(MotionEvent) 1717 * Mouse move events are sent on hover enter, hover move and hover exit. 1718 * They are sent on hover exit because sometimes it acts as both a hover 1719 * move and hover exit. 1720 */ 1721 public boolean onHoverEvent(MotionEvent event) { 1722 TraceEvent.begin("onHoverEvent"); 1723 1724 if (mBrowserAccessibilityManager != null) { 1725 return mBrowserAccessibilityManager.onHoverEvent(event); 1726 } 1727 1728 // Work around Android bug where the x, y coordinates of a hover exit 1729 // event are incorrect when touch exploration is on. 1730 if (mTouchExplorationEnabled && event.getAction() == MotionEvent.ACTION_HOVER_EXIT) { 1731 return true; 1732 } 1733 1734 mContainerView.removeCallbacks(mFakeMouseMoveRunnable); 1735 if (mNativeContentViewCore != 0) { 1736 nativeSendMouseMoveEvent(mNativeContentViewCore, event.getEventTime(), 1737 event.getX(), event.getY()); 1738 } 1739 TraceEvent.end("onHoverEvent"); 1740 return true; 1741 } 1742 1743 /** 1744 * @see View#onGenericMotionEvent(MotionEvent) 1745 */ 1746 public boolean onGenericMotionEvent(MotionEvent event) { 1747 if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { 1748 switch (event.getAction()) { 1749 case MotionEvent.ACTION_SCROLL: 1750 nativeSendMouseWheelEvent(mNativeContentViewCore, event.getEventTime(), 1751 event.getX(), event.getY(), 1752 event.getAxisValue(MotionEvent.AXIS_VSCROLL)); 1753 1754 mContainerView.removeCallbacks(mFakeMouseMoveRunnable); 1755 // Send a delayed onMouseMove event so that we end 1756 // up hovering over the right position after the scroll. 1757 final MotionEvent eventFakeMouseMove = MotionEvent.obtain(event); 1758 mFakeMouseMoveRunnable = new Runnable() { 1759 @Override 1760 public void run() { 1761 onHoverEvent(eventFakeMouseMove); 1762 } 1763 }; 1764 mContainerView.postDelayed(mFakeMouseMoveRunnable, 250); 1765 return true; 1766 } 1767 } 1768 return mContainerViewInternals.super_onGenericMotionEvent(event); 1769 } 1770 1771 /** 1772 * @see View#scrollBy(int, int) 1773 * Currently the ContentView scrolling happens in the native side. In 1774 * the Java view system, it is always pinned at (0, 0). scrollBy() and scrollTo() 1775 * are overridden, so that View's mScrollX and mScrollY will be unchanged at 1776 * (0, 0). This is critical for drawing ContentView correctly. 1777 */ 1778 public void scrollBy(int xPix, int yPix) { 1779 if (mNativeContentViewCore != 0) { 1780 nativeScrollBy(mNativeContentViewCore, 1781 SystemClock.uptimeMillis(), 0, 0, xPix, yPix); 1782 } 1783 } 1784 1785 /** 1786 * @see View#scrollTo(int, int) 1787 */ 1788 public void scrollTo(int xPix, int yPix) { 1789 if (mNativeContentViewCore == 0) return; 1790 final float xCurrentPix = mRenderCoordinates.getScrollXPix(); 1791 final float yCurrentPix = mRenderCoordinates.getScrollYPix(); 1792 final float dxPix = xPix - xCurrentPix; 1793 final float dyPix = yPix - yCurrentPix; 1794 if (dxPix != 0 || dyPix != 0) { 1795 long time = SystemClock.uptimeMillis(); 1796 nativeScrollBegin(mNativeContentViewCore, time, 1797 xCurrentPix, yCurrentPix, -dxPix, -dyPix); 1798 nativeScrollBy(mNativeContentViewCore, 1799 time, xCurrentPix, yCurrentPix, dxPix, dyPix); 1800 nativeScrollEnd(mNativeContentViewCore, time); 1801 } 1802 } 1803 1804 // NOTE: this can go away once ContentView.getScrollX() reports correct values. 1805 // see: b/6029133 1806 public int getNativeScrollXForTest() { 1807 return mRenderCoordinates.getScrollXPixInt(); 1808 } 1809 1810 // NOTE: this can go away once ContentView.getScrollY() reports correct values. 1811 // see: b/6029133 1812 public int getNativeScrollYForTest() { 1813 return mRenderCoordinates.getScrollYPixInt(); 1814 } 1815 1816 /** 1817 * @see View#computeHorizontalScrollExtent() 1818 */ 1819 @SuppressWarnings("javadoc") 1820 public int computeHorizontalScrollExtent() { 1821 return mRenderCoordinates.getLastFrameViewportWidthPixInt(); 1822 } 1823 1824 /** 1825 * @see View#computeHorizontalScrollOffset() 1826 */ 1827 @SuppressWarnings("javadoc") 1828 public int computeHorizontalScrollOffset() { 1829 return mRenderCoordinates.getScrollXPixInt(); 1830 } 1831 1832 /** 1833 * @see View#computeHorizontalScrollRange() 1834 */ 1835 @SuppressWarnings("javadoc") 1836 public int computeHorizontalScrollRange() { 1837 return mRenderCoordinates.getContentWidthPixInt(); 1838 } 1839 1840 /** 1841 * @see View#computeVerticalScrollExtent() 1842 */ 1843 @SuppressWarnings("javadoc") 1844 public int computeVerticalScrollExtent() { 1845 return mRenderCoordinates.getLastFrameViewportHeightPixInt(); 1846 } 1847 1848 /** 1849 * @see View#computeVerticalScrollOffset() 1850 */ 1851 @SuppressWarnings("javadoc") 1852 public int computeVerticalScrollOffset() { 1853 return mRenderCoordinates.getScrollYPixInt(); 1854 } 1855 1856 /** 1857 * @see View#computeVerticalScrollRange() 1858 */ 1859 @SuppressWarnings("javadoc") 1860 public int computeVerticalScrollRange() { 1861 return mRenderCoordinates.getContentHeightPixInt(); 1862 } 1863 1864 // End FrameLayout overrides. 1865 1866 /** 1867 * @see View#awakenScrollBars(int, boolean) 1868 */ 1869 @SuppressWarnings("javadoc") 1870 public boolean awakenScrollBars(int startDelay, boolean invalidate) { 1871 // For the default implementation of ContentView which draws the scrollBars on the native 1872 // side, calling this function may get us into a bad state where we keep drawing the 1873 // scrollBars, so disable it by always returning false. 1874 if (mContainerView.getScrollBarStyle() == View.SCROLLBARS_INSIDE_OVERLAY) { 1875 return false; 1876 } else { 1877 return mContainerViewInternals.super_awakenScrollBars(startDelay, invalidate); 1878 } 1879 } 1880 1881 private void updateForTapOrPress(int type, float xPix, float yPix) { 1882 if (type != GestureEventType.SINGLE_TAP_CONFIRMED 1883 && type != GestureEventType.SINGLE_TAP_UP 1884 && type != GestureEventType.LONG_PRESS 1885 && type != GestureEventType.LONG_TAP) { 1886 return; 1887 } 1888 1889 if (mContainerView.isFocusable() && mContainerView.isFocusableInTouchMode() 1890 && !mContainerView.isFocused()) { 1891 mContainerView.requestFocus(); 1892 } 1893 1894 if (!mPopupZoomer.isShowing()) mPopupZoomer.setLastTouch(xPix, yPix); 1895 1896 if (type == GestureEventType.LONG_PRESS 1897 || type == GestureEventType.LONG_TAP) { 1898 getInsertionHandleController().allowAutomaticShowing(); 1899 getSelectionHandleController().allowAutomaticShowing(); 1900 } else { 1901 setClickXAndY((int) xPix, (int) yPix); 1902 if (mSelectionEditable) getInsertionHandleController().allowAutomaticShowing(); 1903 } 1904 } 1905 1906 private void setClickXAndY(int x, int y) { 1907 mSingleTapX = x; 1908 mSingleTapY = y; 1909 } 1910 1911 /** 1912 * @return The x coordinate for the last point that a singleTap gesture was initiated from. 1913 */ 1914 public int getSingleTapX() { 1915 return mSingleTapX; 1916 } 1917 1918 /** 1919 * @return The y coordinate for the last point that a singleTap gesture was initiated from. 1920 */ 1921 public int getSingleTapY() { 1922 return mSingleTapY; 1923 } 1924 1925 public void setZoomControlsDelegate(ZoomControlsDelegate zoomControlsDelegate) { 1926 mZoomControlsDelegate = zoomControlsDelegate; 1927 } 1928 1929 public void updateMultiTouchZoomSupport(boolean supportsMultiTouchZoom) { 1930 if (mNativeContentViewCore == 0) return; 1931 nativeSetMultiTouchZoomSupportEnabled(mNativeContentViewCore, supportsMultiTouchZoom); 1932 } 1933 1934 public void updateDoubleTapSupport(boolean supportsDoubleTap) { 1935 if (mNativeContentViewCore == 0) return; 1936 nativeSetDoubleTapSupportEnabled(mNativeContentViewCore, supportsDoubleTap); 1937 } 1938 1939 public void selectPopupMenuItems(int[] indices) { 1940 if (mNativeContentViewCore != 0) { 1941 nativeSelectPopupMenuItems(mNativeContentViewCore, indices); 1942 } 1943 mSelectPopupDialog = null; 1944 } 1945 1946 /** 1947 * Send the screen orientation value to the renderer. 1948 */ 1949 @VisibleForTesting 1950 void sendOrientationChangeEvent(int orientation) { 1951 if (mNativeContentViewCore == 0) return; 1952 1953 nativeSendOrientationChangeEvent(mNativeContentViewCore, orientation); 1954 } 1955 1956 /** 1957 * Register the delegate to be used when content can not be handled by 1958 * the rendering engine, and should be downloaded instead. This will replace 1959 * the current delegate, if any. 1960 * @param delegate An implementation of ContentViewDownloadDelegate. 1961 */ 1962 public void setDownloadDelegate(ContentViewDownloadDelegate delegate) { 1963 mDownloadDelegate = delegate; 1964 } 1965 1966 // Called by DownloadController. 1967 ContentViewDownloadDelegate getDownloadDelegate() { 1968 return mDownloadDelegate; 1969 } 1970 1971 private SelectionHandleController getSelectionHandleController() { 1972 if (mSelectionHandleController == null) { 1973 mSelectionHandleController = new SelectionHandleController( 1974 getContainerView(), mPositionObserver) { 1975 @Override 1976 public void selectBetweenCoordinates(int x1, int y1, int x2, int y2) { 1977 if (mNativeContentViewCore != 0 && !(x1 == x2 && y1 == y2)) { 1978 nativeSelectBetweenCoordinates(mNativeContentViewCore, 1979 x1, y1 - mRenderCoordinates.getContentOffsetYPix(), 1980 x2, y2 - mRenderCoordinates.getContentOffsetYPix()); 1981 } 1982 } 1983 1984 @Override 1985 public void showHandles(int startDir, int endDir) { 1986 super.showHandles(startDir, endDir); 1987 showSelectActionBar(); 1988 } 1989 1990 }; 1991 1992 mSelectionHandleController.hideAndDisallowAutomaticShowing(); 1993 updateInsertionSelectionVisibleBounds(); 1994 } 1995 1996 return mSelectionHandleController; 1997 } 1998 1999 private InsertionHandleController getInsertionHandleController() { 2000 if (mInsertionHandleController == null) { 2001 mInsertionHandleController = new InsertionHandleController( 2002 getContainerView(), mPositionObserver) { 2003 private static final int AVERAGE_LINE_HEIGHT = 14; 2004 2005 @Override 2006 public void setCursorPosition(int x, int y) { 2007 if (mNativeContentViewCore != 0) { 2008 nativeMoveCaret(mNativeContentViewCore, 2009 x, y - mRenderCoordinates.getContentOffsetYPix()); 2010 } 2011 } 2012 2013 @Override 2014 public void paste() { 2015 mImeAdapter.paste(); 2016 hideHandles(); 2017 } 2018 2019 @Override 2020 public int getLineHeight() { 2021 return (int) Math.ceil( 2022 mRenderCoordinates.fromLocalCssToPix(AVERAGE_LINE_HEIGHT)); 2023 } 2024 2025 @Override 2026 public void showHandle() { 2027 super.showHandle(); 2028 } 2029 }; 2030 2031 mInsertionHandleController.hideAndDisallowAutomaticShowing(); 2032 updateInsertionSelectionVisibleBounds(); 2033 } 2034 2035 return mInsertionHandleController; 2036 } 2037 2038 @VisibleForTesting 2039 public InsertionHandleController getInsertionHandleControllerForTest() { 2040 return mInsertionHandleController; 2041 } 2042 2043 @VisibleForTesting 2044 public SelectionHandleController getSelectionHandleControllerForTest() { 2045 return mSelectionHandleController; 2046 } 2047 2048 private void updateHandleScreenPositions() { 2049 if (isSelectionHandleShowing()) { 2050 mSelectionHandleController.setStartHandlePosition( 2051 mStartHandlePoint.getXPix(), mStartHandlePoint.getYPix()); 2052 mSelectionHandleController.setEndHandlePosition( 2053 mEndHandlePoint.getXPix(), mEndHandlePoint.getYPix()); 2054 } 2055 2056 if (isInsertionHandleShowing()) { 2057 mInsertionHandleController.setHandlePosition( 2058 mInsertionHandlePoint.getXPix(), mInsertionHandlePoint.getYPix()); 2059 } 2060 } 2061 2062 private void hideHandles() { 2063 if (mSelectionHandleController != null) { 2064 mSelectionHandleController.hideAndDisallowAutomaticShowing(); 2065 } 2066 if (mInsertionHandleController != null) { 2067 mInsertionHandleController.hideAndDisallowAutomaticShowing(); 2068 } 2069 mPositionObserver.removeListener(mPositionListener); 2070 } 2071 2072 private void showSelectActionBar() { 2073 if (mActionMode != null) { 2074 mActionMode.invalidate(); 2075 return; 2076 } 2077 2078 // Start a new action mode with a SelectActionModeCallback. 2079 SelectActionModeCallback.ActionHandler actionHandler = 2080 new SelectActionModeCallback.ActionHandler() { 2081 @Override 2082 public void selectAll() { 2083 mImeAdapter.selectAll(); 2084 } 2085 2086 @Override 2087 public void cut() { 2088 mImeAdapter.cut(); 2089 } 2090 2091 @Override 2092 public void copy() { 2093 mImeAdapter.copy(); 2094 } 2095 2096 @Override 2097 public void paste() { 2098 mImeAdapter.paste(); 2099 } 2100 2101 @Override 2102 public void share() { 2103 final String query = getSelectedText(); 2104 if (TextUtils.isEmpty(query)) return; 2105 2106 Intent send = new Intent(Intent.ACTION_SEND); 2107 send.setType("text/plain"); 2108 send.putExtra(Intent.EXTRA_TEXT, query); 2109 try { 2110 Intent i = Intent.createChooser(send, getContext().getString( 2111 R.string.actionbar_share)); 2112 i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2113 getContext().startActivity(i); 2114 } catch (android.content.ActivityNotFoundException ex) { 2115 // If no app handles it, do nothing. 2116 } 2117 } 2118 2119 @Override 2120 public void search() { 2121 final String query = getSelectedText(); 2122 if (TextUtils.isEmpty(query)) return; 2123 2124 // See if ContentViewClient wants to override 2125 if (getContentViewClient().doesPerformWebSearch()) { 2126 getContentViewClient().performWebSearch(query); 2127 return; 2128 } 2129 2130 Intent i = new Intent(Intent.ACTION_WEB_SEARCH); 2131 i.putExtra(SearchManager.EXTRA_NEW_SEARCH, true); 2132 i.putExtra(SearchManager.QUERY, query); 2133 i.putExtra(Browser.EXTRA_APPLICATION_ID, getContext().getPackageName()); 2134 if (!(getContext() instanceof Activity)) { 2135 i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2136 } 2137 try { 2138 getContext().startActivity(i); 2139 } catch (android.content.ActivityNotFoundException ex) { 2140 // If no app handles it, do nothing. 2141 } 2142 } 2143 2144 @Override 2145 public boolean isSelectionEditable() { 2146 return mSelectionEditable; 2147 } 2148 2149 @Override 2150 public void onDestroyActionMode() { 2151 mActionMode = null; 2152 if (mUnselectAllOnActionModeDismiss) mImeAdapter.unselect(); 2153 getContentViewClient().onContextualActionBarHidden(); 2154 } 2155 2156 @Override 2157 public boolean isShareAvailable() { 2158 Intent intent = new Intent(Intent.ACTION_SEND); 2159 intent.setType("text/plain"); 2160 return getContext().getPackageManager().queryIntentActivities(intent, 2161 PackageManager.MATCH_DEFAULT_ONLY).size() > 0; 2162 } 2163 2164 @Override 2165 public boolean isWebSearchAvailable() { 2166 if (getContentViewClient().doesPerformWebSearch()) return true; 2167 Intent intent = new Intent(Intent.ACTION_WEB_SEARCH); 2168 intent.putExtra(SearchManager.EXTRA_NEW_SEARCH, true); 2169 return getContext().getPackageManager().queryIntentActivities(intent, 2170 PackageManager.MATCH_DEFAULT_ONLY).size() > 0; 2171 } 2172 }; 2173 mActionMode = null; 2174 // On ICS, startActionMode throws an NPE when getParent() is null. 2175 if (mContainerView.getParent() != null) { 2176 mActionMode = mContainerView.startActionMode( 2177 getContentViewClient().getSelectActionModeCallback(getContext(), actionHandler, 2178 nativeIsIncognito(mNativeContentViewCore))); 2179 } 2180 mUnselectAllOnActionModeDismiss = true; 2181 if (mActionMode == null) { 2182 // There is no ActionMode, so remove the selection. 2183 mImeAdapter.unselect(); 2184 } else { 2185 getContentViewClient().onContextualActionBarShown(); 2186 } 2187 } 2188 2189 public boolean getUseDesktopUserAgent() { 2190 if (mNativeContentViewCore != 0) { 2191 return nativeGetUseDesktopUserAgent(mNativeContentViewCore); 2192 } 2193 return false; 2194 } 2195 2196 /** 2197 * Set whether or not we're using a desktop user agent for the currently loaded page. 2198 * @param override If true, use a desktop user agent. Use a mobile one otherwise. 2199 * @param reloadOnChange Reload the page if the UA has changed. 2200 */ 2201 public void setUseDesktopUserAgent(boolean override, boolean reloadOnChange) { 2202 if (mNativeContentViewCore != 0) { 2203 nativeSetUseDesktopUserAgent(mNativeContentViewCore, override, reloadOnChange); 2204 } 2205 } 2206 2207 public void clearSslPreferences() { 2208 nativeClearSslPreferences(mNativeContentViewCore); 2209 } 2210 2211 private boolean isSelectionHandleShowing() { 2212 return mSelectionHandleController != null && mSelectionHandleController.isShowing(); 2213 } 2214 2215 private boolean isInsertionHandleShowing() { 2216 return mInsertionHandleController != null && mInsertionHandleController.isShowing(); 2217 } 2218 2219 // Makes the insertion/selection handles invisible. They will fade back in shortly after the 2220 // last call to scheduleTextHandleFadeIn (or temporarilyHideTextHandles). 2221 private void temporarilyHideTextHandles() { 2222 if (isSelectionHandleShowing() && !mSelectionHandleController.isDragging()) { 2223 mSelectionHandleController.setHandleVisibility(HandleView.INVISIBLE); 2224 } 2225 if (isInsertionHandleShowing() && !mInsertionHandleController.isDragging()) { 2226 mInsertionHandleController.setHandleVisibility(HandleView.INVISIBLE); 2227 } 2228 scheduleTextHandleFadeIn(); 2229 } 2230 2231 private boolean allowTextHandleFadeIn() { 2232 if (mTouchScrollInProgress) return false; 2233 2234 if (mPopupZoomer.isShowing()) return false; 2235 2236 return true; 2237 } 2238 2239 // Cancels any pending fade in and schedules a new one. 2240 private void scheduleTextHandleFadeIn() { 2241 if (!isInsertionHandleShowing() && !isSelectionHandleShowing()) return; 2242 2243 if (mDeferredHandleFadeInRunnable == null) { 2244 mDeferredHandleFadeInRunnable = new Runnable() { 2245 @Override 2246 public void run() { 2247 if (!allowTextHandleFadeIn()) { 2248 // Delay fade in until it is allowed. 2249 scheduleTextHandleFadeIn(); 2250 } else { 2251 if (isSelectionHandleShowing()) { 2252 mSelectionHandleController.beginHandleFadeIn(); 2253 } 2254 if (isInsertionHandleShowing()) { 2255 mInsertionHandleController.beginHandleFadeIn(); 2256 } 2257 } 2258 } 2259 }; 2260 } 2261 2262 mContainerView.removeCallbacks(mDeferredHandleFadeInRunnable); 2263 mContainerView.postDelayed(mDeferredHandleFadeInRunnable, TEXT_HANDLE_FADE_IN_DELAY); 2264 } 2265 2266 /** 2267 * Shows the IME if the focused widget could accept text input. 2268 */ 2269 public void showImeIfNeeded() { 2270 if (mNativeContentViewCore != 0) nativeShowImeIfNeeded(mNativeContentViewCore); 2271 } 2272 2273 /** 2274 * Hides the IME if the containerView is the active view for IME. 2275 */ 2276 public void hideImeIfNeeded() { 2277 // Hide input method window from the current view synchronously 2278 // because ImeAdapter does so asynchronouly with a delay, and 2279 // by the time when ImeAdapter dismisses the input, the 2280 // containerView may have lost focus. 2281 // We cannot trust ContentViewClient#onImeStateChangeRequested to 2282 // hide the input window because it has an empty default implementation. 2283 // So we need to explicitly hide the input method window here. 2284 if (mInputMethodManagerWrapper.isActive(mContainerView)) { 2285 mInputMethodManagerWrapper.hideSoftInputFromWindow( 2286 mContainerView.getWindowToken(), 0, null); 2287 } 2288 getContentViewClient().onImeStateChangeRequested(false); 2289 } 2290 2291 @SuppressWarnings("unused") 2292 @CalledByNative 2293 private void updateFrameInfo( 2294 float scrollOffsetX, float scrollOffsetY, 2295 float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor, 2296 float contentWidth, float contentHeight, 2297 float viewportWidth, float viewportHeight, 2298 float controlsOffsetYCss, float contentOffsetYCss, 2299 float overdrawBottomHeightCss) { 2300 TraceEvent.instant("ContentViewCore:updateFrameInfo"); 2301 // Adjust contentWidth/Height to be always at least as big as 2302 // the actual viewport (as set by onSizeChanged). 2303 final float deviceScale = mRenderCoordinates.getDeviceScaleFactor(); 2304 contentWidth = Math.max(contentWidth, 2305 mViewportWidthPix / (deviceScale * pageScaleFactor)); 2306 contentHeight = Math.max(contentHeight, 2307 mViewportHeightPix / (deviceScale * pageScaleFactor)); 2308 final float contentOffsetYPix = mRenderCoordinates.fromDipToPix(contentOffsetYCss); 2309 2310 final boolean contentSizeChanged = 2311 contentWidth != mRenderCoordinates.getContentWidthCss() 2312 || contentHeight != mRenderCoordinates.getContentHeightCss(); 2313 final boolean scaleLimitsChanged = 2314 minPageScaleFactor != mRenderCoordinates.getMinPageScaleFactor() 2315 || maxPageScaleFactor != mRenderCoordinates.getMaxPageScaleFactor(); 2316 final boolean pageScaleChanged = 2317 pageScaleFactor != mRenderCoordinates.getPageScaleFactor(); 2318 final boolean scrollChanged = 2319 pageScaleChanged 2320 || scrollOffsetX != mRenderCoordinates.getScrollX() 2321 || scrollOffsetY != mRenderCoordinates.getScrollY(); 2322 final boolean contentOffsetChanged = 2323 contentOffsetYPix != mRenderCoordinates.getContentOffsetYPix(); 2324 2325 final boolean needHidePopupZoomer = contentSizeChanged || scrollChanged; 2326 final boolean needUpdateZoomControls = scaleLimitsChanged || scrollChanged; 2327 final boolean needTemporarilyHideHandles = scrollChanged; 2328 2329 if (needHidePopupZoomer) mPopupZoomer.hide(true); 2330 2331 if (scrollChanged) { 2332 mContainerViewInternals.onScrollChanged( 2333 (int) mRenderCoordinates.fromLocalCssToPix(scrollOffsetX), 2334 (int) mRenderCoordinates.fromLocalCssToPix(scrollOffsetY), 2335 (int) mRenderCoordinates.getScrollXPix(), 2336 (int) mRenderCoordinates.getScrollYPix()); 2337 } 2338 2339 mRenderCoordinates.updateFrameInfo( 2340 scrollOffsetX, scrollOffsetY, 2341 contentWidth, contentHeight, 2342 viewportWidth, viewportHeight, 2343 pageScaleFactor, minPageScaleFactor, maxPageScaleFactor, 2344 contentOffsetYPix); 2345 onRenderCoordinatesUpdated(); 2346 2347 if (scrollChanged || contentOffsetChanged) { 2348 for (mGestureStateListenersIterator.rewind(); 2349 mGestureStateListenersIterator.hasNext();) { 2350 mGestureStateListenersIterator.next().onScrollOffsetOrExtentChanged( 2351 computeVerticalScrollOffset(), 2352 computeVerticalScrollExtent()); 2353 } 2354 } 2355 2356 if (needTemporarilyHideHandles) temporarilyHideTextHandles(); 2357 if (needUpdateZoomControls) mZoomControlsDelegate.updateZoomControls(); 2358 if (contentOffsetChanged) updateHandleScreenPositions(); 2359 2360 // Update offsets for fullscreen. 2361 final float controlsOffsetPix = controlsOffsetYCss * deviceScale; 2362 final float overdrawBottomHeightPix = overdrawBottomHeightCss * deviceScale; 2363 getContentViewClient().onOffsetsForFullscreenChanged( 2364 controlsOffsetPix, contentOffsetYPix, overdrawBottomHeightPix); 2365 2366 mPendingRendererFrame = true; 2367 if (mBrowserAccessibilityManager != null) { 2368 mBrowserAccessibilityManager.notifyFrameInfoInitialized(); 2369 } 2370 } 2371 2372 @CalledByNative 2373 private void updateImeAdapter(long nativeImeAdapterAndroid, int textInputType, 2374 String text, int selectionStart, int selectionEnd, 2375 int compositionStart, int compositionEnd, boolean showImeIfNeeded, 2376 boolean isNonImeChange) { 2377 TraceEvent.begin(); 2378 mSelectionEditable = (textInputType != ImeAdapter.getTextInputTypeNone()); 2379 2380 if (mActionMode != null) mActionMode.invalidate(); 2381 2382 mImeAdapter.attachAndShowIfNeeded(nativeImeAdapterAndroid, textInputType, showImeIfNeeded); 2383 2384 if (mInputConnection != null) { 2385 mInputConnection.updateState(text, selectionStart, selectionEnd, compositionStart, 2386 compositionEnd, isNonImeChange); 2387 } 2388 TraceEvent.end(); 2389 } 2390 2391 @SuppressWarnings("unused") 2392 @CalledByNative 2393 private void setTitle(String title) { 2394 getContentViewClient().onUpdateTitle(title); 2395 } 2396 2397 /** 2398 * Called (from native) when the <select> popup needs to be shown. 2399 * @param items Items to show. 2400 * @param enabled POPUP_ITEM_TYPEs for items. 2401 * @param multiple Whether the popup menu should support multi-select. 2402 * @param selectedIndices Indices of selected items. 2403 */ 2404 @SuppressWarnings("unused") 2405 @CalledByNative 2406 private void showSelectPopup(String[] items, int[] enabled, boolean multiple, 2407 int[] selectedIndices) { 2408 if (mContainerView.getParent() == null || mContainerView.getVisibility() != View.VISIBLE) { 2409 selectPopupMenuItems(null); 2410 return; 2411 } 2412 2413 hideSelectPopup(); 2414 assert items.length == enabled.length; 2415 List<SelectPopupItem> popupItems = new ArrayList<SelectPopupItem>(); 2416 for (int i = 0; i < items.length; i++) { 2417 popupItems.add(new SelectPopupItem(items[i], enabled[i])); 2418 } 2419 mSelectPopupDialog = SelectPopupDialog.show(this, popupItems, multiple, selectedIndices); 2420 } 2421 2422 /** 2423 * Called when the <select> popup needs to be hidden. 2424 */ 2425 @CalledByNative 2426 private void hideSelectPopup() { 2427 if (mSelectPopupDialog != null) { 2428 mSelectPopupDialog.hide(); 2429 mSelectPopupDialog = null; 2430 } 2431 } 2432 2433 /** 2434 * @return The visible select popup dialog being shown. 2435 */ 2436 public SelectPopupDialog getSelectPopupForTest() { 2437 return mSelectPopupDialog; 2438 } 2439 2440 @SuppressWarnings("unused") 2441 @CalledByNative 2442 private void showDisambiguationPopup(Rect targetRect, Bitmap zoomedBitmap) { 2443 mPopupZoomer.setBitmap(zoomedBitmap); 2444 mPopupZoomer.show(targetRect); 2445 temporarilyHideTextHandles(); 2446 } 2447 2448 @SuppressWarnings("unused") 2449 @CalledByNative 2450 private TouchEventSynthesizer createTouchEventSynthesizer() { 2451 return new TouchEventSynthesizer(this); 2452 } 2453 2454 @SuppressWarnings("unused") 2455 @CalledByNative 2456 private void onSelectionChanged(String text) { 2457 mLastSelectedText = text; 2458 getContentViewClient().onSelectionChanged(text); 2459 } 2460 2461 @SuppressWarnings("unused") 2462 @CalledByNative 2463 private void onSelectionBoundsChanged(Rect anchorRectDip, int anchorDir, Rect focusRectDip, 2464 int focusDir, boolean isAnchorFirst) { 2465 // All coordinates are in DIP. 2466 int x1 = anchorRectDip.left; 2467 int y1 = anchorRectDip.bottom; 2468 int x2 = focusRectDip.left; 2469 int y2 = focusRectDip.bottom; 2470 2471 if (x1 != x2 || y1 != y2 || 2472 (mSelectionHandleController != null && mSelectionHandleController.isDragging())) { 2473 if (mInsertionHandleController != null) { 2474 mInsertionHandleController.hide(); 2475 } 2476 if (isAnchorFirst) { 2477 mStartHandlePoint.setLocalDip(x1, y1); 2478 mEndHandlePoint.setLocalDip(x2, y2); 2479 } else { 2480 mStartHandlePoint.setLocalDip(x2, y2); 2481 mEndHandlePoint.setLocalDip(x1, y1); 2482 } 2483 2484 boolean wereSelectionHandlesShowing = getSelectionHandleController().isShowing(); 2485 2486 getSelectionHandleController().onSelectionChanged(anchorDir, focusDir); 2487 updateHandleScreenPositions(); 2488 mHasSelection = true; 2489 2490 if (!wereSelectionHandlesShowing && getSelectionHandleController().isShowing()) { 2491 // TODO(cjhopman): Remove this when there is a better signal that long press caused 2492 // a selection. See http://crbug.com/150151. 2493 mContainerView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 2494 } 2495 2496 } else { 2497 mUnselectAllOnActionModeDismiss = false; 2498 hideSelectActionBar(); 2499 if (x1 != 0 && y1 != 0 && mSelectionEditable) { 2500 // Selection is a caret, and a text field is focused. 2501 if (mSelectionHandleController != null) { 2502 mSelectionHandleController.hide(); 2503 } 2504 mInsertionHandlePoint.setLocalDip(x1, y1); 2505 2506 getInsertionHandleController().onCursorPositionChanged(); 2507 updateHandleScreenPositions(); 2508 if (mInputMethodManagerWrapper.isWatchingCursor(mContainerView)) { 2509 final int xPix = (int) mInsertionHandlePoint.getXPix(); 2510 final int yPix = (int) mInsertionHandlePoint.getYPix(); 2511 mInputMethodManagerWrapper.updateCursor( 2512 mContainerView, xPix, yPix, xPix, yPix); 2513 } 2514 } else { 2515 // Deselection 2516 if (mSelectionHandleController != null) { 2517 mSelectionHandleController.hideAndDisallowAutomaticShowing(); 2518 } 2519 if (mInsertionHandleController != null) { 2520 mInsertionHandleController.hideAndDisallowAutomaticShowing(); 2521 } 2522 } 2523 mHasSelection = false; 2524 } 2525 if (isSelectionHandleShowing() || isInsertionHandleShowing()) { 2526 mPositionObserver.addListener(mPositionListener); 2527 } 2528 } 2529 2530 @CalledByNative 2531 private void setSelectionRootBounds(Rect bounds) { 2532 mTopLeftVisibilityClippingPoint.setLocalDip(bounds.left, bounds.top); 2533 mBottomRightVisibilityClippingPoint.setLocalDip(bounds.right, bounds.bottom); 2534 updateInsertionSelectionVisibleBounds(); 2535 } 2536 2537 private void updateInsertionSelectionVisibleBounds() { 2538 if (mSelectionHandleController == null && mInsertionHandleController == null) { 2539 return; 2540 } 2541 2542 int x1 = Math.round(mTopLeftVisibilityClippingPoint.getXPix()); 2543 int y1 = Math.round(mTopLeftVisibilityClippingPoint.getYPix()); 2544 int x2 = Math.round(mBottomRightVisibilityClippingPoint.getXPix()); 2545 int y2 = Math.round(mBottomRightVisibilityClippingPoint.getYPix()); 2546 2547 if (mSelectionHandleController != null) { 2548 mSelectionHandleController.setVisibleClippingRectangle(x1, y1, x2, y2); 2549 } 2550 2551 if (mInsertionHandleController != null) { 2552 mInsertionHandleController.setVisibleClippingRectangle(x1, y1, x2, y2); 2553 } 2554 } 2555 2556 @SuppressWarnings("unused") 2557 @CalledByNative 2558 private static void onEvaluateJavaScriptResult( 2559 String jsonResult, JavaScriptCallback callback) { 2560 callback.handleJavaScriptResult(jsonResult); 2561 } 2562 2563 @SuppressWarnings("unused") 2564 @CalledByNative 2565 private void showPastePopup(int xDip, int yDip) { 2566 mInsertionHandlePoint.setLocalDip(xDip, yDip); 2567 getInsertionHandleController().showHandle(); 2568 updateHandleScreenPositions(); 2569 getInsertionHandleController().showHandleWithPastePopup(); 2570 } 2571 2572 @SuppressWarnings("unused") 2573 @CalledByNative 2574 private void onRenderProcessSwap(int oldPid, int newPid) { 2575 if (!mInForeground) { 2576 ChildProcessLauncher.getBindingManager().setInForeground(newPid, false); 2577 } else if (oldPid != newPid) { 2578 ChildProcessLauncher.getBindingManager().setInForeground(oldPid, false); 2579 ChildProcessLauncher.getBindingManager().setInForeground(newPid, true); 2580 } 2581 2582 attachImeAdapter(); 2583 } 2584 2585 @SuppressWarnings("unused") 2586 @CalledByNative 2587 private void onWebContentsConnected() { 2588 attachImeAdapter(); 2589 } 2590 2591 /** 2592 * Attaches the native ImeAdapter object to the java ImeAdapter to allow communication via JNI. 2593 */ 2594 public void attachImeAdapter() { 2595 if (mImeAdapter != null && mNativeContentViewCore != 0) { 2596 mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore)); 2597 } 2598 } 2599 2600 /** 2601 * @see View#hasFocus() 2602 */ 2603 @CalledByNative 2604 public boolean hasFocus() { 2605 return mContainerView.hasFocus(); 2606 } 2607 2608 /** 2609 * Checks whether the ContentViewCore can be zoomed in. 2610 * 2611 * @return True if the ContentViewCore can be zoomed in. 2612 */ 2613 // This method uses the term 'zoom' for legacy reasons, but relates 2614 // to what chrome calls the 'page scale factor'. 2615 public boolean canZoomIn() { 2616 final float zoomInExtent = mRenderCoordinates.getMaxPageScaleFactor() 2617 - mRenderCoordinates.getPageScaleFactor(); 2618 return zoomInExtent > ZOOM_CONTROLS_EPSILON; 2619 } 2620 2621 /** 2622 * Checks whether the ContentViewCore can be zoomed out. 2623 * 2624 * @return True if the ContentViewCore can be zoomed out. 2625 */ 2626 // This method uses the term 'zoom' for legacy reasons, but relates 2627 // to what chrome calls the 'page scale factor'. 2628 public boolean canZoomOut() { 2629 final float zoomOutExtent = mRenderCoordinates.getPageScaleFactor() 2630 - mRenderCoordinates.getMinPageScaleFactor(); 2631 return zoomOutExtent > ZOOM_CONTROLS_EPSILON; 2632 } 2633 2634 /** 2635 * Zooms in the ContentViewCore by 25% (or less if that would result in 2636 * zooming in more than possible). 2637 * 2638 * @return True if there was a zoom change, false otherwise. 2639 */ 2640 // This method uses the term 'zoom' for legacy reasons, but relates 2641 // to what chrome calls the 'page scale factor'. 2642 public boolean zoomIn() { 2643 if (!canZoomIn()) { 2644 return false; 2645 } 2646 return pinchByDelta(1.25f); 2647 } 2648 2649 /** 2650 * Zooms out the ContentViewCore by 20% (or less if that would result in 2651 * zooming out more than possible). 2652 * 2653 * @return True if there was a zoom change, false otherwise. 2654 */ 2655 // This method uses the term 'zoom' for legacy reasons, but relates 2656 // to what chrome calls the 'page scale factor'. 2657 public boolean zoomOut() { 2658 if (!canZoomOut()) { 2659 return false; 2660 } 2661 return pinchByDelta(0.8f); 2662 } 2663 2664 /** 2665 * Resets the zoom factor of the ContentViewCore. 2666 * 2667 * @return True if there was a zoom change, false otherwise. 2668 */ 2669 // This method uses the term 'zoom' for legacy reasons, but relates 2670 // to what chrome calls the 'page scale factor'. 2671 public boolean zoomReset() { 2672 // The page scale factor is initialized to mNativeMinimumScale when 2673 // the page finishes loading. Thus sets it back to mNativeMinimumScale. 2674 if (!canZoomOut()) return false; 2675 return pinchByDelta( 2676 mRenderCoordinates.getMinPageScaleFactor() 2677 / mRenderCoordinates.getPageScaleFactor()); 2678 } 2679 2680 /** 2681 * Simulate a pinch zoom gesture. 2682 * 2683 * @param delta the factor by which the current page scale should be multiplied by. 2684 * @return whether the gesture was sent. 2685 */ 2686 public boolean pinchByDelta(float delta) { 2687 if (mNativeContentViewCore == 0) return false; 2688 2689 long timeMs = SystemClock.uptimeMillis(); 2690 int xPix = getViewportWidthPix() / 2; 2691 int yPix = getViewportHeightPix() / 2; 2692 2693 nativePinchBegin(mNativeContentViewCore, timeMs, xPix, yPix); 2694 nativePinchBy(mNativeContentViewCore, timeMs, xPix, yPix, delta); 2695 nativePinchEnd(mNativeContentViewCore, timeMs); 2696 2697 return true; 2698 } 2699 2700 /** 2701 * Invokes the graphical zoom picker widget for this ContentView. 2702 */ 2703 public void invokeZoomPicker() { 2704 mZoomControlsDelegate.invokeZoomPicker(); 2705 } 2706 2707 /** 2708 * Enables or disables inspection of JavaScript objects added via 2709 * {@link #addJavascriptInterface(Object, String)} by means of Object.keys() method and 2710 * "for .. in" loop. Being able to inspect JavaScript objects is useful 2711 * when debugging hybrid Android apps, but can't be enabled for legacy applications due 2712 * to compatibility risks. 2713 * 2714 * @param allow Whether to allow JavaScript objects inspection. 2715 */ 2716 public void setAllowJavascriptInterfacesInspection(boolean allow) { 2717 nativeSetAllowJavascriptInterfacesInspection(mNativeContentViewCore, allow); 2718 } 2719 2720 /** 2721 * This will mimic {@link #addPossiblyUnsafeJavascriptInterface(Object, String, Class)} 2722 * and automatically pass in {@link JavascriptInterface} as the required annotation. 2723 * 2724 * @param object The Java object to inject into the ContentViewCore's JavaScript context. Null 2725 * values are ignored. 2726 * @param name The name used to expose the instance in JavaScript. 2727 */ 2728 public void addJavascriptInterface(Object object, String name) { 2729 addPossiblyUnsafeJavascriptInterface(object, name, JavascriptInterface.class); 2730 } 2731 2732 /** 2733 * This method injects the supplied Java object into the ContentViewCore. 2734 * The object is injected into the JavaScript context of the main frame, 2735 * using the supplied name. This allows the Java object to be accessed from 2736 * JavaScript. Note that that injected objects will not appear in 2737 * JavaScript until the page is next (re)loaded. For example: 2738 * <pre> view.addJavascriptInterface(new Object(), "injectedObject"); 2739 * view.loadData("<!DOCTYPE html><title></title>", "text/html", null); 2740 * view.loadUrl("javascript:alert(injectedObject.toString())");</pre> 2741 * <p><strong>IMPORTANT:</strong> 2742 * <ul> 2743 * <li> addJavascriptInterface() can be used to allow JavaScript to control 2744 * the host application. This is a powerful feature, but also presents a 2745 * security risk. Use of this method in a ContentViewCore containing 2746 * untrusted content could allow an attacker to manipulate the host 2747 * application in unintended ways, executing Java code with the permissions 2748 * of the host application. Use extreme care when using this method in a 2749 * ContentViewCore which could contain untrusted content. Particular care 2750 * should be taken to avoid unintentional access to inherited methods, such 2751 * as {@link Object#getClass()}. To prevent access to inherited methods, 2752 * pass an annotation for {@code requiredAnnotation}. This will ensure 2753 * that only methods with {@code requiredAnnotation} are exposed to the 2754 * Javascript layer. {@code requiredAnnotation} will be passed to all 2755 * subsequently injected Java objects if any methods return an object. This 2756 * means the same restrictions (or lack thereof) will apply. Alternatively, 2757 * {@link #addJavascriptInterface(Object, String)} can be called, which 2758 * automatically uses the {@link JavascriptInterface} annotation. 2759 * <li> JavaScript interacts with Java objects on a private, background 2760 * thread of the ContentViewCore. Care is therefore required to maintain 2761 * thread safety.</li> 2762 * </ul></p> 2763 * 2764 * @param object The Java object to inject into the 2765 * ContentViewCore's JavaScript context. Null 2766 * values are ignored. 2767 * @param name The name used to expose the instance in 2768 * JavaScript. 2769 * @param requiredAnnotation Restrict exposed methods to ones with this 2770 * annotation. If {@code null} all methods are 2771 * exposed. 2772 * 2773 */ 2774 public void addPossiblyUnsafeJavascriptInterface(Object object, String name, 2775 Class<? extends Annotation> requiredAnnotation) { 2776 if (mNativeContentViewCore != 0 && object != null) { 2777 mJavaScriptInterfaces.put(name, object); 2778 nativeAddJavascriptInterface(mNativeContentViewCore, object, name, requiredAnnotation, 2779 mRetainedJavaScriptObjects); 2780 } 2781 } 2782 2783 /** 2784 * Removes a previously added JavaScript interface with the given name. 2785 * 2786 * @param name The name of the interface to remove. 2787 */ 2788 public void removeJavascriptInterface(String name) { 2789 mJavaScriptInterfaces.remove(name); 2790 if (mNativeContentViewCore != 0) { 2791 nativeRemoveJavascriptInterface(mNativeContentViewCore, name); 2792 } 2793 } 2794 2795 /** 2796 * Return the current scale of the ContentView. 2797 * @return The current page scale factor. 2798 */ 2799 public float getScale() { 2800 return mRenderCoordinates.getPageScaleFactor(); 2801 } 2802 2803 /** 2804 * If the view is ready to draw contents to the screen. In hardware mode, 2805 * the initialization of the surface texture may not occur until after the 2806 * view has been added to the layout. This method will return {@code true} 2807 * once the texture is actually ready. 2808 */ 2809 public boolean isReady() { 2810 if (mNativeContentViewCore == 0) return false; 2811 return nativeIsRenderWidgetHostViewReady(mNativeContentViewCore); 2812 } 2813 2814 @CalledByNative 2815 private void startContentIntent(String contentUrl) { 2816 getContentViewClient().onStartContentIntent(getContext(), contentUrl); 2817 } 2818 2819 @Override 2820 public void onAccessibilityStateChanged(boolean enabled) { 2821 setAccessibilityState(enabled); 2822 } 2823 2824 /** 2825 * Determines whether or not this ContentViewCore can handle this accessibility action. 2826 * @param action The action to perform. 2827 * @return Whether or not this action is supported. 2828 */ 2829 public boolean supportsAccessibilityAction(int action) { 2830 return mAccessibilityInjector.supportsAccessibilityAction(action); 2831 } 2832 2833 /** 2834 * Attempts to perform an accessibility action on the web content. If the accessibility action 2835 * cannot be processed, it returns {@code null}, allowing the caller to know to call the 2836 * super {@link View#performAccessibilityAction(int, Bundle)} method and use that return value. 2837 * Otherwise the return value from this method should be used. 2838 * @param action The action to perform. 2839 * @param arguments Optional action arguments. 2840 * @return Whether the action was performed or {@code null} if the call should be delegated to 2841 * the super {@link View} class. 2842 */ 2843 public boolean performAccessibilityAction(int action, Bundle arguments) { 2844 if (mAccessibilityInjector.supportsAccessibilityAction(action)) { 2845 return mAccessibilityInjector.performAccessibilityAction(action, arguments); 2846 } 2847 2848 return false; 2849 } 2850 2851 /** 2852 * Set the BrowserAccessibilityManager, used for native accessibility 2853 * (not script injection). This is only set when system accessibility 2854 * has been enabled. 2855 * @param manager The new BrowserAccessibilityManager. 2856 */ 2857 public void setBrowserAccessibilityManager(BrowserAccessibilityManager manager) { 2858 mBrowserAccessibilityManager = manager; 2859 } 2860 2861 /** 2862 * Get the BrowserAccessibilityManager, used for native accessibility 2863 * (not script injection). This will return null when system accessibility 2864 * is not enabled. 2865 * @return This view's BrowserAccessibilityManager. 2866 */ 2867 public BrowserAccessibilityManager getBrowserAccessibilityManager() { 2868 return mBrowserAccessibilityManager; 2869 } 2870 2871 /** 2872 * If native accessibility (not script injection) is enabled, and if this is 2873 * running on JellyBean or later, returns an AccessibilityNodeProvider that 2874 * implements native accessibility for this view. Returns null otherwise. 2875 * Lazily initializes native accessibility here if it's allowed. 2876 * @return The AccessibilityNodeProvider, if available, or null otherwise. 2877 */ 2878 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 2879 if (mBrowserAccessibilityManager != null) { 2880 return mBrowserAccessibilityManager.getAccessibilityNodeProvider(); 2881 } 2882 2883 if (mNativeAccessibilityAllowed && 2884 !mNativeAccessibilityEnabled && 2885 mNativeContentViewCore != 0 && 2886 Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 2887 mNativeAccessibilityEnabled = true; 2888 nativeSetAccessibilityEnabled(mNativeContentViewCore, true); 2889 } 2890 2891 return null; 2892 } 2893 2894 /** 2895 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 2896 */ 2897 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 2898 // Note: this is only used by the script-injecting accessibility code. 2899 mAccessibilityInjector.onInitializeAccessibilityNodeInfo(info); 2900 } 2901 2902 /** 2903 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 2904 */ 2905 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 2906 // Note: this is only used by the script-injecting accessibility code. 2907 event.setClassName(this.getClass().getName()); 2908 2909 // Identify where the top-left of the screen currently points to. 2910 event.setScrollX(mRenderCoordinates.getScrollXPixInt()); 2911 event.setScrollY(mRenderCoordinates.getScrollYPixInt()); 2912 2913 // The maximum scroll values are determined by taking the content dimensions and 2914 // subtracting off the actual dimensions of the ChromeView. 2915 int maxScrollXPix = Math.max(0, mRenderCoordinates.getMaxHorizontalScrollPixInt()); 2916 int maxScrollYPix = Math.max(0, mRenderCoordinates.getMaxVerticalScrollPixInt()); 2917 event.setScrollable(maxScrollXPix > 0 || maxScrollYPix > 0); 2918 2919 // Setting the maximum scroll values requires API level 15 or higher. 2920 final int SDK_VERSION_REQUIRED_TO_SET_SCROLL = 15; 2921 if (Build.VERSION.SDK_INT >= SDK_VERSION_REQUIRED_TO_SET_SCROLL) { 2922 event.setMaxScrollX(maxScrollXPix); 2923 event.setMaxScrollY(maxScrollYPix); 2924 } 2925 } 2926 2927 /** 2928 * Returns whether accessibility script injection is enabled on the device 2929 */ 2930 public boolean isDeviceAccessibilityScriptInjectionEnabled() { 2931 try { 2932 if (!CommandLine.getInstance().hasSwitch( 2933 ContentSwitches.ENABLE_ACCESSIBILITY_SCRIPT_INJECTION)) { 2934 return false; 2935 } 2936 2937 if (!mContentSettings.getJavaScriptEnabled()) { 2938 return false; 2939 } 2940 2941 int result = getContext().checkCallingOrSelfPermission( 2942 android.Manifest.permission.INTERNET); 2943 if (result != PackageManager.PERMISSION_GRANTED) { 2944 return false; 2945 } 2946 2947 Field field = Settings.Secure.class.getField("ACCESSIBILITY_SCRIPT_INJECTION"); 2948 field.setAccessible(true); 2949 String accessibilityScriptInjection = (String) field.get(null); 2950 ContentResolver contentResolver = getContext().getContentResolver(); 2951 2952 if (mAccessibilityScriptInjectionObserver == null) { 2953 ContentObserver contentObserver = new ContentObserver(new Handler()) { 2954 @Override 2955 public void onChange(boolean selfChange, Uri uri) { 2956 setAccessibilityState(mAccessibilityManager.isEnabled()); 2957 } 2958 }; 2959 contentResolver.registerContentObserver( 2960 Settings.Secure.getUriFor(accessibilityScriptInjection), 2961 false, 2962 contentObserver); 2963 mAccessibilityScriptInjectionObserver = contentObserver; 2964 } 2965 2966 return Settings.Secure.getInt(contentResolver, accessibilityScriptInjection, 0) == 1; 2967 } catch (NoSuchFieldException e) { 2968 // Do nothing, default to false. 2969 } catch (IllegalAccessException e) { 2970 // Do nothing, default to false. 2971 } 2972 return false; 2973 } 2974 2975 /** 2976 * Returns whether or not accessibility injection is being used. 2977 */ 2978 public boolean isInjectingAccessibilityScript() { 2979 return mAccessibilityInjector.accessibilityIsAvailable(); 2980 } 2981 2982 /** 2983 * Turns browser accessibility on or off. 2984 * If |state| is |false|, this turns off both native and injected accessibility. 2985 * Otherwise, if accessibility script injection is enabled, this will enable the injected 2986 * accessibility scripts. Native accessibility is enabled on demand. 2987 */ 2988 public void setAccessibilityState(boolean state) { 2989 if (!state) { 2990 setInjectedAccessibility(false); 2991 mNativeAccessibilityAllowed = false; 2992 mTouchExplorationEnabled = false; 2993 } else { 2994 boolean useScriptInjection = isDeviceAccessibilityScriptInjectionEnabled(); 2995 setInjectedAccessibility(useScriptInjection); 2996 mNativeAccessibilityAllowed = !useScriptInjection; 2997 mTouchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled(); 2998 } 2999 } 3000 3001 /** 3002 * Enable or disable injected accessibility features 3003 */ 3004 public void setInjectedAccessibility(boolean enabled) { 3005 mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary(); 3006 mAccessibilityInjector.setScriptEnabled(enabled); 3007 } 3008 3009 /** 3010 * Stop any TTS notifications that are currently going on. 3011 */ 3012 public void stopCurrentAccessibilityNotifications() { 3013 mAccessibilityInjector.onPageLostFocus(); 3014 } 3015 3016 /** 3017 * Inform WebKit that Fullscreen mode has been exited by the user. 3018 */ 3019 public void exitFullscreen() { 3020 if (mNativeContentViewCore != 0) nativeExitFullscreen(mNativeContentViewCore); 3021 } 3022 3023 /** 3024 * Changes whether hiding the top controls is enabled. 3025 * 3026 * @param enableHiding Whether hiding the top controls should be enabled or not. 3027 * @param enableShowing Whether showing the top controls should be enabled or not. 3028 * @param animate Whether the transition should be animated or not. 3029 */ 3030 public void updateTopControlsState(boolean enableHiding, boolean enableShowing, 3031 boolean animate) { 3032 if (mNativeContentViewCore != 0) { 3033 nativeUpdateTopControlsState( 3034 mNativeContentViewCore, enableHiding, enableShowing, animate); 3035 } 3036 } 3037 3038 /** 3039 * Callback factory method for nativeGetNavigationHistory(). 3040 */ 3041 @CalledByNative 3042 private void addToNavigationHistory(Object history, int index, String url, String virtualUrl, 3043 String originalUrl, String title, Bitmap favicon) { 3044 NavigationEntry entry = new NavigationEntry( 3045 index, url, virtualUrl, originalUrl, title, favicon); 3046 ((NavigationHistory) history).addEntry(entry); 3047 } 3048 3049 /** 3050 * Get a copy of the navigation history of the view. 3051 */ 3052 public NavigationHistory getNavigationHistory() { 3053 NavigationHistory history = new NavigationHistory(); 3054 if (mNativeContentViewCore != 0) { 3055 int currentIndex = nativeGetNavigationHistory(mNativeContentViewCore, history); 3056 history.setCurrentEntryIndex(currentIndex); 3057 } 3058 return history; 3059 } 3060 3061 @Override 3062 public NavigationHistory getDirectedNavigationHistory(boolean isForward, int itemLimit) { 3063 NavigationHistory history = new NavigationHistory(); 3064 if (mNativeContentViewCore != 0) { 3065 nativeGetDirectedNavigationHistory( 3066 mNativeContentViewCore, history, isForward, itemLimit); 3067 } 3068 return history; 3069 } 3070 3071 /** 3072 * @return The original request URL for the current navigation entry, or null if there is no 3073 * current entry. 3074 */ 3075 public String getOriginalUrlForActiveNavigationEntry() { 3076 if (mNativeContentViewCore != 0) { 3077 return nativeGetOriginalUrlForActiveNavigationEntry(mNativeContentViewCore); 3078 } 3079 return ""; 3080 } 3081 3082 /** 3083 * @return The cached copy of render positions and scales. 3084 */ 3085 public RenderCoordinates getRenderCoordinates() { 3086 return mRenderCoordinates; 3087 } 3088 3089 @CalledByNative 3090 private int getLocationInWindowX() { 3091 return mLocationInWindowX; 3092 } 3093 3094 @CalledByNative 3095 private int getLocationInWindowY() { 3096 return mLocationInWindowY; 3097 } 3098 3099 @CalledByNative 3100 private static Rect createRect(int x, int y, int right, int bottom) { 3101 return new Rect(x, y, right, bottom); 3102 } 3103 3104 private boolean onAnimate(long frameTimeMicros) { 3105 if (mNativeContentViewCore == 0) return false; 3106 return nativeOnAnimate(mNativeContentViewCore, frameTimeMicros); 3107 } 3108 3109 private void animateIfNecessary(long frameTimeMicros) { 3110 if (mNeedAnimate) { 3111 mNeedAnimate = onAnimate(frameTimeMicros); 3112 if (!mNeedAnimate) removeVSyncSubscriber(); 3113 } 3114 } 3115 3116 public void extractSmartClipData(int x, int y, int width, int height) { 3117 if (mNativeContentViewCore != 0) { 3118 nativeExtractSmartClipData(mNativeContentViewCore, x, y, width, height); 3119 } 3120 } 3121 3122 @CalledByNative 3123 private void onSmartClipDataExtracted(String result) { 3124 if (mSmartClipDataListener != null ) { 3125 mSmartClipDataListener.onSmartClipDataExtracted(result); 3126 } 3127 } 3128 3129 public void setSmartClipDataListener(SmartClipDataListener listener) { 3130 mSmartClipDataListener = listener; 3131 } 3132 3133 /** 3134 * Offer a long press gesture to the embedding View, primarily for WebView compatibility. 3135 * 3136 * @return true if the embedder handled the event. 3137 */ 3138 private boolean offerLongPressToEmbedder() { 3139 return mContainerView.performLongClick(); 3140 } 3141 3142 /** 3143 * Reset scroll and fling accounting, notifying listeners as appropriate. 3144 * This is useful as a failsafe when the input stream may have been interruped. 3145 */ 3146 private void resetScrollInProgress() { 3147 if (!isScrollInProgress()) return; 3148 3149 final boolean touchScrollInProgress = mTouchScrollInProgress; 3150 final int potentiallyActiveFlingCount = mPotentiallyActiveFlingCount; 3151 3152 mTouchScrollInProgress = false; 3153 mPotentiallyActiveFlingCount = 0; 3154 3155 if (touchScrollInProgress) updateGestureStateListener(GestureEventType.SCROLL_END); 3156 if (potentiallyActiveFlingCount > 0) updateGestureStateListener(GestureEventType.FLING_END); 3157 } 3158 3159 private native long nativeInit(long webContentsPtr, 3160 long viewAndroidPtr, long windowAndroidPtr); 3161 3162 @CalledByNative 3163 private ContentVideoViewClient getContentVideoViewClient() { 3164 return getContentViewClient().getContentVideoViewClient(); 3165 } 3166 3167 @CalledByNative 3168 private boolean shouldBlockMediaRequest(String url) { 3169 return getContentViewClient().shouldBlockMediaRequest(url); 3170 } 3171 3172 @CalledByNative 3173 private void onNativeFlingStopped() { 3174 // Note that mTouchScrollInProgress should normally be false at this 3175 // point, but we reset it anyway as another failsafe. 3176 mTouchScrollInProgress = false; 3177 if (mPotentiallyActiveFlingCount <= 0) return; 3178 mPotentiallyActiveFlingCount--; 3179 updateGestureStateListener(GestureEventType.FLING_END); 3180 } 3181 3182 @Override 3183 public void onScreenOrientationChanged(int orientation) { 3184 sendOrientationChangeEvent(orientation); 3185 } 3186 3187 private native WebContents nativeGetWebContentsAndroid(long nativeContentViewCoreImpl); 3188 3189 private native void nativeOnJavaContentViewCoreDestroyed(long nativeContentViewCoreImpl); 3190 3191 private native void nativeLoadUrl( 3192 long nativeContentViewCoreImpl, 3193 String url, 3194 int loadUrlType, 3195 int transitionType, 3196 int uaOverrideOption, 3197 String extraHeaders, 3198 byte[] postData, 3199 String baseUrlForDataUrl, 3200 String virtualUrlForDataUrl, 3201 boolean canLoadLocalResources); 3202 3203 private native String nativeGetURL(long nativeContentViewCoreImpl); 3204 3205 private native String nativeGetTitle(long nativeContentViewCoreImpl); 3206 3207 private native void nativeShowInterstitialPage( 3208 long nativeContentViewCoreImpl, String url, long nativeInterstitialPageDelegateAndroid); 3209 private native boolean nativeIsShowingInterstitialPage(long nativeContentViewCoreImpl); 3210 3211 private native boolean nativeIsIncognito(long nativeContentViewCoreImpl); 3212 3213 private native void nativeSetFocus(long nativeContentViewCoreImpl, boolean focused); 3214 3215 private native void nativeSendOrientationChangeEvent( 3216 long nativeContentViewCoreImpl, int orientation); 3217 3218 // All touch events (including flings, scrolls etc) accept coordinates in physical pixels. 3219 private native boolean nativeOnTouchEvent( 3220 long nativeContentViewCoreImpl, MotionEvent event, 3221 long timeMs, int action, int pointerCount, int historySize, int actionIndex, 3222 float x0, float y0, float x1, float y1, 3223 int pointerId0, int pointerId1, 3224 float touchMajor0, float touchMajor1); 3225 3226 private native int nativeSendMouseMoveEvent( 3227 long nativeContentViewCoreImpl, long timeMs, float x, float y); 3228 3229 private native int nativeSendMouseWheelEvent( 3230 long nativeContentViewCoreImpl, long timeMs, float x, float y, float verticalAxis); 3231 3232 private native void nativeScrollBegin( 3233 long nativeContentViewCoreImpl, long timeMs, float x, float y, float hintX, 3234 float hintY); 3235 3236 private native void nativeScrollEnd(long nativeContentViewCoreImpl, long timeMs); 3237 3238 private native void nativeScrollBy( 3239 long nativeContentViewCoreImpl, long timeMs, float x, float y, 3240 float deltaX, float deltaY); 3241 3242 private native void nativeFlingStart( 3243 long nativeContentViewCoreImpl, long timeMs, float x, float y, float vx, float vy); 3244 3245 private native void nativeFlingCancel(long nativeContentViewCoreImpl, long timeMs); 3246 3247 private native void nativeSingleTap( 3248 long nativeContentViewCoreImpl, long timeMs, float x, float y); 3249 3250 private native void nativeDoubleTap( 3251 long nativeContentViewCoreImpl, long timeMs, float x, float y); 3252 3253 private native void nativeLongPress( 3254 long nativeContentViewCoreImpl, long timeMs, float x, float y); 3255 3256 private native void nativePinchBegin( 3257 long nativeContentViewCoreImpl, long timeMs, float x, float y); 3258 3259 private native void nativePinchEnd(long nativeContentViewCoreImpl, long timeMs); 3260 3261 private native void nativePinchBy(long nativeContentViewCoreImpl, long timeMs, 3262 float anchorX, float anchorY, float deltaScale); 3263 3264 private native void nativeSelectBetweenCoordinates( 3265 long nativeContentViewCoreImpl, float x1, float y1, float x2, float y2); 3266 3267 private native void nativeMoveCaret(long nativeContentViewCoreImpl, float x, float y); 3268 3269 private native void nativeResetGestureDetectors(long nativeContentViewCoreImpl); 3270 3271 private native void nativeIgnoreRemainingTouchEvents(long nativeContentViewCoreImpl); 3272 3273 private native void nativeOnWindowFocusLost(long nativeContentViewCoreImpl); 3274 3275 private native void nativeSetDoubleTapSupportForPageEnabled( 3276 long nativeContentViewCoreImpl, boolean enabled); 3277 private native void nativeSetDoubleTapSupportEnabled( 3278 long nativeContentViewCoreImpl, boolean enabled); 3279 private native void nativeSetMultiTouchZoomSupportEnabled( 3280 long nativeContentViewCoreImpl, boolean enabled); 3281 3282 private native void nativeLoadIfNecessary(long nativeContentViewCoreImpl); 3283 private native void nativeRequestRestoreLoad(long nativeContentViewCoreImpl); 3284 3285 private native void nativeStopLoading(long nativeContentViewCoreImpl); 3286 3287 private native void nativeReload(long nativeContentViewCoreImpl, boolean checkForRepost); 3288 private native void nativeReloadIgnoringCache( 3289 long nativeContentViewCoreImpl, boolean checkForRepost); 3290 3291 private native void nativeCancelPendingReload(long nativeContentViewCoreImpl); 3292 3293 private native void nativeContinuePendingReload(long nativeContentViewCoreImpl); 3294 3295 private native void nativeSelectPopupMenuItems(long nativeContentViewCoreImpl, int[] indices); 3296 3297 private native void nativeScrollFocusedEditableNodeIntoView(long nativeContentViewCoreImpl); 3298 3299 private native void nativeClearHistory(long nativeContentViewCoreImpl); 3300 3301 private native void nativeEvaluateJavaScript(long nativeContentViewCoreImpl, 3302 String script, JavaScriptCallback callback, boolean startRenderer); 3303 3304 private native long nativeGetNativeImeAdapter(long nativeContentViewCoreImpl); 3305 3306 private native int nativeGetCurrentRenderProcessId(long nativeContentViewCoreImpl); 3307 3308 private native int nativeGetBackgroundColor(long nativeContentViewCoreImpl); 3309 3310 private native void nativeOnShow(long nativeContentViewCoreImpl); 3311 private native void nativeOnHide(long nativeContentViewCoreImpl); 3312 3313 private native void nativeSetUseDesktopUserAgent(long nativeContentViewCoreImpl, 3314 boolean enabled, boolean reloadOnChange); 3315 private native boolean nativeGetUseDesktopUserAgent(long nativeContentViewCoreImpl); 3316 3317 private native void nativeClearSslPreferences(long nativeContentViewCoreImpl); 3318 3319 private native void nativeSetAllowJavascriptInterfacesInspection( 3320 long nativeContentViewCoreImpl, boolean allow); 3321 3322 private native void nativeAddJavascriptInterface(long nativeContentViewCoreImpl, Object object, 3323 String name, Class requiredAnnotation, HashSet<Object> retainedObjectSet); 3324 3325 private native void nativeRemoveJavascriptInterface(long nativeContentViewCoreImpl, 3326 String name); 3327 3328 private native int nativeGetNavigationHistory(long nativeContentViewCoreImpl, Object context); 3329 private native void nativeGetDirectedNavigationHistory(long nativeContentViewCoreImpl, 3330 Object context, boolean isForward, int maxEntries); 3331 private native String nativeGetOriginalUrlForActiveNavigationEntry( 3332 long nativeContentViewCoreImpl); 3333 3334 private native void nativeUpdateVSyncParameters(long nativeContentViewCoreImpl, 3335 long timebaseMicros, long intervalMicros); 3336 3337 private native void nativeOnVSync(long nativeContentViewCoreImpl, long frameTimeMicros); 3338 3339 private native boolean nativeOnAnimate(long nativeContentViewCoreImpl, long frameTimeMicros); 3340 3341 private native void nativeWasResized(long nativeContentViewCoreImpl); 3342 3343 private native boolean nativeIsRenderWidgetHostViewReady(long nativeContentViewCoreImpl); 3344 3345 private native void nativeExitFullscreen(long nativeContentViewCoreImpl); 3346 private native void nativeUpdateTopControlsState(long nativeContentViewCoreImpl, 3347 boolean enableHiding, boolean enableShowing, boolean animate); 3348 3349 private native void nativeShowImeIfNeeded(long nativeContentViewCoreImpl); 3350 3351 private native void nativeSetAccessibilityEnabled( 3352 long nativeContentViewCoreImpl, boolean enabled); 3353 3354 private native void nativeExtractSmartClipData(long nativeContentViewCoreImpl, 3355 int x, int y, int w, int h); 3356} 3357