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