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