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