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