ContentView.java revision a02191e04bc25c4935f804f2c080ae28663d096d
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.content.Context; 8import android.content.res.Configuration; 9import android.graphics.Canvas; 10import android.graphics.Rect; 11import android.os.Build; 12import android.view.KeyEvent; 13import android.view.MotionEvent; 14import android.view.View; 15import android.view.accessibility.AccessibilityEvent; 16import android.view.accessibility.AccessibilityNodeInfo; 17import android.view.inputmethod.EditorInfo; 18import android.view.inputmethod.InputConnection; 19import android.widget.FrameLayout; 20 21import com.google.common.annotations.VisibleForTesting; 22 23import org.chromium.base.TraceEvent; 24import org.chromium.ui.base.WindowAndroid; 25 26/** 27 * The containing view for {@link ContentViewCore} that exists in the Android UI hierarchy and 28 * exposes the various {@link View} functionality to it. 29 * 30 * TODO(joth): Remove any methods overrides from this class that were added for WebView 31 * compatibility. 32 */ 33public class ContentView extends FrameLayout 34 implements ContentViewCore.InternalAccessDelegate, PageInfo { 35 36 private final ContentViewCore mContentViewCore; 37 38 private float mCurrentTouchOffsetX; 39 private float mCurrentTouchOffsetY; 40 private final int[] mLocationInWindow = new int[2]; 41 42 /** 43 * Creates an instance of a ContentView. 44 * @param context The Context the view is running in, through which it can 45 * access the current theme, resources, etc. 46 * @param nativeWebContents A pointer to the native web contents. 47 * @param windowAndroid An instance of the WindowAndroid. 48 * @return A ContentView instance. 49 */ 50 public static ContentView newInstance( 51 Context context, long nativeWebContents, WindowAndroid windowAndroid) { 52 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { 53 return new ContentView(context, nativeWebContents, windowAndroid); 54 } else { 55 return new JellyBeanContentView(context, nativeWebContents, windowAndroid); 56 } 57 } 58 59 protected ContentView(Context context, long nativeWebContents, WindowAndroid windowAndroid) { 60 super(context, null, android.R.attr.webViewStyle); 61 62 if (getScrollBarStyle() == View.SCROLLBARS_INSIDE_OVERLAY) { 63 setHorizontalScrollBarEnabled(false); 64 setVerticalScrollBarEnabled(false); 65 } 66 67 setFocusable(true); 68 setFocusableInTouchMode(true); 69 70 mContentViewCore = new ContentViewCore(context); 71 mContentViewCore.initialize(this, this, nativeWebContents, windowAndroid); 72 } 73 74 /** 75 * @return The URL of the page. 76 */ 77 public String getUrl() { 78 return mContentViewCore.getUrl(); 79 } 80 81 // PageInfo implementation. 82 83 @Override 84 public String getTitle() { 85 return mContentViewCore.getTitle(); 86 } 87 88 @Override 89 public int getBackgroundColor() { 90 return mContentViewCore.getBackgroundColor(); 91 } 92 93 @Override 94 public View getView() { 95 return this; 96 } 97 98 /** 99 * @return The core component of the ContentView that handles JNI communication. Should only be 100 * used for passing to native. 101 */ 102 public ContentViewCore getContentViewCore() { 103 return mContentViewCore; 104 } 105 106 /** 107 * Destroy the internal state of the WebView. This method may only be called 108 * after the WebView has been removed from the view system. No other methods 109 * may be called on this WebView after this method has been called. 110 */ 111 public void destroy() { 112 mContentViewCore.destroy(); 113 } 114 115 /** 116 * Returns true initially, false after destroy() has been called. 117 * It is illegal to call any other public method after destroy(). 118 */ 119 public boolean isAlive() { 120 return mContentViewCore.isAlive(); 121 } 122 123 @VisibleForTesting 124 public ContentViewClient getContentViewClient() { 125 return mContentViewCore.getContentViewClient(); 126 } 127 128 /** 129 * Load url without fixing up the url string. Consumers of ContentView are responsible for 130 * ensuring the URL passed in is properly formatted (i.e. the scheme has been added if left 131 * off during user input). 132 * 133 * @param params Parameters for this load. 134 */ 135 public void loadUrl(LoadUrlParams params) { 136 mContentViewCore.loadUrl(params); 137 } 138 139 /** 140 * @return Whether the current WebContents has a previous navigation entry. 141 */ 142 public boolean canGoBack() { 143 return mContentViewCore.canGoBack(); 144 } 145 146 /** 147 * @return Whether the current WebContents has a navigation entry after the current one. 148 */ 149 public boolean canGoForward() { 150 return mContentViewCore.canGoForward(); 151 } 152 153 /** 154 * Goes to the navigation entry before the current one. 155 */ 156 public void goBack() { 157 mContentViewCore.goBack(); 158 } 159 160 /** 161 * Goes to the navigation entry following the current one. 162 */ 163 public void goForward() { 164 mContentViewCore.goForward(); 165 } 166 167 /** 168 * Fling the ContentView from the current position. 169 * @param x Fling touch starting position 170 * @param y Fling touch starting position 171 * @param velocityX Initial velocity of the fling (X) measured in pixels per second. 172 * @param velocityY Initial velocity of the fling (Y) measured in pixels per second. 173 */ 174 @VisibleForTesting 175 public void fling(long timeMs, int x, int y, int velocityX, int velocityY) { 176 mContentViewCore.flingForTest(timeMs, x, y, velocityX, velocityY); 177 } 178 179 /** 180 * To be called when the ContentView is shown. 181 **/ 182 public void onShow() { 183 mContentViewCore.onShow(); 184 } 185 186 /** 187 * To be called when the ContentView is hidden. 188 **/ 189 public void onHide() { 190 mContentViewCore.onHide(); 191 } 192 193 /** 194 * Hides the select action bar. 195 */ 196 public void hideSelectActionBar() { 197 mContentViewCore.hideSelectActionBar(); 198 } 199 200 // FrameLayout overrides. 201 202 // Needed by ContentViewCore.InternalAccessDelegate 203 @Override 204 public boolean drawChild(Canvas canvas, View child, long drawingTime) { 205 return super.drawChild(canvas, child, drawingTime); 206 } 207 208 // Needed by ContentViewCore.InternalAccessDelegate 209 @Override 210 public void onScrollChanged(int l, int t, int oldl, int oldt) { 211 super.onScrollChanged(l, t, oldl, oldt); 212 } 213 214 @Override 215 protected void onSizeChanged(int w, int h, int ow, int oh) { 216 TraceEvent.begin(); 217 super.onSizeChanged(w, h, ow, oh); 218 mContentViewCore.onSizeChanged(w, h, ow, oh); 219 TraceEvent.end(); 220 } 221 222 @Override 223 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 224 super.onLayout(changed, left, top, right, bottom); 225 if (changed) { 226 getLocationInWindow(mLocationInWindow); 227 mContentViewCore.onLocationInWindowChanged(mLocationInWindow[0], mLocationInWindow[1]); 228 } 229 } 230 231 @Override 232 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 233 return mContentViewCore.onCreateInputConnection(outAttrs); 234 } 235 236 @Override 237 public boolean onCheckIsTextEditor() { 238 return mContentViewCore.onCheckIsTextEditor(); 239 } 240 241 @Override 242 protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { 243 TraceEvent.begin(); 244 super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); 245 mContentViewCore.onFocusChanged(gainFocus); 246 TraceEvent.end(); 247 } 248 249 @Override 250 public void onWindowFocusChanged(boolean hasWindowFocus) { 251 super.onWindowFocusChanged(hasWindowFocus); 252 mContentViewCore.onWindowFocusChanged(hasWindowFocus); 253 } 254 255 @Override 256 public boolean onKeyUp(int keyCode, KeyEvent event) { 257 return mContentViewCore.onKeyUp(keyCode, event); 258 } 259 260 @Override 261 public boolean dispatchKeyEventPreIme(KeyEvent event) { 262 return mContentViewCore.dispatchKeyEventPreIme(event); 263 } 264 265 @Override 266 public boolean dispatchKeyEvent(KeyEvent event) { 267 if (isFocused()) { 268 return mContentViewCore.dispatchKeyEvent(event); 269 } else { 270 return super.dispatchKeyEvent(event); 271 } 272 } 273 274 @Override 275 public boolean onTouchEvent(MotionEvent event) { 276 MotionEvent offset = createOffsetMotionEvent(event); 277 boolean consumed = mContentViewCore.onTouchEvent(offset); 278 offset.recycle(); 279 return consumed; 280 } 281 282 /** 283 * Mouse move events are sent on hover enter, hover move and hover exit. 284 * They are sent on hover exit because sometimes it acts as both a hover 285 * move and hover exit. 286 */ 287 @Override 288 public boolean onHoverEvent(MotionEvent event) { 289 MotionEvent offset = createOffsetMotionEvent(event); 290 boolean consumed = mContentViewCore.onHoverEvent(offset); 291 offset.recycle(); 292 super.onHoverEvent(event); 293 return consumed; 294 } 295 296 @Override 297 public boolean onGenericMotionEvent(MotionEvent event) { 298 return mContentViewCore.onGenericMotionEvent(event); 299 } 300 301 @Override 302 public boolean performLongClick() { 303 return false; 304 } 305 306 /** 307 * Sets the current amount to offset incoming touch events by. This is used to handle content 308 * moving and not lining up properly with the android input system. 309 * @param dx The X offset in pixels to shift touch events. 310 * @param dy The Y offset in pixels to shift touch events. 311 */ 312 public void setCurrentMotionEventOffsets(float dx, float dy) { 313 mCurrentTouchOffsetX = dx; 314 mCurrentTouchOffsetY = dy; 315 } 316 317 private MotionEvent createOffsetMotionEvent(MotionEvent src) { 318 MotionEvent dst = MotionEvent.obtain(src); 319 dst.offsetLocation(mCurrentTouchOffsetX, mCurrentTouchOffsetY); 320 return dst; 321 } 322 323 @Override 324 protected void onConfigurationChanged(Configuration newConfig) { 325 mContentViewCore.onConfigurationChanged(newConfig); 326 } 327 328 /** 329 * Currently the ContentView scrolling happens in the native side. In 330 * the Java view system, it is always pinned at (0, 0). scrollBy() and scrollTo() 331 * are overridden, so that View's mScrollX and mScrollY will be unchanged at 332 * (0, 0). This is critical for drawing ContentView correctly. 333 */ 334 @Override 335 public void scrollBy(int x, int y) { 336 mContentViewCore.scrollBy(x, y); 337 } 338 339 @Override 340 public void scrollTo(int x, int y) { 341 mContentViewCore.scrollTo(x, y); 342 } 343 344 @Override 345 protected int computeHorizontalScrollExtent() { 346 // TODO(dtrainor): Need to expose scroll events properly to public. Either make getScroll* 347 // work or expose computeHorizontalScrollOffset()/computeVerticalScrollOffset as public. 348 return mContentViewCore.computeHorizontalScrollExtent(); 349 } 350 351 @Override 352 protected int computeHorizontalScrollOffset() { 353 return mContentViewCore.computeHorizontalScrollOffset(); 354 } 355 356 @Override 357 protected int computeHorizontalScrollRange() { 358 return mContentViewCore.computeHorizontalScrollRange(); 359 } 360 361 @Override 362 protected int computeVerticalScrollExtent() { 363 return mContentViewCore.computeVerticalScrollExtent(); 364 } 365 366 @Override 367 protected int computeVerticalScrollOffset() { 368 return mContentViewCore.computeVerticalScrollOffset(); 369 } 370 371 @Override 372 protected int computeVerticalScrollRange() { 373 return mContentViewCore.computeVerticalScrollRange(); 374 } 375 376 // End FrameLayout overrides. 377 378 @Override 379 public boolean awakenScrollBars(int startDelay, boolean invalidate) { 380 return mContentViewCore.awakenScrollBars(startDelay, invalidate); 381 } 382 383 @Override 384 public boolean awakenScrollBars() { 385 return super.awakenScrollBars(); 386 } 387 388 public int getSingleTapX() { 389 return mContentViewCore.getSingleTapX(); 390 } 391 392 public int getSingleTapY() { 393 return mContentViewCore.getSingleTapY(); 394 } 395 396 @Override 397 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 398 super.onInitializeAccessibilityNodeInfo(info); 399 mContentViewCore.onInitializeAccessibilityNodeInfo(info); 400 } 401 402 /** 403 * Fills in scrolling values for AccessibilityEvents. 404 * @param event Event being fired. 405 */ 406 @Override 407 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 408 super.onInitializeAccessibilityEvent(event); 409 mContentViewCore.onInitializeAccessibilityEvent(event); 410 } 411 412 @Override 413 protected void onAttachedToWindow() { 414 super.onAttachedToWindow(); 415 mContentViewCore.onAttachedToWindow(); 416 } 417 418 @Override 419 protected void onDetachedFromWindow() { 420 super.onDetachedFromWindow(); 421 mContentViewCore.onDetachedFromWindow(); 422 } 423 424 @Override 425 protected void onVisibilityChanged(View changedView, int visibility) { 426 super.onVisibilityChanged(changedView, visibility); 427 mContentViewCore.onVisibilityChanged(changedView, visibility); 428 } 429 430 /** 431 * Return the current scale of the WebView 432 * @return The current scale. 433 */ 434 public float getScale() { 435 return mContentViewCore.getScale(); 436 } 437 438 /** 439 * Enable or disable accessibility features. 440 */ 441 public void setAccessibilityState(boolean state) { 442 mContentViewCore.setAccessibilityState(state); 443 } 444 445 /** 446 * Inform WebKit that Fullscreen mode has been exited by the user. 447 */ 448 public void exitFullscreen() { 449 mContentViewCore.exitFullscreen(); 450 } 451 452 /** 453 * Return content scroll y. 454 * 455 * @return The vertical scroll position in pixels. 456 */ 457 public int getContentScrollY() { 458 return mContentViewCore.computeVerticalScrollOffset(); 459 } 460 461 /** 462 * Return content height. 463 * 464 * @return The height of the content in pixels. 465 */ 466 public int getContentHeight() { 467 return mContentViewCore.computeVerticalScrollRange(); 468 } 469 470 /////////////////////////////////////////////////////////////////////////////////////////////// 471 // Start Implementation of ContentViewCore.InternalAccessDelegate // 472 /////////////////////////////////////////////////////////////////////////////////////////////// 473 474 @Override 475 public boolean super_onKeyUp(int keyCode, KeyEvent event) { 476 return super.onKeyUp(keyCode, event); 477 } 478 479 @Override 480 public boolean super_dispatchKeyEventPreIme(KeyEvent event) { 481 return super.dispatchKeyEventPreIme(event); 482 } 483 484 @Override 485 public boolean super_dispatchKeyEvent(KeyEvent event) { 486 return super.dispatchKeyEvent(event); 487 } 488 489 @Override 490 public boolean super_onGenericMotionEvent(MotionEvent event) { 491 return super.onGenericMotionEvent(event); 492 } 493 494 @Override 495 public void super_onConfigurationChanged(Configuration newConfig) { 496 super.onConfigurationChanged(newConfig); 497 } 498 499 @Override 500 public boolean super_awakenScrollBars(int startDelay, boolean invalidate) { 501 return super.awakenScrollBars(startDelay, invalidate); 502 } 503 504 /////////////////////////////////////////////////////////////////////////////////////////////// 505 // End Implementation of ContentViewCore.InternalAccessDelegate // 506 /////////////////////////////////////////////////////////////////////////////////////////////// 507} 508