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