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