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