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