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