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