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