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