ContentViewCore.java revision c2db58bd994c04d98e4ee2cd7565b71548655fe3
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 /** 1199 * @return The selected text (empty if no text selected). 1200 */ 1201 public String getSelectedText() { 1202 return mHasSelection ? mLastSelectedText : ""; 1203 } 1204 1205 /** 1206 * @return Whether the current selection is editable (false if no text selected). 1207 */ 1208 public boolean isSelectionEditable() { 1209 return mHasSelection ? mSelectionEditable : false; 1210 } 1211 1212 // End FrameLayout overrides. 1213 1214 /** 1215 * @see View#onTouchEvent(MotionEvent) 1216 */ 1217 public boolean onTouchEvent(MotionEvent event) { 1218 undoScrollFocusedEditableNodeIntoViewIfNeeded(false); 1219 return mContentViewGestureHandler.onTouchEvent(event); 1220 } 1221 1222 /** 1223 * @return ContentViewGestureHandler for all MotionEvent and gesture related calls. 1224 */ 1225 ContentViewGestureHandler getContentViewGestureHandler() { 1226 return mContentViewGestureHandler; 1227 } 1228 1229 @Override 1230 public boolean sendTouchEvent(long timeMs, int action, TouchPoint[] pts) { 1231 if (mNativeContentViewCore != 0) { 1232 return nativeSendTouchEvent(mNativeContentViewCore, timeMs, action, pts); 1233 } 1234 return false; 1235 } 1236 1237 @SuppressWarnings("unused") 1238 @CalledByNative 1239 private void hasTouchEventHandlers(boolean hasTouchHandlers) { 1240 mContentViewGestureHandler.hasTouchEventHandlers(hasTouchHandlers); 1241 } 1242 1243 @SuppressWarnings("unused") 1244 @CalledByNative 1245 private void confirmTouchEvent(int ackResult) { 1246 mContentViewGestureHandler.confirmTouchEvent(ackResult); 1247 } 1248 1249 @SuppressWarnings("unused") 1250 @CalledByNative 1251 private void unhandledFlingStartEvent() { 1252 if (mGestureStateListener != null) { 1253 mGestureStateListener.onUnhandledFlingStartEvent(); 1254 } 1255 } 1256 1257 @Override 1258 public boolean sendGesture(int type, long timeMs, int x, int y, boolean lastInputEventForVSync, 1259 Bundle b) { 1260 if (offerGestureToEmbedder(type)) return false; 1261 if (mNativeContentViewCore == 0) return false; 1262 updateTextHandlesForGesture(type); 1263 updateGestureStateListener(type, b); 1264 if (lastInputEventForVSync && isVSyncNotificationEnabled()) { 1265 assert type == ContentViewGestureHandler.GESTURE_SCROLL_BY || 1266 type == ContentViewGestureHandler.GESTURE_PINCH_BY; 1267 mDidSignalVSyncUsingInputEvent = true; 1268 } 1269 switch (type) { 1270 case ContentViewGestureHandler.GESTURE_SHOW_PRESSED_STATE: 1271 nativeShowPressState(mNativeContentViewCore, timeMs, x, y); 1272 return true; 1273 case ContentViewGestureHandler.GESTURE_SHOW_PRESS_CANCEL: 1274 nativeShowPressCancel(mNativeContentViewCore, timeMs, x, y); 1275 return true; 1276 case ContentViewGestureHandler.GESTURE_DOUBLE_TAP: 1277 nativeDoubleTap(mNativeContentViewCore, timeMs, x, y); 1278 return true; 1279 case ContentViewGestureHandler.GESTURE_SINGLE_TAP_UP: 1280 nativeSingleTap(mNativeContentViewCore, timeMs, x, y, false); 1281 return true; 1282 case ContentViewGestureHandler.GESTURE_SINGLE_TAP_CONFIRMED: 1283 handleTapOrPress(timeMs, x, y, 0, 1284 b.getBoolean(ContentViewGestureHandler.SHOW_PRESS, false)); 1285 return true; 1286 case ContentViewGestureHandler.GESTURE_SINGLE_TAP_UNCONFIRMED: 1287 nativeSingleTapUnconfirmed(mNativeContentViewCore, timeMs, x, y); 1288 return true; 1289 case ContentViewGestureHandler.GESTURE_LONG_PRESS: 1290 handleTapOrPress(timeMs, x, y, IS_LONG_PRESS, false); 1291 return true; 1292 case ContentViewGestureHandler.GESTURE_LONG_TAP: 1293 handleTapOrPress(timeMs, x, y, IS_LONG_TAP, false); 1294 return true; 1295 case ContentViewGestureHandler.GESTURE_SCROLL_START: 1296 nativeScrollBegin(mNativeContentViewCore, timeMs, x, y); 1297 return true; 1298 case ContentViewGestureHandler.GESTURE_SCROLL_BY: { 1299 int dx = b.getInt(ContentViewGestureHandler.DISTANCE_X); 1300 int dy = b.getInt(ContentViewGestureHandler.DISTANCE_Y); 1301 nativeScrollBy(mNativeContentViewCore, timeMs, x, y, dx, dy, 1302 lastInputEventForVSync); 1303 return true; 1304 } 1305 case ContentViewGestureHandler.GESTURE_SCROLL_END: 1306 nativeScrollEnd(mNativeContentViewCore, timeMs); 1307 return true; 1308 case ContentViewGestureHandler.GESTURE_FLING_START: 1309 nativeFlingStart(mNativeContentViewCore, timeMs, x, y, 1310 b.getInt(ContentViewGestureHandler.VELOCITY_X, 0), 1311 b.getInt(ContentViewGestureHandler.VELOCITY_Y, 0)); 1312 return true; 1313 case ContentViewGestureHandler.GESTURE_FLING_CANCEL: 1314 nativeFlingCancel(mNativeContentViewCore, timeMs); 1315 return true; 1316 case ContentViewGestureHandler.GESTURE_PINCH_BEGIN: 1317 nativePinchBegin(mNativeContentViewCore, timeMs, x, y); 1318 return true; 1319 case ContentViewGestureHandler.GESTURE_PINCH_BY: 1320 nativePinchBy(mNativeContentViewCore, timeMs, x, y, 1321 b.getFloat(ContentViewGestureHandler.DELTA, 0), 1322 lastInputEventForVSync); 1323 return true; 1324 case ContentViewGestureHandler.GESTURE_PINCH_END: 1325 nativePinchEnd(mNativeContentViewCore, timeMs); 1326 return true; 1327 default: 1328 return false; 1329 } 1330 } 1331 1332 public void setGestureStateListener(GestureStateListener pinchGestureStateListener) { 1333 mGestureStateListener = pinchGestureStateListener; 1334 } 1335 1336 void updateGestureStateListener(int gestureType, Bundle b) { 1337 if (mGestureStateListener == null) return; 1338 1339 switch (gestureType) { 1340 case ContentViewGestureHandler.GESTURE_PINCH_BEGIN: 1341 mGestureStateListener.onPinchGestureStart(); 1342 break; 1343 case ContentViewGestureHandler.GESTURE_PINCH_END: 1344 mGestureStateListener.onPinchGestureEnd(); 1345 break; 1346 case ContentViewGestureHandler.GESTURE_FLING_START: 1347 mGestureStateListener.onFlingStartGesture( 1348 b.getInt(ContentViewGestureHandler.VELOCITY_X, 0), 1349 b.getInt(ContentViewGestureHandler.VELOCITY_Y, 0)); 1350 break; 1351 case ContentViewGestureHandler.GESTURE_FLING_CANCEL: 1352 mGestureStateListener.onFlingCancelGesture(); 1353 break; 1354 default: 1355 break; 1356 } 1357 } 1358 1359 public interface JavaScriptCallback { 1360 void handleJavaScriptResult(String jsonResult); 1361 } 1362 1363 /** 1364 * Injects the passed Javascript code in the current page and evaluates it. 1365 * If a result is required, pass in a callback. 1366 * Used in automation tests. 1367 * 1368 * @param script The Javascript to execute. 1369 * @param callback The callback to be fired off when a result is ready. The script's 1370 * result will be json encoded and passed as the parameter, and the call 1371 * will be made on the main thread. 1372 * If no result is required, pass null. 1373 * @throws IllegalStateException If the ContentView has been destroyed. 1374 */ 1375 public void evaluateJavaScript( 1376 String script, JavaScriptCallback callback) throws IllegalStateException { 1377 checkIsAlive(); 1378 nativeEvaluateJavaScript(mNativeContentViewCore, script, callback); 1379 } 1380 1381 /** 1382 * This method should be called when the containing activity is paused. 1383 */ 1384 public void onActivityPause() { 1385 TraceEvent.begin(); 1386 hidePopupDialog(); 1387 nativeOnHide(mNativeContentViewCore); 1388 TraceEvent.end(); 1389 } 1390 1391 /** 1392 * This method should be called when the containing activity is resumed. 1393 */ 1394 public void onActivityResume() { 1395 nativeOnShow(mNativeContentViewCore); 1396 setAccessibilityState(mAccessibilityManager.isEnabled()); 1397 } 1398 1399 /** 1400 * To be called when the ContentView is shown. 1401 */ 1402 public void onShow() { 1403 nativeOnShow(mNativeContentViewCore); 1404 setAccessibilityState(mAccessibilityManager.isEnabled()); 1405 } 1406 1407 /** 1408 * To be called when the ContentView is hidden. 1409 */ 1410 public void onHide() { 1411 hidePopupDialog(); 1412 setInjectedAccessibility(false); 1413 nativeOnHide(mNativeContentViewCore); 1414 } 1415 1416 /** 1417 * Return the ContentSettings object used to retrieve the settings for this 1418 * ContentViewCore. For modifications, ChromeNativePreferences is to be used. 1419 * @return A ContentSettings object that can be used to retrieve this 1420 * ContentViewCore's settings. 1421 */ 1422 public ContentSettings getContentSettings() { 1423 return mContentSettings; 1424 } 1425 1426 @Override 1427 public boolean didUIStealScroll(float x, float y) { 1428 return getContentViewClient().shouldOverrideScroll( 1429 x, y, computeHorizontalScrollOffset(), computeVerticalScrollOffset()); 1430 } 1431 1432 @Override 1433 public boolean hasFixedPageScale() { 1434 return mRenderCoordinates.hasFixedPageScale(); 1435 } 1436 1437 private void hidePopupDialog() { 1438 SelectPopupDialog.hide(this); 1439 hideHandles(); 1440 hideSelectActionBar(); 1441 } 1442 1443 void hideSelectActionBar() { 1444 if (mActionMode != null) { 1445 mActionMode.finish(); 1446 mActionMode = null; 1447 } 1448 } 1449 1450 public boolean isSelectActionBarShowing() { 1451 return mActionMode != null; 1452 } 1453 1454 private void resetGestureDetectors() { 1455 mContentViewGestureHandler.resetGestureHandlers(); 1456 } 1457 1458 /** 1459 * @see View#onAttachedToWindow() 1460 */ 1461 @SuppressWarnings("javadoc") 1462 public void onAttachedToWindow() { 1463 mAttachedToWindow = true; 1464 if (mNativeContentViewCore != 0) { 1465 assert mPid == nativeGetCurrentRenderProcessId(mNativeContentViewCore); 1466 ChildProcessLauncher.bindAsHighPriority(mPid); 1467 // Normally the initial binding is removed in onRenderProcessSwap(), but it is possible 1468 // to construct WebContents and spawn the renderer before passing it to ContentViewCore. 1469 // In this case there will be no onRenderProcessSwap() call and the initial binding will 1470 // be removed here. 1471 ChildProcessLauncher.removeInitialBinding(mPid); 1472 } 1473 setAccessibilityState(mAccessibilityManager.isEnabled()); 1474 } 1475 1476 /** 1477 * @see View#onDetachedFromWindow() 1478 */ 1479 @SuppressWarnings("javadoc") 1480 public void onDetachedFromWindow() { 1481 mAttachedToWindow = false; 1482 if (mNativeContentViewCore != 0) { 1483 assert mPid == nativeGetCurrentRenderProcessId(mNativeContentViewCore); 1484 ChildProcessLauncher.unbindAsHighPriority(mPid); 1485 } 1486 setInjectedAccessibility(false); 1487 hidePopupDialog(); 1488 mZoomControlsDelegate.dismissZoomPicker(); 1489 unregisterAccessibilityContentObserver(); 1490 } 1491 1492 /** 1493 * @see View#onVisibilityChanged(android.view.View, int) 1494 */ 1495 public void onVisibilityChanged(View changedView, int visibility) { 1496 if (visibility != View.VISIBLE) { 1497 mZoomControlsDelegate.dismissZoomPicker(); 1498 } 1499 } 1500 1501 /** 1502 * @see View#onCreateInputConnection(EditorInfo) 1503 */ 1504 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 1505 if (!mImeAdapter.hasTextInputType()) { 1506 // Although onCheckIsTextEditor will return false in this case, the EditorInfo 1507 // is still used by the InputMethodService. Need to make sure the IME doesn't 1508 // enter fullscreen mode. 1509 outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN; 1510 } 1511 mInputConnection = 1512 mAdapterInputConnectionFactory.get(mContainerView, mImeAdapter, outAttrs); 1513 return mInputConnection; 1514 } 1515 1516 public Editable getEditableForTest() { 1517 return mInputConnection.getEditable(); 1518 } 1519 1520 /** 1521 * @see View#onCheckIsTextEditor() 1522 */ 1523 public boolean onCheckIsTextEditor() { 1524 return mImeAdapter.hasTextInputType(); 1525 } 1526 1527 /** 1528 * @see View#onConfigurationChanged(Configuration) 1529 */ 1530 @SuppressWarnings("javadoc") 1531 public void onConfigurationChanged(Configuration newConfig) { 1532 TraceEvent.begin(); 1533 1534 if (newConfig.keyboard != Configuration.KEYBOARD_NOKEYS) { 1535 mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore), 1536 ImeAdapter.getTextInputTypeNone(), 1537 AdapterInputConnection.INVALID_SELECTION, 1538 AdapterInputConnection.INVALID_SELECTION); 1539 InputMethodManager manager = (InputMethodManager) 1540 getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 1541 manager.restartInput(mContainerView); 1542 } 1543 mContainerViewInternals.super_onConfigurationChanged(newConfig); 1544 mNeedUpdateOrientationChanged = true; 1545 TraceEvent.end(); 1546 } 1547 1548 /** 1549 * @see View#onSizeChanged(int, int, int, int) 1550 */ 1551 @SuppressWarnings("javadoc") 1552 public void onSizeChanged(int wPix, int hPix, int owPix, int ohPix) { 1553 if (getViewportWidthPix() == wPix && getViewportHeightPix() == hPix) return; 1554 1555 mViewportWidthPix = wPix; 1556 mViewportHeightPix = hPix; 1557 if (mNativeContentViewCore != 0) { 1558 nativeWasResized(mNativeContentViewCore); 1559 } 1560 1561 updateAfterSizeChanged(); 1562 } 1563 1564 /** 1565 * Called when the underlying surface the compositor draws to changes size. 1566 * This may be larger than the viewport size. 1567 */ 1568 public void onPhysicalBackingSizeChanged(int wPix, int hPix) { 1569 if (mPhysicalBackingWidthPix == wPix && mPhysicalBackingHeightPix == hPix) return; 1570 1571 mPhysicalBackingWidthPix = wPix; 1572 mPhysicalBackingHeightPix = hPix; 1573 1574 if (mNativeContentViewCore != 0) { 1575 nativeWasResized(mNativeContentViewCore); 1576 } 1577 } 1578 1579 /** 1580 * Called when the amount the surface is overdrawing off the bottom has changed. 1581 * @param overdrawHeightPix The overdraw height. 1582 */ 1583 public void onOverdrawBottomHeightChanged(int overdrawHeightPix) { 1584 if (mOverdrawBottomHeightPix == overdrawHeightPix) return; 1585 1586 mOverdrawBottomHeightPix = overdrawHeightPix; 1587 1588 if (mNativeContentViewCore != 0) { 1589 nativeWasResized(mNativeContentViewCore); 1590 } 1591 } 1592 1593 private void updateAfterSizeChanged() { 1594 mPopupZoomer.hide(false); 1595 1596 // Execute a delayed form focus operation because the OSK was brought 1597 // up earlier. 1598 if (!mFocusPreOSKViewportRect.isEmpty()) { 1599 Rect rect = new Rect(); 1600 getContainerView().getWindowVisibleDisplayFrame(rect); 1601 if (!rect.equals(mFocusPreOSKViewportRect)) { 1602 scrollFocusedEditableNodeIntoView(); 1603 mFocusPreOSKViewportRect.setEmpty(); 1604 } 1605 } else if (mUnfocusOnNextSizeChanged) { 1606 undoScrollFocusedEditableNodeIntoViewIfNeeded(true); 1607 mUnfocusOnNextSizeChanged = false; 1608 } 1609 1610 if (mNeedUpdateOrientationChanged) { 1611 sendOrientationChangeEvent(); 1612 mNeedUpdateOrientationChanged = false; 1613 } 1614 } 1615 1616 private void scrollFocusedEditableNodeIntoView() { 1617 if (mNativeContentViewCore != 0) { 1618 Runnable scrollTask = new Runnable() { 1619 @Override 1620 public void run() { 1621 if (mNativeContentViewCore != 0) { 1622 nativeScrollFocusedEditableNodeIntoView(mNativeContentViewCore); 1623 } 1624 } 1625 }; 1626 1627 scrollTask.run(); 1628 1629 // The native side keeps track of whether the zoom and scroll actually occurred. It is 1630 // more efficient to do it this way and sometimes fire an unnecessary message rather 1631 // than synchronize with the renderer and always have an additional message. 1632 mScrolledAndZoomedFocusedEditableNode = true; 1633 } 1634 } 1635 1636 private void undoScrollFocusedEditableNodeIntoViewIfNeeded(boolean backButtonPressed) { 1637 // The only call to this function that matters is the first call after the 1638 // scrollFocusedEditableNodeIntoView function call. 1639 // If the first call to this function is a result of a back button press we want to undo the 1640 // preceding scroll. If the call is a result of some other action we don't want to perform 1641 // an undo. 1642 // All subsequent calls are ignored since only the scroll function sets 1643 // mScrolledAndZoomedFocusedEditableNode to true. 1644 if (mScrolledAndZoomedFocusedEditableNode && backButtonPressed && 1645 mNativeContentViewCore != 0) { 1646 Runnable scrollTask = new Runnable() { 1647 @Override 1648 public void run() { 1649 if (mNativeContentViewCore != 0) { 1650 nativeUndoScrollFocusedEditableNodeIntoView(mNativeContentViewCore); 1651 } 1652 } 1653 }; 1654 1655 scrollTask.run(); 1656 } 1657 mScrolledAndZoomedFocusedEditableNode = false; 1658 } 1659 1660 public void onFocusChanged(boolean gainFocus) { 1661 if (!gainFocus) getContentViewClient().onImeStateChangeRequested(false); 1662 if (mNativeContentViewCore != 0) nativeSetFocus(mNativeContentViewCore, gainFocus); 1663 } 1664 1665 /** 1666 * @see View#onKeyUp(int, KeyEvent) 1667 */ 1668 public boolean onKeyUp(int keyCode, KeyEvent event) { 1669 if (mPopupZoomer.isShowing() && keyCode == KeyEvent.KEYCODE_BACK) { 1670 mPopupZoomer.hide(true); 1671 return true; 1672 } 1673 return mContainerViewInternals.super_onKeyUp(keyCode, event); 1674 } 1675 1676 /** 1677 * @see View#dispatchKeyEventPreIme(KeyEvent) 1678 */ 1679 public boolean dispatchKeyEventPreIme(KeyEvent event) { 1680 try { 1681 TraceEvent.begin(); 1682 if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && mImeAdapter.isActive()) { 1683 mUnfocusOnNextSizeChanged = true; 1684 } else { 1685 undoScrollFocusedEditableNodeIntoViewIfNeeded(false); 1686 } 1687 return mContainerViewInternals.super_dispatchKeyEventPreIme(event); 1688 } finally { 1689 TraceEvent.end(); 1690 } 1691 } 1692 1693 /** 1694 * @see View#dispatchKeyEvent(KeyEvent) 1695 */ 1696 public boolean dispatchKeyEvent(KeyEvent event) { 1697 if (getContentViewClient().shouldOverrideKeyEvent(event)) { 1698 return mContainerViewInternals.super_dispatchKeyEvent(event); 1699 } 1700 1701 if (mImeAdapter.dispatchKeyEvent(event)) return true; 1702 1703 return mContainerViewInternals.super_dispatchKeyEvent(event); 1704 } 1705 1706 /** 1707 * @see View#onHoverEvent(MotionEvent) 1708 * Mouse move events are sent on hover enter, hover move and hover exit. 1709 * They are sent on hover exit because sometimes it acts as both a hover 1710 * move and hover exit. 1711 */ 1712 public boolean onHoverEvent(MotionEvent event) { 1713 TraceEvent.begin("onHoverEvent"); 1714 mContainerView.removeCallbacks(mFakeMouseMoveRunnable); 1715 if (mBrowserAccessibilityManager != null) { 1716 return mBrowserAccessibilityManager.onHoverEvent(event); 1717 } 1718 if (mNativeContentViewCore != 0) { 1719 nativeSendMouseMoveEvent(mNativeContentViewCore, event.getEventTime(), 1720 event.getX(), event.getY()); 1721 } 1722 TraceEvent.end("onHoverEvent"); 1723 return true; 1724 } 1725 1726 /** 1727 * @see View#onGenericMotionEvent(MotionEvent) 1728 */ 1729 public boolean onGenericMotionEvent(MotionEvent event) { 1730 if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { 1731 switch (event.getAction()) { 1732 case MotionEvent.ACTION_SCROLL: 1733 nativeSendMouseWheelEvent(mNativeContentViewCore, event.getEventTime(), 1734 event.getX(), event.getY(), 1735 event.getAxisValue(MotionEvent.AXIS_VSCROLL)); 1736 1737 mContainerView.removeCallbacks(mFakeMouseMoveRunnable); 1738 // Send a delayed onMouseMove event so that we end 1739 // up hovering over the right position after the scroll. 1740 final MotionEvent eventFakeMouseMove = MotionEvent.obtain(event); 1741 mFakeMouseMoveRunnable = new Runnable() { 1742 @Override 1743 public void run() { 1744 onHoverEvent(eventFakeMouseMove); 1745 } 1746 }; 1747 mContainerView.postDelayed(mFakeMouseMoveRunnable, 250); 1748 return true; 1749 } 1750 } 1751 return mContainerViewInternals.super_onGenericMotionEvent(event); 1752 } 1753 1754 /** 1755 * @see View#scrollBy(int, int) 1756 * Currently the ContentView scrolling happens in the native side. In 1757 * the Java view system, it is always pinned at (0, 0). scrollBy() and scrollTo() 1758 * are overridden, so that View's mScrollX and mScrollY will be unchanged at 1759 * (0, 0). This is critical for drawing ContentView correctly. 1760 */ 1761 public void scrollBy(int xPix, int yPix) { 1762 if (mNativeContentViewCore != 0) { 1763 nativeScrollBy(mNativeContentViewCore, 1764 System.currentTimeMillis(), 0, 0, xPix, yPix, false); 1765 } 1766 } 1767 1768 /** 1769 * @see View#scrollTo(int, int) 1770 */ 1771 public void scrollTo(int xPix, int yPix) { 1772 if (mNativeContentViewCore == 0) return; 1773 final float xCurrentPix = mRenderCoordinates.getScrollXPix(); 1774 final float yCurrentPix = mRenderCoordinates.getScrollYPix(); 1775 final float dxPix = xPix - xCurrentPix; 1776 final float dyPix = yPix - yCurrentPix; 1777 if (dxPix != 0 || dyPix != 0) { 1778 long time = System.currentTimeMillis(); 1779 nativeScrollBegin(mNativeContentViewCore, time, xCurrentPix, yCurrentPix); 1780 nativeScrollBy(mNativeContentViewCore, 1781 time, xCurrentPix, yCurrentPix, dxPix, dyPix, false); 1782 nativeScrollEnd(mNativeContentViewCore, time); 1783 } 1784 } 1785 1786 // NOTE: this can go away once ContentView.getScrollX() reports correct values. 1787 // see: b/6029133 1788 public int getNativeScrollXForTest() { 1789 return mRenderCoordinates.getScrollXPixInt(); 1790 } 1791 1792 // NOTE: this can go away once ContentView.getScrollY() reports correct values. 1793 // see: b/6029133 1794 public int getNativeScrollYForTest() { 1795 return mRenderCoordinates.getScrollYPixInt(); 1796 } 1797 1798 /** 1799 * @see View#computeHorizontalScrollExtent() 1800 */ 1801 @SuppressWarnings("javadoc") 1802 public int computeHorizontalScrollExtent() { 1803 return mRenderCoordinates.getLastFrameViewportWidthPixInt(); 1804 } 1805 1806 /** 1807 * @see View#computeHorizontalScrollOffset() 1808 */ 1809 @SuppressWarnings("javadoc") 1810 public int computeHorizontalScrollOffset() { 1811 return mRenderCoordinates.getScrollXPixInt(); 1812 } 1813 1814 /** 1815 * @see View#computeHorizontalScrollRange() 1816 */ 1817 @SuppressWarnings("javadoc") 1818 public int computeHorizontalScrollRange() { 1819 return mRenderCoordinates.getContentWidthPixInt(); 1820 } 1821 1822 /** 1823 * @see View#computeVerticalScrollExtent() 1824 */ 1825 @SuppressWarnings("javadoc") 1826 public int computeVerticalScrollExtent() { 1827 return mRenderCoordinates.getLastFrameViewportHeightPixInt(); 1828 } 1829 1830 /** 1831 * @see View#computeVerticalScrollOffset() 1832 */ 1833 @SuppressWarnings("javadoc") 1834 public int computeVerticalScrollOffset() { 1835 return mRenderCoordinates.getScrollYPixInt(); 1836 } 1837 1838 /** 1839 * @see View#computeVerticalScrollRange() 1840 */ 1841 @SuppressWarnings("javadoc") 1842 public int computeVerticalScrollRange() { 1843 return mRenderCoordinates.getContentHeightPixInt(); 1844 } 1845 1846 // End FrameLayout overrides. 1847 1848 /** 1849 * @see View#awakenScrollBars(int, boolean) 1850 */ 1851 @SuppressWarnings("javadoc") 1852 public boolean awakenScrollBars(int startDelay, boolean invalidate) { 1853 // For the default implementation of ContentView which draws the scrollBars on the native 1854 // side, calling this function may get us into a bad state where we keep drawing the 1855 // scrollBars, so disable it by always returning false. 1856 if (mContainerView.getScrollBarStyle() == View.SCROLLBARS_INSIDE_OVERLAY) { 1857 return false; 1858 } else { 1859 return mContainerViewInternals.super_awakenScrollBars(startDelay, invalidate); 1860 } 1861 } 1862 1863 @SuppressWarnings("unused") 1864 @CalledByNative 1865 private void onTabCrash() { 1866 assert mPid != 0; 1867 getContentViewClient().onRendererCrash(ChildProcessLauncher.isOomProtected(mPid)); 1868 mPid = 0; 1869 } 1870 1871 private void handleTapOrPress( 1872 long timeMs, float xPix, float yPix, int isLongPressOrTap, boolean showPress) { 1873 if (!mContainerView.isFocused()) mContainerView.requestFocus(); 1874 1875 if (!mPopupZoomer.isShowing()) mPopupZoomer.setLastTouch(xPix, yPix); 1876 1877 if (isLongPressOrTap == IS_LONG_PRESS) { 1878 getInsertionHandleController().allowAutomaticShowing(); 1879 getSelectionHandleController().allowAutomaticShowing(); 1880 if (mNativeContentViewCore != 0) { 1881 nativeLongPress(mNativeContentViewCore, timeMs, xPix, yPix, false); 1882 } 1883 } else if (isLongPressOrTap == IS_LONG_TAP) { 1884 getInsertionHandleController().allowAutomaticShowing(); 1885 getSelectionHandleController().allowAutomaticShowing(); 1886 if (mNativeContentViewCore != 0) { 1887 nativeLongTap(mNativeContentViewCore, timeMs, xPix, yPix, false); 1888 } 1889 } else { 1890 if (!showPress && mNativeContentViewCore != 0) { 1891 nativeShowPressState(mNativeContentViewCore, timeMs, xPix, yPix); 1892 } 1893 if (mSelectionEditable) getInsertionHandleController().allowAutomaticShowing(); 1894 if (mNativeContentViewCore != 0) { 1895 nativeSingleTap(mNativeContentViewCore, timeMs, xPix, yPix, false); 1896 } 1897 } 1898 } 1899 1900 public void setZoomControlsDelegate(ZoomControlsDelegate zoomControlsDelegate) { 1901 mZoomControlsDelegate = zoomControlsDelegate; 1902 } 1903 1904 public void updateMultiTouchZoomSupport(boolean supportsMultiTouchZoom) { 1905 mZoomManager.updateMultiTouchSupport(supportsMultiTouchZoom); 1906 } 1907 1908 public void selectPopupMenuItems(int[] indices) { 1909 if (mNativeContentViewCore != 0) { 1910 nativeSelectPopupMenuItems(mNativeContentViewCore, indices); 1911 } 1912 } 1913 1914 /** 1915 * Get the screen orientation from the OS and push it to WebKit. 1916 * 1917 * TODO(husky): Add a hook for mock orientations. 1918 * 1919 * TODO(husky): Currently each new tab starts with an orientation of 0 until you actually 1920 * rotate the device. This is wrong if you actually started in landscape mode. To fix this, we 1921 * need to push the correct orientation, but only after WebKit's Frame object has been fully 1922 * initialized. Need to find a good time to do that. onPageFinished() would probably work but 1923 * it isn't implemented yet. 1924 */ 1925 private void sendOrientationChangeEvent() { 1926 if (mNativeContentViewCore == 0) return; 1927 1928 WindowManager windowManager = 1929 (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); 1930 switch (windowManager.getDefaultDisplay().getRotation()) { 1931 case Surface.ROTATION_90: 1932 nativeSendOrientationChangeEvent(mNativeContentViewCore, 90); 1933 break; 1934 case Surface.ROTATION_180: 1935 nativeSendOrientationChangeEvent(mNativeContentViewCore, 180); 1936 break; 1937 case Surface.ROTATION_270: 1938 nativeSendOrientationChangeEvent(mNativeContentViewCore, -90); 1939 break; 1940 case Surface.ROTATION_0: 1941 nativeSendOrientationChangeEvent(mNativeContentViewCore, 0); 1942 break; 1943 default: 1944 Log.w(TAG, "Unknown rotation!"); 1945 break; 1946 } 1947 } 1948 1949 /** 1950 * Register the delegate to be used when content can not be handled by 1951 * the rendering engine, and should be downloaded instead. This will replace 1952 * the current delegate, if any. 1953 * @param delegate An implementation of ContentViewDownloadDelegate. 1954 */ 1955 public void setDownloadDelegate(ContentViewDownloadDelegate delegate) { 1956 mDownloadDelegate = delegate; 1957 } 1958 1959 // Called by DownloadController. 1960 ContentViewDownloadDelegate getDownloadDelegate() { 1961 return mDownloadDelegate; 1962 } 1963 1964 private SelectionHandleController getSelectionHandleController() { 1965 if (mSelectionHandleController == null) { 1966 mSelectionHandleController = new SelectionHandleController(getContainerView()) { 1967 @Override 1968 public void selectBetweenCoordinates(int x1, int y1, int x2, int y2) { 1969 if (mNativeContentViewCore != 0 && !(x1 == x2 && y1 == y2)) { 1970 nativeSelectBetweenCoordinates(mNativeContentViewCore, 1971 x1, y1 - mRenderCoordinates.getContentOffsetYPix(), 1972 x2, y2 - mRenderCoordinates.getContentOffsetYPix()); 1973 } 1974 } 1975 1976 @Override 1977 public void showHandles(int startDir, int endDir) { 1978 super.showHandles(startDir, endDir); 1979 showSelectActionBar(); 1980 } 1981 1982 }; 1983 1984 mSelectionHandleController.hideAndDisallowAutomaticShowing(); 1985 } 1986 1987 return mSelectionHandleController; 1988 } 1989 1990 private InsertionHandleController getInsertionHandleController() { 1991 if (mInsertionHandleController == null) { 1992 mInsertionHandleController = new InsertionHandleController(getContainerView()) { 1993 private static final int AVERAGE_LINE_HEIGHT = 14; 1994 1995 @Override 1996 public void setCursorPosition(int x, int y) { 1997 if (mNativeContentViewCore != 0) { 1998 nativeMoveCaret(mNativeContentViewCore, 1999 x, y - mRenderCoordinates.getContentOffsetYPix()); 2000 } 2001 } 2002 2003 @Override 2004 public void paste() { 2005 mImeAdapter.paste(); 2006 hideHandles(); 2007 } 2008 2009 @Override 2010 public int getLineHeight() { 2011 return (int) Math.ceil( 2012 mRenderCoordinates.fromLocalCssToPix(AVERAGE_LINE_HEIGHT)); 2013 } 2014 2015 @Override 2016 public void showHandle() { 2017 super.showHandle(); 2018 } 2019 }; 2020 2021 mInsertionHandleController.hideAndDisallowAutomaticShowing(); 2022 } 2023 2024 return mInsertionHandleController; 2025 } 2026 2027 @VisibleForTesting 2028 public InsertionHandleController getInsertionHandleControllerForTest() { 2029 return mInsertionHandleController; 2030 } 2031 2032 @VisibleForTesting 2033 public SelectionHandleController getSelectionHandleControllerForTest() { 2034 return mSelectionHandleController; 2035 } 2036 2037 private void updateHandleScreenPositions() { 2038 if (isSelectionHandleShowing()) { 2039 mSelectionHandleController.setStartHandlePosition( 2040 mStartHandlePoint.getXPix(), mStartHandlePoint.getYPix()); 2041 mSelectionHandleController.setEndHandlePosition( 2042 mEndHandlePoint.getXPix(), mEndHandlePoint.getYPix()); 2043 } 2044 2045 if (isInsertionHandleShowing()) { 2046 mInsertionHandleController.setHandlePosition( 2047 mInsertionHandlePoint.getXPix(), mInsertionHandlePoint.getYPix()); 2048 } 2049 } 2050 2051 private void hideHandles() { 2052 if (mSelectionHandleController != null) { 2053 mSelectionHandleController.hideAndDisallowAutomaticShowing(); 2054 } 2055 if (mInsertionHandleController != null) { 2056 mInsertionHandleController.hideAndDisallowAutomaticShowing(); 2057 } 2058 } 2059 2060 private void showSelectActionBar() { 2061 if (mActionMode != null) { 2062 mActionMode.invalidate(); 2063 return; 2064 } 2065 2066 // Start a new action mode with a SelectActionModeCallback. 2067 SelectActionModeCallback.ActionHandler actionHandler = 2068 new SelectActionModeCallback.ActionHandler() { 2069 @Override 2070 public boolean selectAll() { 2071 return mImeAdapter.selectAll(); 2072 } 2073 2074 @Override 2075 public boolean cut() { 2076 return mImeAdapter.cut(); 2077 } 2078 2079 @Override 2080 public boolean copy() { 2081 return mImeAdapter.copy(); 2082 } 2083 2084 @Override 2085 public boolean paste() { 2086 return mImeAdapter.paste(); 2087 } 2088 2089 @Override 2090 public boolean isSelectionEditable() { 2091 return mSelectionEditable; 2092 } 2093 2094 @Override 2095 public String getSelectedText() { 2096 return ContentViewCore.this.getSelectedText(); 2097 } 2098 2099 @Override 2100 public void onDestroyActionMode() { 2101 mActionMode = null; 2102 if (mUnselectAllOnActionModeDismiss) mImeAdapter.unselect(); 2103 getContentViewClient().onContextualActionBarHidden(); 2104 } 2105 }; 2106 mActionMode = null; 2107 // On ICS, startActionMode throws an NPE when getParent() is null. 2108 if (mContainerView.getParent() != null) { 2109 mActionMode = mContainerView.startActionMode( 2110 getContentViewClient().getSelectActionModeCallback(getContext(), actionHandler, 2111 nativeIsIncognito(mNativeContentViewCore))); 2112 } 2113 mUnselectAllOnActionModeDismiss = true; 2114 if (mActionMode == null) { 2115 // There is no ActionMode, so remove the selection. 2116 mImeAdapter.unselect(); 2117 } else { 2118 getContentViewClient().onContextualActionBarShown(); 2119 } 2120 } 2121 2122 public boolean getUseDesktopUserAgent() { 2123 if (mNativeContentViewCore != 0) { 2124 return nativeGetUseDesktopUserAgent(mNativeContentViewCore); 2125 } 2126 return false; 2127 } 2128 2129 /** 2130 * Set whether or not we're using a desktop user agent for the currently loaded page. 2131 * @param override If true, use a desktop user agent. Use a mobile one otherwise. 2132 * @param reloadOnChange Reload the page if the UA has changed. 2133 */ 2134 public void setUseDesktopUserAgent(boolean override, boolean reloadOnChange) { 2135 if (mNativeContentViewCore != 0) { 2136 nativeSetUseDesktopUserAgent(mNativeContentViewCore, override, reloadOnChange); 2137 } 2138 } 2139 2140 public void clearSslPreferences() { 2141 nativeClearSslPreferences(mNativeContentViewCore); 2142 } 2143 2144 /** 2145 * @return Whether the native ContentView has crashed. 2146 */ 2147 public boolean isCrashed() { 2148 if (mNativeContentViewCore == 0) return false; 2149 return nativeCrashed(mNativeContentViewCore); 2150 } 2151 2152 private boolean isSelectionHandleShowing() { 2153 return mSelectionHandleController != null && mSelectionHandleController.isShowing(); 2154 } 2155 2156 private boolean isInsertionHandleShowing() { 2157 return mInsertionHandleController != null && mInsertionHandleController.isShowing(); 2158 } 2159 2160 private void updateTextHandlesForGesture(int type) { 2161 switch(type) { 2162 case ContentViewGestureHandler.GESTURE_DOUBLE_TAP: 2163 case ContentViewGestureHandler.GESTURE_SCROLL_START: 2164 case ContentViewGestureHandler.GESTURE_FLING_START: 2165 case ContentViewGestureHandler.GESTURE_PINCH_BEGIN: 2166 temporarilyHideTextHandles(); 2167 break; 2168 2169 default: 2170 break; 2171 } 2172 } 2173 2174 // Makes the insertion/selection handles invisible. They will fade back in shortly after the 2175 // last call to scheduleTextHandleFadeIn (or temporarilyHideTextHandles). 2176 private void temporarilyHideTextHandles() { 2177 if (isSelectionHandleShowing()) { 2178 mSelectionHandleController.setHandleVisibility(HandleView.INVISIBLE); 2179 } 2180 if (isInsertionHandleShowing()) { 2181 mInsertionHandleController.setHandleVisibility(HandleView.INVISIBLE); 2182 } 2183 scheduleTextHandleFadeIn(); 2184 } 2185 2186 private boolean allowTextHandleFadeIn() { 2187 if (mContentViewGestureHandler.isNativeScrolling() || 2188 mContentViewGestureHandler.isNativePinching()) { 2189 return false; 2190 } 2191 2192 if (mPopupZoomer.isShowing()) return false; 2193 2194 return true; 2195 } 2196 2197 // Cancels any pending fade in and schedules a new one. 2198 private void scheduleTextHandleFadeIn() { 2199 if (!isInsertionHandleShowing() && !isSelectionHandleShowing()) return; 2200 2201 if (mDeferredHandleFadeInRunnable == null) { 2202 mDeferredHandleFadeInRunnable = new Runnable() { 2203 @Override 2204 public void run() { 2205 if (!allowTextHandleFadeIn()) { 2206 // Delay fade in until it is allowed. 2207 scheduleTextHandleFadeIn(); 2208 } else { 2209 if (isSelectionHandleShowing()) { 2210 mSelectionHandleController.beginHandleFadeIn(); 2211 } 2212 if (isInsertionHandleShowing()) { 2213 mInsertionHandleController.beginHandleFadeIn(); 2214 } 2215 } 2216 } 2217 }; 2218 } 2219 2220 mContainerView.removeCallbacks(mDeferredHandleFadeInRunnable); 2221 mContainerView.postDelayed(mDeferredHandleFadeInRunnable, TEXT_HANDLE_FADE_IN_DELAY); 2222 } 2223 2224 /** 2225 * Shows the IME if the focused widget could accept text input. 2226 */ 2227 public void showImeIfNeeded() { 2228 if (mNativeContentViewCore != 0) nativeShowImeIfNeeded(mNativeContentViewCore); 2229 } 2230 2231 public void setUpdateFrameInfoListener(UpdateFrameInfoListener updateFrameInfoListener) { 2232 mUpdateFrameInfoListener = updateFrameInfoListener; 2233 } 2234 2235 @SuppressWarnings("unused") 2236 @CalledByNative 2237 private void updateFrameInfo( 2238 float scrollOffsetX, float scrollOffsetY, 2239 float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor, 2240 float contentWidth, float contentHeight, 2241 float viewportWidth, float viewportHeight, 2242 float controlsOffsetYCss, float contentOffsetYCss, 2243 float overdrawBottomHeightCss) { 2244 TraceEvent.instant("ContentViewCore:updateFrameInfo"); 2245 // Adjust contentWidth/Height to be always at least as big as 2246 // the actual viewport (as set by onSizeChanged). 2247 contentWidth = Math.max(contentWidth, 2248 mRenderCoordinates.fromPixToLocalCss(mViewportWidthPix)); 2249 contentHeight = Math.max(contentHeight, 2250 mRenderCoordinates.fromPixToLocalCss(mViewportHeightPix)); 2251 2252 final float contentOffsetYPix = mRenderCoordinates.fromDipToPix(contentOffsetYCss); 2253 2254 final boolean contentSizeChanged = 2255 contentWidth != mRenderCoordinates.getContentWidthCss() 2256 || contentHeight != mRenderCoordinates.getContentHeightCss(); 2257 final boolean scaleLimitsChanged = 2258 minPageScaleFactor != mRenderCoordinates.getMinPageScaleFactor() 2259 || maxPageScaleFactor != mRenderCoordinates.getMaxPageScaleFactor(); 2260 final boolean pageScaleChanged = 2261 pageScaleFactor != mRenderCoordinates.getPageScaleFactor(); 2262 final boolean scrollChanged = 2263 pageScaleChanged 2264 || scrollOffsetX != mRenderCoordinates.getScrollX() 2265 || scrollOffsetY != mRenderCoordinates.getScrollY(); 2266 final boolean contentOffsetChanged = 2267 contentOffsetYPix != mRenderCoordinates.getContentOffsetYPix(); 2268 2269 final boolean needHidePopupZoomer = contentSizeChanged || scrollChanged; 2270 final boolean needUpdateZoomControls = scaleLimitsChanged || scrollChanged; 2271 final boolean needTemporarilyHideHandles = scrollChanged; 2272 2273 if (needHidePopupZoomer) mPopupZoomer.hide(true); 2274 2275 if (pageScaleChanged) { 2276 // This function should be called back from native as soon 2277 // as the scroll is applied to the backbuffer. We should only 2278 // update mNativeScrollX/Y here for consistency. 2279 getContentViewClient().onScaleChanged( 2280 mRenderCoordinates.getPageScaleFactor(), pageScaleFactor); 2281 } 2282 2283 mRenderCoordinates.updateFrameInfo( 2284 scrollOffsetX, scrollOffsetY, 2285 contentWidth, contentHeight, 2286 viewportWidth, viewportHeight, 2287 pageScaleFactor, minPageScaleFactor, maxPageScaleFactor, 2288 contentOffsetYPix); 2289 2290 if ((contentSizeChanged || pageScaleChanged) && mUpdateFrameInfoListener != null) { 2291 mUpdateFrameInfoListener.onFrameInfoUpdated( 2292 contentWidth, contentHeight, pageScaleFactor); 2293 } 2294 2295 if (needTemporarilyHideHandles) temporarilyHideTextHandles(); 2296 if (needUpdateZoomControls) mZoomControlsDelegate.updateZoomControls(); 2297 if (contentOffsetChanged) updateHandleScreenPositions(); 2298 2299 // Update offsets for fullscreen. 2300 final float deviceScale = mRenderCoordinates.getDeviceScaleFactor(); 2301 final float controlsOffsetPix = controlsOffsetYCss * deviceScale; 2302 final float overdrawBottomHeightPix = overdrawBottomHeightCss * deviceScale; 2303 getContentViewClient().onOffsetsForFullscreenChanged( 2304 controlsOffsetPix, contentOffsetYPix, overdrawBottomHeightPix); 2305 2306 mPendingRendererFrame = true; 2307 if (mBrowserAccessibilityManager != null) { 2308 mBrowserAccessibilityManager.notifyFrameInfoInitialized(); 2309 } 2310 2311 // Update geometry for external video surface. 2312 getContentViewClient().onGeometryChanged(-1, null); 2313 } 2314 2315 @SuppressWarnings("unused") 2316 @CalledByNative 2317 private void updateImeAdapter(int nativeImeAdapterAndroid, int textInputType, 2318 String text, int selectionStart, int selectionEnd, 2319 int compositionStart, int compositionEnd, boolean showImeIfNeeded) { 2320 TraceEvent.begin(); 2321 mSelectionEditable = (textInputType != ImeAdapter.getTextInputTypeNone()); 2322 2323 if (mActionMode != null) mActionMode.invalidate(); 2324 2325 mImeAdapter.attachAndShowIfNeeded(nativeImeAdapterAndroid, textInputType, 2326 selectionStart, selectionEnd, showImeIfNeeded); 2327 2328 if (mInputConnection != null) { 2329 mInputConnection.setEditableText(text, selectionStart, selectionEnd, 2330 compositionStart, compositionEnd); 2331 } 2332 TraceEvent.end(); 2333 } 2334 2335 @SuppressWarnings("unused") 2336 @CalledByNative 2337 private void processImeBatchStateAck(boolean isBegin) { 2338 if (mInputConnection == null) return; 2339 mInputConnection.setIgnoreTextInputStateUpdates(isBegin); 2340 } 2341 2342 @SuppressWarnings("unused") 2343 @CalledByNative 2344 private void setTitle(String title) { 2345 getContentViewClient().onUpdateTitle(title); 2346 } 2347 2348 /** 2349 * Called (from native) when the <select> popup needs to be shown. 2350 * @param items Items to show. 2351 * @param enabled POPUP_ITEM_TYPEs for items. 2352 * @param multiple Whether the popup menu should support multi-select. 2353 * @param selectedIndices Indices of selected items. 2354 */ 2355 @SuppressWarnings("unused") 2356 @CalledByNative 2357 private void showSelectPopup(String[] items, int[] enabled, boolean multiple, 2358 int[] selectedIndices) { 2359 SelectPopupDialog.show(this, items, enabled, multiple, selectedIndices); 2360 } 2361 2362 @SuppressWarnings("unused") 2363 @CalledByNative 2364 private void showDisambiguationPopup(Rect targetRect, Bitmap zoomedBitmap) { 2365 mPopupZoomer.setBitmap(zoomedBitmap); 2366 mPopupZoomer.show(targetRect); 2367 temporarilyHideTextHandles(); 2368 } 2369 2370 @SuppressWarnings("unused") 2371 @CalledByNative 2372 private SmoothScroller createSmoothScroller(boolean scrollDown, int mouseEventX, 2373 int mouseEventY) { 2374 return new SmoothScroller(this, scrollDown, mouseEventX, mouseEventY); 2375 } 2376 2377 @SuppressWarnings("unused") 2378 @CalledByNative 2379 private void onSelectionChanged(String text) { 2380 mLastSelectedText = text; 2381 } 2382 2383 @SuppressWarnings("unused") 2384 @CalledByNative 2385 private void onSelectionBoundsChanged(Rect anchorRectDip, int anchorDir, Rect focusRectDip, 2386 int focusDir, boolean isAnchorFirst) { 2387 // All coordinates are in DIP. 2388 int x1 = anchorRectDip.left; 2389 int y1 = anchorRectDip.bottom; 2390 int x2 = focusRectDip.left; 2391 int y2 = focusRectDip.bottom; 2392 2393 if (x1 != x2 || y1 != y2 || 2394 (mSelectionHandleController != null && mSelectionHandleController.isDragging())) { 2395 if (mInsertionHandleController != null) { 2396 mInsertionHandleController.hide(); 2397 } 2398 if (isAnchorFirst) { 2399 mStartHandlePoint.setLocalDip(x1, y1); 2400 mEndHandlePoint.setLocalDip(x2, y2); 2401 } else { 2402 mStartHandlePoint.setLocalDip(x2, y2); 2403 mEndHandlePoint.setLocalDip(x1, y1); 2404 } 2405 2406 getSelectionHandleController().onSelectionChanged(anchorDir, focusDir); 2407 updateHandleScreenPositions(); 2408 mHasSelection = true; 2409 } else { 2410 mUnselectAllOnActionModeDismiss = false; 2411 hideSelectActionBar(); 2412 if (x1 != 0 && y1 != 0 && mSelectionEditable) { 2413 // Selection is a caret, and a text field is focused. 2414 if (mSelectionHandleController != null) { 2415 mSelectionHandleController.hide(); 2416 } 2417 mInsertionHandlePoint.setLocalDip(x1, y1); 2418 2419 getInsertionHandleController().onCursorPositionChanged(); 2420 updateHandleScreenPositions(); 2421 InputMethodManager manager = (InputMethodManager) 2422 getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 2423 if (manager.isWatchingCursor(mContainerView)) { 2424 final int xPix = (int) mInsertionHandlePoint.getXPix(); 2425 final int yPix = (int) mInsertionHandlePoint.getYPix(); 2426 manager.updateCursor(mContainerView, xPix, yPix, xPix, yPix); 2427 } 2428 } else { 2429 // Deselection 2430 if (mSelectionHandleController != null) { 2431 mSelectionHandleController.hideAndDisallowAutomaticShowing(); 2432 } 2433 if (mInsertionHandleController != null) { 2434 mInsertionHandleController.hideAndDisallowAutomaticShowing(); 2435 } 2436 } 2437 mHasSelection = false; 2438 } 2439 } 2440 2441 @SuppressWarnings("unused") 2442 @CalledByNative 2443 private static void onEvaluateJavaScriptResult( 2444 String jsonResult, JavaScriptCallback callback) { 2445 callback.handleJavaScriptResult(jsonResult); 2446 } 2447 2448 @SuppressWarnings("unused") 2449 @CalledByNative 2450 private void showPastePopup(int xDip, int yDip) { 2451 mInsertionHandlePoint.setLocalDip(xDip, yDip); 2452 getInsertionHandleController().showHandle(); 2453 updateHandleScreenPositions(); 2454 getInsertionHandleController().showHandleWithPastePopup(); 2455 } 2456 2457 @SuppressWarnings("unused") 2458 @CalledByNative 2459 private void onRenderProcessSwap(int oldPid, int newPid) { 2460 assert mPid == oldPid || mPid == newPid; 2461 if (mAttachedToWindow && oldPid != newPid) { 2462 ChildProcessLauncher.unbindAsHighPriority(oldPid); 2463 ChildProcessLauncher.bindAsHighPriority(newPid); 2464 } 2465 2466 // We want to remove the initial binding even if the ContentView is not attached, so that 2467 // renderers for ContentViews loading in background do not retain the high priority. 2468 ChildProcessLauncher.removeInitialBinding(newPid); 2469 mPid = newPid; 2470 } 2471 2472 @SuppressWarnings("unused") 2473 @CalledByNative 2474 private void onWebContentsConnected() { 2475 if (mImeAdapter != null && 2476 !mImeAdapter.isNativeImeAdapterAttached() && mNativeContentViewCore != 0) { 2477 mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore)); 2478 } 2479 } 2480 2481 @SuppressWarnings("unused") 2482 @CalledByNative 2483 private void onWebContentsSwapped() { 2484 if (mImeAdapter != null && mNativeContentViewCore != 0) { 2485 mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore)); 2486 } 2487 } 2488 2489 /** 2490 * @return Whether a reload happens when this ContentView is activated. 2491 */ 2492 public boolean needsReload() { 2493 return mNativeContentViewCore != 0 && nativeNeedsReload(mNativeContentViewCore); 2494 } 2495 2496 /** 2497 * @see View#hasFocus() 2498 */ 2499 @CalledByNative 2500 public boolean hasFocus() { 2501 return mContainerView.hasFocus(); 2502 } 2503 2504 /** 2505 * Checks whether the ContentViewCore can be zoomed in. 2506 * 2507 * @return True if the ContentViewCore can be zoomed in. 2508 */ 2509 // This method uses the term 'zoom' for legacy reasons, but relates 2510 // to what chrome calls the 'page scale factor'. 2511 public boolean canZoomIn() { 2512 final float zoomInExtent = mRenderCoordinates.getMaxPageScaleFactor() 2513 - mRenderCoordinates.getPageScaleFactor(); 2514 return zoomInExtent > ZOOM_CONTROLS_EPSILON; 2515 } 2516 2517 /** 2518 * Checks whether the ContentViewCore can be zoomed out. 2519 * 2520 * @return True if the ContentViewCore can be zoomed out. 2521 */ 2522 // This method uses the term 'zoom' for legacy reasons, but relates 2523 // to what chrome calls the 'page scale factor'. 2524 public boolean canZoomOut() { 2525 final float zoomOutExtent = mRenderCoordinates.getPageScaleFactor() 2526 - mRenderCoordinates.getMinPageScaleFactor(); 2527 return zoomOutExtent > ZOOM_CONTROLS_EPSILON; 2528 } 2529 2530 /** 2531 * Zooms in the ContentViewCore by 25% (or less if that would result in 2532 * zooming in more than possible). 2533 * 2534 * @return True if there was a zoom change, false otherwise. 2535 */ 2536 // This method uses the term 'zoom' for legacy reasons, but relates 2537 // to what chrome calls the 'page scale factor'. 2538 public boolean zoomIn() { 2539 if (!canZoomIn()) { 2540 return false; 2541 } 2542 return zoomByDelta(1.25f); 2543 } 2544 2545 /** 2546 * Zooms out the ContentViewCore by 20% (or less if that would result in 2547 * zooming out more than possible). 2548 * 2549 * @return True if there was a zoom change, false otherwise. 2550 */ 2551 // This method uses the term 'zoom' for legacy reasons, but relates 2552 // to what chrome calls the 'page scale factor'. 2553 public boolean zoomOut() { 2554 if (!canZoomOut()) { 2555 return false; 2556 } 2557 return zoomByDelta(0.8f); 2558 } 2559 2560 /** 2561 * Resets the zoom factor of the ContentViewCore. 2562 * 2563 * @return True if there was a zoom change, false otherwise. 2564 */ 2565 // This method uses the term 'zoom' for legacy reasons, but relates 2566 // to what chrome calls the 'page scale factor'. 2567 public boolean zoomReset() { 2568 // The page scale factor is initialized to mNativeMinimumScale when 2569 // the page finishes loading. Thus sets it back to mNativeMinimumScale. 2570 if (!canZoomOut()) return false; 2571 return zoomByDelta( 2572 mRenderCoordinates.getMinPageScaleFactor() 2573 / mRenderCoordinates.getPageScaleFactor()); 2574 } 2575 2576 private boolean zoomByDelta(float delta) { 2577 if (mNativeContentViewCore == 0) { 2578 return false; 2579 } 2580 2581 long timeMs = System.currentTimeMillis(); 2582 int xPix = getViewportWidthPix() / 2; 2583 int yPix = getViewportHeightPix() / 2; 2584 2585 getContentViewGestureHandler().pinchBegin(timeMs, xPix, yPix); 2586 getContentViewGestureHandler().pinchBy(timeMs, xPix, yPix, delta); 2587 getContentViewGestureHandler().pinchEnd(timeMs); 2588 2589 return true; 2590 } 2591 2592 /** 2593 * Invokes the graphical zoom picker widget for this ContentView. 2594 */ 2595 @Override 2596 public void invokeZoomPicker() { 2597 mZoomControlsDelegate.invokeZoomPicker(); 2598 } 2599 2600 /** 2601 * This will mimic {@link #addPossiblyUnsafeJavascriptInterface(Object, String, Class)} 2602 * and automatically pass in {@link JavascriptInterface} as the required annotation. 2603 * 2604 * @param object The Java object to inject into the ContentViewCore's JavaScript context. Null 2605 * values are ignored. 2606 * @param name The name used to expose the instance in JavaScript. 2607 */ 2608 public void addJavascriptInterface(Object object, String name) { 2609 addPossiblyUnsafeJavascriptInterface(object, name, JavascriptInterface.class); 2610 } 2611 2612 /** 2613 * This method injects the supplied Java object into the ContentViewCore. 2614 * The object is injected into the JavaScript context of the main frame, 2615 * using the supplied name. This allows the Java object to be accessed from 2616 * JavaScript. Note that that injected objects will not appear in 2617 * JavaScript until the page is next (re)loaded. For example: 2618 * <pre> view.addJavascriptInterface(new Object(), "injectedObject"); 2619 * view.loadData("<!DOCTYPE html><title></title>", "text/html", null); 2620 * view.loadUrl("javascript:alert(injectedObject.toString())");</pre> 2621 * <p><strong>IMPORTANT:</strong> 2622 * <ul> 2623 * <li> addJavascriptInterface() can be used to allow JavaScript to control 2624 * the host application. This is a powerful feature, but also presents a 2625 * security risk. Use of this method in a ContentViewCore containing 2626 * untrusted content could allow an attacker to manipulate the host 2627 * application in unintended ways, executing Java code with the permissions 2628 * of the host application. Use extreme care when using this method in a 2629 * ContentViewCore which could contain untrusted content. Particular care 2630 * should be taken to avoid unintentional access to inherited methods, such 2631 * as {@link Object#getClass()}. To prevent access to inherited methods, 2632 * pass an annotation for {@code requiredAnnotation}. This will ensure 2633 * that only methods with {@code requiredAnnotation} are exposed to the 2634 * Javascript layer. {@code requiredAnnotation} will be passed to all 2635 * subsequently injected Java objects if any methods return an object. This 2636 * means the same restrictions (or lack thereof) will apply. Alternatively, 2637 * {@link #addJavascriptInterface(Object, String)} can be called, which 2638 * automatically uses the {@link JavascriptInterface} annotation. 2639 * <li> JavaScript interacts with Java objects on a private, background 2640 * thread of the ContentViewCore. Care is therefore required to maintain 2641 * thread safety.</li> 2642 * </ul></p> 2643 * 2644 * @param object The Java object to inject into the 2645 * ContentViewCore's JavaScript context. Null 2646 * values are ignored. 2647 * @param name The name used to expose the instance in 2648 * JavaScript. 2649 * @param requiredAnnotation Restrict exposed methods to ones with this 2650 * annotation. If {@code null} all methods are 2651 * exposed. 2652 * 2653 */ 2654 public void addPossiblyUnsafeJavascriptInterface(Object object, String name, 2655 Class<? extends Annotation> requiredAnnotation) { 2656 if (mNativeContentViewCore != 0 && object != null) { 2657 mJavaScriptInterfaces.put(name, object); 2658 nativeAddJavascriptInterface(mNativeContentViewCore, object, name, requiredAnnotation, 2659 mRetainedJavaScriptObjects); 2660 } 2661 } 2662 2663 /** 2664 * Removes a previously added JavaScript interface with the given name. 2665 * 2666 * @param name The name of the interface to remove. 2667 */ 2668 public void removeJavascriptInterface(String name) { 2669 mJavaScriptInterfaces.remove(name); 2670 if (mNativeContentViewCore != 0) { 2671 nativeRemoveJavascriptInterface(mNativeContentViewCore, name); 2672 } 2673 } 2674 2675 /** 2676 * Return the current scale of the ContentView. 2677 * @return The current page scale factor. 2678 */ 2679 public float getScale() { 2680 return mRenderCoordinates.getPageScaleFactor(); 2681 } 2682 2683 /** 2684 * If the view is ready to draw contents to the screen. In hardware mode, 2685 * the initialization of the surface texture may not occur until after the 2686 * view has been added to the layout. This method will return {@code true} 2687 * once the texture is actually ready. 2688 */ 2689 public boolean isReady() { 2690 return nativeIsRenderWidgetHostViewReady(mNativeContentViewCore); 2691 } 2692 2693 @CalledByNative 2694 private void startContentIntent(String contentUrl) { 2695 getContentViewClient().onStartContentIntent(getContext(), contentUrl); 2696 } 2697 2698 @Override 2699 public void onAccessibilityStateChanged(boolean enabled) { 2700 setAccessibilityState(enabled); 2701 } 2702 2703 /** 2704 * Determines whether or not this ContentViewCore can handle this accessibility action. 2705 * @param action The action to perform. 2706 * @return Whether or not this action is supported. 2707 */ 2708 public boolean supportsAccessibilityAction(int action) { 2709 return mAccessibilityInjector.supportsAccessibilityAction(action); 2710 } 2711 2712 /** 2713 * Attempts to perform an accessibility action on the web content. If the accessibility action 2714 * cannot be processed, it returns {@code null}, allowing the caller to know to call the 2715 * super {@link View#performAccessibilityAction(int, Bundle)} method and use that return value. 2716 * Otherwise the return value from this method should be used. 2717 * @param action The action to perform. 2718 * @param arguments Optional action arguments. 2719 * @return Whether the action was performed or {@code null} if the call should be delegated to 2720 * the super {@link View} class. 2721 */ 2722 public boolean performAccessibilityAction(int action, Bundle arguments) { 2723 if (mAccessibilityInjector.supportsAccessibilityAction(action)) { 2724 return mAccessibilityInjector.performAccessibilityAction(action, arguments); 2725 } 2726 2727 return false; 2728 } 2729 2730 /** 2731 * Set the BrowserAccessibilityManager, used for native accessibility 2732 * (not script injection). This is only set when system accessibility 2733 * has been enabled. 2734 * @param manager The new BrowserAccessibilityManager. 2735 */ 2736 public void setBrowserAccessibilityManager(BrowserAccessibilityManager manager) { 2737 mBrowserAccessibilityManager = manager; 2738 } 2739 2740 /** 2741 * Get the BrowserAccessibilityManager, used for native accessibility 2742 * (not script injection). This will return null when system accessibility 2743 * is not enabled. 2744 * @return This view's BrowserAccessibilityManager. 2745 */ 2746 public BrowserAccessibilityManager getBrowserAccessibilityManager() { 2747 return mBrowserAccessibilityManager; 2748 } 2749 2750 /** 2751 * If native accessibility (not script injection) is enabled, and if this is 2752 * running on JellyBean or later, returns an AccessibilityNodeProvider that 2753 * implements native accessibility for this view. Returns null otherwise. 2754 * @return The AccessibilityNodeProvider, if available, or null otherwise. 2755 */ 2756 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 2757 if (mBrowserAccessibilityManager != null) { 2758 return mBrowserAccessibilityManager.getAccessibilityNodeProvider(); 2759 } else { 2760 return null; 2761 } 2762 } 2763 2764 /** 2765 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 2766 */ 2767 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 2768 // Note: this is only used by the script-injecting accessibility code. 2769 mAccessibilityInjector.onInitializeAccessibilityNodeInfo(info); 2770 } 2771 2772 /** 2773 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 2774 */ 2775 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 2776 // Note: this is only used by the script-injecting accessibility code. 2777 event.setClassName(this.getClass().getName()); 2778 2779 // Identify where the top-left of the screen currently points to. 2780 event.setScrollX(mRenderCoordinates.getScrollXPixInt()); 2781 event.setScrollY(mRenderCoordinates.getScrollYPixInt()); 2782 2783 // The maximum scroll values are determined by taking the content dimensions and 2784 // subtracting off the actual dimensions of the ChromeView. 2785 int maxScrollXPix = Math.max(0, mRenderCoordinates.getMaxHorizontalScrollPixInt()); 2786 int maxScrollYPix = Math.max(0, mRenderCoordinates.getMaxVerticalScrollPixInt()); 2787 event.setScrollable(maxScrollXPix > 0 || maxScrollYPix > 0); 2788 2789 // Setting the maximum scroll values requires API level 15 or higher. 2790 final int SDK_VERSION_REQUIRED_TO_SET_SCROLL = 15; 2791 if (Build.VERSION.SDK_INT >= SDK_VERSION_REQUIRED_TO_SET_SCROLL) { 2792 event.setMaxScrollX(maxScrollXPix); 2793 event.setMaxScrollY(maxScrollYPix); 2794 } 2795 } 2796 2797 /** 2798 * Returns whether accessibility script injection is enabled on the device 2799 */ 2800 public boolean isDeviceAccessibilityScriptInjectionEnabled() { 2801 try { 2802 if (!mContentSettings.getJavaScriptEnabled()) { 2803 return false; 2804 } 2805 2806 int result = getContext().checkCallingOrSelfPermission( 2807 android.Manifest.permission.INTERNET); 2808 if (result != PackageManager.PERMISSION_GRANTED) { 2809 return false; 2810 } 2811 2812 Field field = Settings.Secure.class.getField("ACCESSIBILITY_SCRIPT_INJECTION"); 2813 field.setAccessible(true); 2814 String accessibilityScriptInjection = (String) field.get(null); 2815 ContentResolver contentResolver = getContext().getContentResolver(); 2816 2817 if (mAccessibilityScriptInjectionObserver == null) { 2818 ContentObserver contentObserver = new ContentObserver(new Handler()) { 2819 public void onChange(boolean selfChange, Uri uri) { 2820 setAccessibilityState(mAccessibilityManager.isEnabled()); 2821 } 2822 }; 2823 contentResolver.registerContentObserver( 2824 Settings.Secure.getUriFor(accessibilityScriptInjection), 2825 false, 2826 contentObserver); 2827 mAccessibilityScriptInjectionObserver = contentObserver; 2828 } 2829 2830 return Settings.Secure.getInt(contentResolver, accessibilityScriptInjection, 0) == 1; 2831 } catch (NoSuchFieldException e) { 2832 } catch (IllegalAccessException e) { 2833 } 2834 return false; 2835 } 2836 2837 /** 2838 * Returns whether or not accessibility injection is being used. 2839 */ 2840 public boolean isInjectingAccessibilityScript() { 2841 return mAccessibilityInjector.accessibilityIsAvailable(); 2842 } 2843 2844 /** 2845 * Turns browser accessibility on or off. 2846 * If |state| is |false|, this turns off both native and injected accessibility. 2847 * Otherwise, if accessibility script injection is enabled, this will enable the injected 2848 * accessibility scripts, and if it is disabled this will enable the native accessibility. 2849 */ 2850 public void setAccessibilityState(boolean state) { 2851 boolean injectedAccessibility = false; 2852 boolean nativeAccessibility = false; 2853 if (state) { 2854 if (isDeviceAccessibilityScriptInjectionEnabled()) { 2855 injectedAccessibility = true; 2856 } else { 2857 nativeAccessibility = true; 2858 } 2859 } 2860 setInjectedAccessibility(injectedAccessibility); 2861 setNativeAccessibilityState(nativeAccessibility); 2862 } 2863 2864 /** 2865 * Enable or disable native accessibility features. 2866 */ 2867 public void setNativeAccessibilityState(boolean enabled) { 2868 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 2869 nativeSetAccessibilityEnabled(mNativeContentViewCore, enabled); 2870 } 2871 } 2872 2873 /** 2874 * Enable or disable injected accessibility features 2875 */ 2876 public void setInjectedAccessibility(boolean enabled) { 2877 mAccessibilityInjector.addOrRemoveAccessibilityApisIfNecessary(); 2878 mAccessibilityInjector.setScriptEnabled(enabled); 2879 } 2880 2881 /** 2882 * Stop any TTS notifications that are currently going on. 2883 */ 2884 public void stopCurrentAccessibilityNotifications() { 2885 mAccessibilityInjector.onPageLostFocus(); 2886 } 2887 2888 /** 2889 * Inform WebKit that Fullscreen mode has been exited by the user. 2890 */ 2891 public void exitFullscreen() { 2892 nativeExitFullscreen(mNativeContentViewCore); 2893 } 2894 2895 /** 2896 * Changes whether hiding the top controls is enabled. 2897 * 2898 * @param enableHiding Whether hiding the top controls should be enabled or not. 2899 * @param enableShowing Whether showing the top controls should be enabled or not. 2900 * @param animate Whether the transition should be animated or not. 2901 */ 2902 public void updateTopControlsState(boolean enableHiding, boolean enableShowing, 2903 boolean animate) { 2904 nativeUpdateTopControlsState(mNativeContentViewCore, enableHiding, enableShowing, animate); 2905 } 2906 2907 /** 2908 * Callback factory method for nativeGetNavigationHistory(). 2909 */ 2910 @CalledByNative 2911 private void addToNavigationHistory(Object history, int index, String url, String virtualUrl, 2912 String originalUrl, String title, Bitmap favicon) { 2913 NavigationEntry entry = new NavigationEntry( 2914 index, url, virtualUrl, originalUrl, title, favicon); 2915 ((NavigationHistory) history).addEntry(entry); 2916 } 2917 2918 /** 2919 * Get a copy of the navigation history of the view. 2920 */ 2921 public NavigationHistory getNavigationHistory() { 2922 NavigationHistory history = new NavigationHistory(); 2923 int currentIndex = nativeGetNavigationHistory(mNativeContentViewCore, history); 2924 history.setCurrentEntryIndex(currentIndex); 2925 return history; 2926 } 2927 2928 @Override 2929 public NavigationHistory getDirectedNavigationHistory(boolean isForward, int itemLimit) { 2930 NavigationHistory history = new NavigationHistory(); 2931 nativeGetDirectedNavigationHistory(mNativeContentViewCore, history, isForward, itemLimit); 2932 return history; 2933 } 2934 2935 /** 2936 * @return The original request URL for the current navigation entry, or null if there is no 2937 * current entry. 2938 */ 2939 public String getOriginalUrlForActiveNavigationEntry() { 2940 return nativeGetOriginalUrlForActiveNavigationEntry(mNativeContentViewCore); 2941 } 2942 2943 /** 2944 * @return The cached copy of render positions and scales. 2945 */ 2946 public RenderCoordinates getRenderCoordinates() { 2947 return mRenderCoordinates; 2948 } 2949 2950 @CalledByNative 2951 private static Rect createRect(int x, int y, int right, int bottom) { 2952 return new Rect(x, y, right, bottom); 2953 } 2954 2955 public void attachExternalVideoSurface(int playerId, Surface surface) { 2956 if (mNativeContentViewCore != 0) { 2957 nativeAttachExternalVideoSurface(mNativeContentViewCore, playerId, surface); 2958 } 2959 } 2960 2961 public void detachExternalVideoSurface(int playerId) { 2962 if (mNativeContentViewCore != 0) { 2963 nativeDetachExternalVideoSurface(mNativeContentViewCore, playerId); 2964 } 2965 } 2966 2967 private boolean onAnimate(long frameTimeMicros) { 2968 if (mNativeContentViewCore == 0) return false; 2969 return nativeOnAnimate(mNativeContentViewCore, frameTimeMicros); 2970 } 2971 2972 private void animateIfNecessary(long frameTimeMicros) { 2973 if (mNeedAnimate) { 2974 mNeedAnimate = onAnimate(frameTimeMicros); 2975 if (!mNeedAnimate) setVSyncNotificationEnabled(false); 2976 } 2977 } 2978 2979 @CalledByNative 2980 private void notifyExternalSurface( 2981 int playerId, boolean isRequest, float x, float y, float width, float height) { 2982 if (isRequest) getContentViewClient().onExternalVideoSurfaceRequested(playerId); 2983 getContentViewClient().onGeometryChanged(playerId, new RectF(x, y, x + width, y + height)); 2984 } 2985 2986 /** 2987 * Offer a subset of gesture events to the embedding View, 2988 * primarily for WebView compatibility. 2989 * 2990 * @param type The type of the event. 2991 * 2992 * @return true if the embedder handled the event. 2993 */ 2994 private boolean offerGestureToEmbedder(int type) { 2995 if (type == ContentViewGestureHandler.GESTURE_LONG_PRESS) { 2996 return mContainerView.performLongClick(); 2997 } 2998 return false; 2999 } 3000 3001 private native int nativeInit(boolean hardwareAccelerated, int webContentsPtr, 3002 int viewAndroidPtr, int windowAndroidPtr); 3003 3004 @CalledByNative 3005 private ContentVideoViewClient getContentVideoViewClient() { 3006 return mContentViewClient.getContentVideoViewClient(); 3007 } 3008 3009 private native void nativeOnJavaContentViewCoreDestroyed(int nativeContentViewCoreImpl); 3010 3011 private native void nativeLoadUrl( 3012 int nativeContentViewCoreImpl, 3013 String url, 3014 int loadUrlType, 3015 int transitionType, 3016 int uaOverrideOption, 3017 String extraHeaders, 3018 byte[] postData, 3019 String baseUrlForDataUrl, 3020 String virtualUrlForDataUrl, 3021 boolean canLoadLocalResources); 3022 3023 private native String nativeGetURL(int nativeContentViewCoreImpl); 3024 3025 private native String nativeGetTitle(int nativeContentViewCoreImpl); 3026 3027 private native void nativeShowInterstitialPage( 3028 int nativeContentViewCoreImpl, String url, int nativeInterstitialPageDelegateAndroid); 3029 private native boolean nativeIsShowingInterstitialPage(int nativeContentViewCoreImpl); 3030 3031 private native boolean nativeIsIncognito(int nativeContentViewCoreImpl); 3032 3033 // Returns true if the native side crashed so that java side can draw a sad tab. 3034 private native boolean nativeCrashed(int nativeContentViewCoreImpl); 3035 3036 private native void nativeSetFocus(int nativeContentViewCoreImpl, boolean focused); 3037 3038 private native void nativeSendOrientationChangeEvent( 3039 int nativeContentViewCoreImpl, int orientation); 3040 3041 // All touch events (including flings, scrolls etc) accept coordinates in physical pixels. 3042 private native boolean nativeSendTouchEvent( 3043 int nativeContentViewCoreImpl, long timeMs, int action, TouchPoint[] pts); 3044 3045 private native int nativeSendMouseMoveEvent( 3046 int nativeContentViewCoreImpl, long timeMs, float x, float y); 3047 3048 private native int nativeSendMouseWheelEvent( 3049 int nativeContentViewCoreImpl, long timeMs, float x, float y, float verticalAxis); 3050 3051 private native void nativeScrollBegin( 3052 int nativeContentViewCoreImpl, long timeMs, float x, float y); 3053 3054 private native void nativeScrollEnd(int nativeContentViewCoreImpl, long timeMs); 3055 3056 private native void nativeScrollBy( 3057 int nativeContentViewCoreImpl, long timeMs, float x, float y, 3058 float deltaX, float deltaY, boolean lastInputEventForVSync); 3059 3060 private native void nativeFlingStart( 3061 int nativeContentViewCoreImpl, long timeMs, float x, float y, float vx, float vy); 3062 3063 private native void nativeFlingCancel(int nativeContentViewCoreImpl, long timeMs); 3064 3065 private native void nativeSingleTap( 3066 int nativeContentViewCoreImpl, long timeMs, float x, float y, boolean linkPreviewTap); 3067 3068 private native void nativeSingleTapUnconfirmed( 3069 int nativeContentViewCoreImpl, long timeMs, float x, float y); 3070 3071 private native void nativeShowPressState( 3072 int nativeContentViewCoreImpl, long timeMs, float x, float y); 3073 3074 private native void nativeShowPressCancel( 3075 int nativeContentViewCoreImpl, long timeMs, float x, float y); 3076 3077 private native void nativeDoubleTap( 3078 int nativeContentViewCoreImpl, long timeMs, float x, float y); 3079 3080 private native void nativeLongPress( 3081 int nativeContentViewCoreImpl, long timeMs, float x, float y, boolean linkPreviewTap); 3082 3083 private native void nativeLongTap( 3084 int nativeContentViewCoreImpl, long timeMs, float x, float y, boolean linkPreviewTap); 3085 3086 private native void nativePinchBegin( 3087 int nativeContentViewCoreImpl, long timeMs, float x, float y); 3088 3089 private native void nativePinchEnd(int nativeContentViewCoreImpl, long timeMs); 3090 3091 private native void nativePinchBy(int nativeContentViewCoreImpl, long timeMs, 3092 float anchorX, float anchorY, float deltaScale, boolean lastInputEventForVSync); 3093 3094 private native void nativeSelectBetweenCoordinates( 3095 int nativeContentViewCoreImpl, float x1, float y1, float x2, float y2); 3096 3097 private native void nativeMoveCaret(int nativeContentViewCoreImpl, float x, float y); 3098 3099 private native boolean nativeCanGoBack(int nativeContentViewCoreImpl); 3100 private native boolean nativeCanGoForward(int nativeContentViewCoreImpl); 3101 private native boolean nativeCanGoToOffset(int nativeContentViewCoreImpl, int offset); 3102 private native void nativeGoBack(int nativeContentViewCoreImpl); 3103 private native void nativeGoForward(int nativeContentViewCoreImpl); 3104 private native void nativeGoToOffset(int nativeContentViewCoreImpl, int offset); 3105 private native void nativeGoToNavigationIndex(int nativeContentViewCoreImpl, int index); 3106 3107 private native void nativeStopLoading(int nativeContentViewCoreImpl); 3108 3109 private native void nativeReload(int nativeContentViewCoreImpl); 3110 3111 private native void nativeCancelPendingReload(int nativeContentViewCoreImpl); 3112 3113 private native void nativeContinuePendingReload(int nativeContentViewCoreImpl); 3114 3115 private native void nativeSelectPopupMenuItems(int nativeContentViewCoreImpl, int[] indices); 3116 3117 private native void nativeScrollFocusedEditableNodeIntoView(int nativeContentViewCoreImpl); 3118 private native void nativeUndoScrollFocusedEditableNodeIntoView(int nativeContentViewCoreImpl); 3119 private native boolean nativeNeedsReload(int nativeContentViewCoreImpl); 3120 3121 private native void nativeClearHistory(int nativeContentViewCoreImpl); 3122 3123 private native void nativeEvaluateJavaScript(int nativeContentViewCoreImpl, 3124 String script, JavaScriptCallback callback); 3125 3126 private native int nativeGetNativeImeAdapter(int nativeContentViewCoreImpl); 3127 3128 private native int nativeGetCurrentRenderProcessId(int nativeContentViewCoreImpl); 3129 3130 private native int nativeGetBackgroundColor(int nativeContentViewCoreImpl); 3131 3132 private native void nativeOnShow(int nativeContentViewCoreImpl); 3133 private native void nativeOnHide(int nativeContentViewCoreImpl); 3134 3135 private native void nativeSetUseDesktopUserAgent(int nativeContentViewCoreImpl, 3136 boolean enabled, boolean reloadOnChange); 3137 private native boolean nativeGetUseDesktopUserAgent(int nativeContentViewCoreImpl); 3138 3139 private native void nativeClearSslPreferences(int nativeContentViewCoreImpl); 3140 3141 private native void nativeAddJavascriptInterface(int nativeContentViewCoreImpl, Object object, 3142 String name, Class requiredAnnotation, HashSet<Object> retainedObjectSet); 3143 3144 private native void nativeRemoveJavascriptInterface(int nativeContentViewCoreImpl, String name); 3145 3146 private native int nativeGetNavigationHistory(int nativeContentViewCoreImpl, Object context); 3147 private native void nativeGetDirectedNavigationHistory(int nativeContentViewCoreImpl, 3148 Object context, boolean isForward, int maxEntries); 3149 private native String nativeGetOriginalUrlForActiveNavigationEntry( 3150 int nativeContentViewCoreImpl); 3151 3152 private native void nativeUpdateVSyncParameters(int nativeContentViewCoreImpl, 3153 long timebaseMicros, long intervalMicros); 3154 3155 private native void nativeOnVSync(int nativeContentViewCoreImpl, long frameTimeMicros); 3156 3157 private native boolean nativeOnAnimate(int nativeContentViewCoreImpl, long frameTimeMicros); 3158 3159 private native boolean nativePopulateBitmapFromCompositor(int nativeContentViewCoreImpl, 3160 Bitmap bitmap); 3161 3162 private native void nativeWasResized(int nativeContentViewCoreImpl); 3163 3164 private native boolean nativeIsRenderWidgetHostViewReady(int nativeContentViewCoreImpl); 3165 3166 private native void nativeExitFullscreen(int nativeContentViewCoreImpl); 3167 private native void nativeUpdateTopControlsState(int nativeContentViewCoreImpl, 3168 boolean enableHiding, boolean enableShowing, boolean animate); 3169 3170 private native void nativeShowImeIfNeeded(int nativeContentViewCoreImpl); 3171 3172 private native void nativeAttachExternalVideoSurface( 3173 int nativeContentViewCoreImpl, int playerId, Surface surface); 3174 3175 private native void nativeDetachExternalVideoSurface( 3176 int nativeContentViewCoreImpl, int playerId); 3177 3178 private native void nativeSetAccessibilityEnabled( 3179 int nativeContentViewCoreImpl, boolean enabled); 3180} 3181