ContentView.java revision 0529e5d033099cbfc42635f6f6183833b09dff6e
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 org.chromium.base.TraceEvent; 22import org.chromium.ui.base.WindowAndroid; 23 24/** 25 * The containing view for {@link ContentViewCore} that exists in the Android UI hierarchy and 26 * exposes the various {@link View} functionality to it. 27 * 28 * TODO(joth): Remove any methods overrides from this class that were added for WebView 29 * compatibility. 30 */ 31public class ContentView extends FrameLayout 32 implements ContentViewCore.InternalAccessDelegate, PageInfo { 33 34 private final ContentViewCore mContentViewCore; 35 36 private float mCurrentTouchOffsetX; 37 private float mCurrentTouchOffsetY; 38 private final int[] mLocationInWindow = new int[2]; 39 40 /** 41 * Creates an instance of a ContentView. 42 * @param context The Context the view is running in, through which it can 43 * access the current theme, resources, etc. 44 * @param nativeWebContents A pointer to the native web contents. 45 * @param windowAndroid An instance of the WindowAndroid. 46 * @return A ContentView instance. 47 */ 48 public static ContentView newInstance( 49 Context context, long nativeWebContents, WindowAndroid windowAndroid) { 50 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { 51 return new ContentView(context, nativeWebContents, windowAndroid); 52 } else { 53 return new JellyBeanContentView(context, nativeWebContents, windowAndroid); 54 } 55 } 56 57 protected ContentView(Context context, long nativeWebContents, WindowAndroid windowAndroid) { 58 super(context, null, android.R.attr.webViewStyle); 59 60 if (getScrollBarStyle() == View.SCROLLBARS_INSIDE_OVERLAY) { 61 setHorizontalScrollBarEnabled(false); 62 setVerticalScrollBarEnabled(false); 63 } 64 65 setFocusable(true); 66 setFocusableInTouchMode(true); 67 68 mContentViewCore = new ContentViewCore(context); 69 mContentViewCore.initialize(this, this, nativeWebContents, windowAndroid); 70 } 71 72 // PageInfo implementation. 73 74 @Override 75 public String getTitle() { 76 return mContentViewCore.getTitle(); 77 } 78 79 @Override 80 public int getBackgroundColor() { 81 return mContentViewCore.getBackgroundColor(); 82 } 83 84 @Override 85 public View getView() { 86 return this; 87 } 88 89 /** 90 * @return The core component of the ContentView that handles JNI communication. Should only be 91 * used for passing to native. 92 */ 93 public ContentViewCore getContentViewCore() { 94 return mContentViewCore; 95 } 96 97 // FrameLayout overrides. 98 99 // Needed by ContentViewCore.InternalAccessDelegate 100 @Override 101 public boolean drawChild(Canvas canvas, View child, long drawingTime) { 102 return super.drawChild(canvas, child, drawingTime); 103 } 104 105 // Needed by ContentViewCore.InternalAccessDelegate 106 @Override 107 public void onScrollChanged(int l, int t, int oldl, int oldt) { 108 super.onScrollChanged(l, t, oldl, oldt); 109 } 110 111 @Override 112 protected void onSizeChanged(int w, int h, int ow, int oh) { 113 TraceEvent.begin(); 114 super.onSizeChanged(w, h, ow, oh); 115 mContentViewCore.onSizeChanged(w, h, ow, oh); 116 TraceEvent.end(); 117 } 118 119 @Override 120 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 121 super.onLayout(changed, left, top, right, bottom); 122 if (changed) { 123 getLocationInWindow(mLocationInWindow); 124 mContentViewCore.onLocationInWindowChanged(mLocationInWindow[0], mLocationInWindow[1]); 125 } 126 } 127 128 @Override 129 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 130 return mContentViewCore.onCreateInputConnection(outAttrs); 131 } 132 133 @Override 134 public boolean onCheckIsTextEditor() { 135 return mContentViewCore.onCheckIsTextEditor(); 136 } 137 138 @Override 139 protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { 140 TraceEvent.begin(); 141 super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); 142 mContentViewCore.onFocusChanged(gainFocus); 143 TraceEvent.end(); 144 } 145 146 @Override 147 public void onWindowFocusChanged(boolean hasWindowFocus) { 148 super.onWindowFocusChanged(hasWindowFocus); 149 mContentViewCore.onWindowFocusChanged(hasWindowFocus); 150 } 151 152 @Override 153 public boolean onKeyUp(int keyCode, KeyEvent event) { 154 return mContentViewCore.onKeyUp(keyCode, event); 155 } 156 157 @Override 158 public boolean dispatchKeyEventPreIme(KeyEvent event) { 159 return mContentViewCore.dispatchKeyEventPreIme(event); 160 } 161 162 @Override 163 public boolean dispatchKeyEvent(KeyEvent event) { 164 if (isFocused()) { 165 return mContentViewCore.dispatchKeyEvent(event); 166 } else { 167 return super.dispatchKeyEvent(event); 168 } 169 } 170 171 @Override 172 public boolean onTouchEvent(MotionEvent event) { 173 MotionEvent offset = createOffsetMotionEvent(event); 174 boolean consumed = mContentViewCore.onTouchEvent(offset); 175 offset.recycle(); 176 return consumed; 177 } 178 179 /** 180 * Mouse move events are sent on hover enter, hover move and hover exit. 181 * They are sent on hover exit because sometimes it acts as both a hover 182 * move and hover exit. 183 */ 184 @Override 185 public boolean onHoverEvent(MotionEvent event) { 186 MotionEvent offset = createOffsetMotionEvent(event); 187 boolean consumed = mContentViewCore.onHoverEvent(offset); 188 offset.recycle(); 189 if (!mContentViewCore.isTouchExplorationEnabled()) super.onHoverEvent(event); 190 return consumed; 191 } 192 193 @Override 194 public boolean onGenericMotionEvent(MotionEvent event) { 195 return mContentViewCore.onGenericMotionEvent(event); 196 } 197 198 @Override 199 public boolean performLongClick() { 200 return false; 201 } 202 203 /** 204 * Sets the current amount to offset incoming touch events by. This is used to handle content 205 * moving and not lining up properly with the android input system. 206 * @param dx The X offset in pixels to shift touch events. 207 * @param dy The Y offset in pixels to shift touch events. 208 */ 209 public void setCurrentMotionEventOffsets(float dx, float dy) { 210 mCurrentTouchOffsetX = dx; 211 mCurrentTouchOffsetY = dy; 212 } 213 214 private MotionEvent createOffsetMotionEvent(MotionEvent src) { 215 MotionEvent dst = MotionEvent.obtain(src); 216 dst.offsetLocation(mCurrentTouchOffsetX, mCurrentTouchOffsetY); 217 return dst; 218 } 219 220 @Override 221 protected void onConfigurationChanged(Configuration newConfig) { 222 mContentViewCore.onConfigurationChanged(newConfig); 223 } 224 225 /** 226 * Currently the ContentView scrolling happens in the native side. In 227 * the Java view system, it is always pinned at (0, 0). scrollBy() and scrollTo() 228 * are overridden, so that View's mScrollX and mScrollY will be unchanged at 229 * (0, 0). This is critical for drawing ContentView correctly. 230 */ 231 @Override 232 public void scrollBy(int x, int y) { 233 mContentViewCore.scrollBy(x, y); 234 } 235 236 @Override 237 public void scrollTo(int x, int y) { 238 mContentViewCore.scrollTo(x, y); 239 } 240 241 @Override 242 protected int computeHorizontalScrollExtent() { 243 // TODO(dtrainor): Need to expose scroll events properly to public. Either make getScroll* 244 // work or expose computeHorizontalScrollOffset()/computeVerticalScrollOffset as public. 245 return mContentViewCore.computeHorizontalScrollExtent(); 246 } 247 248 @Override 249 protected int computeHorizontalScrollOffset() { 250 return mContentViewCore.computeHorizontalScrollOffset(); 251 } 252 253 @Override 254 protected int computeHorizontalScrollRange() { 255 return mContentViewCore.computeHorizontalScrollRange(); 256 } 257 258 @Override 259 protected int computeVerticalScrollExtent() { 260 return mContentViewCore.computeVerticalScrollExtent(); 261 } 262 263 @Override 264 protected int computeVerticalScrollOffset() { 265 return mContentViewCore.computeVerticalScrollOffset(); 266 } 267 268 @Override 269 protected int computeVerticalScrollRange() { 270 return mContentViewCore.computeVerticalScrollRange(); 271 } 272 273 // End FrameLayout overrides. 274 275 @Override 276 public boolean awakenScrollBars(int startDelay, boolean invalidate) { 277 return mContentViewCore.awakenScrollBars(startDelay, invalidate); 278 } 279 280 @Override 281 public boolean awakenScrollBars() { 282 return super.awakenScrollBars(); 283 } 284 285 @Override 286 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 287 super.onInitializeAccessibilityNodeInfo(info); 288 mContentViewCore.onInitializeAccessibilityNodeInfo(info); 289 } 290 291 /** 292 * Fills in scrolling values for AccessibilityEvents. 293 * @param event Event being fired. 294 */ 295 @Override 296 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 297 super.onInitializeAccessibilityEvent(event); 298 mContentViewCore.onInitializeAccessibilityEvent(event); 299 } 300 301 @Override 302 protected void onAttachedToWindow() { 303 super.onAttachedToWindow(); 304 mContentViewCore.onAttachedToWindow(); 305 } 306 307 @Override 308 protected void onDetachedFromWindow() { 309 super.onDetachedFromWindow(); 310 mContentViewCore.onDetachedFromWindow(); 311 } 312 313 @Override 314 protected void onVisibilityChanged(View changedView, int visibility) { 315 super.onVisibilityChanged(changedView, visibility); 316 mContentViewCore.onVisibilityChanged(changedView, visibility); 317 } 318 319 /** 320 * Return content scroll y. 321 * 322 * @return The vertical scroll position in pixels. 323 */ 324 public int getContentScrollY() { 325 return mContentViewCore.computeVerticalScrollOffset(); 326 } 327 328 /** 329 * Return content height. 330 * 331 * @return The height of the content in pixels. 332 */ 333 public int getContentHeight() { 334 return mContentViewCore.computeVerticalScrollRange(); 335 } 336 337 /////////////////////////////////////////////////////////////////////////////////////////////// 338 // Start Implementation of ContentViewCore.InternalAccessDelegate // 339 /////////////////////////////////////////////////////////////////////////////////////////////// 340 341 @Override 342 public boolean super_onKeyUp(int keyCode, KeyEvent event) { 343 return super.onKeyUp(keyCode, event); 344 } 345 346 @Override 347 public boolean super_dispatchKeyEventPreIme(KeyEvent event) { 348 return super.dispatchKeyEventPreIme(event); 349 } 350 351 @Override 352 public boolean super_dispatchKeyEvent(KeyEvent event) { 353 return super.dispatchKeyEvent(event); 354 } 355 356 @Override 357 public boolean super_onGenericMotionEvent(MotionEvent event) { 358 return super.onGenericMotionEvent(event); 359 } 360 361 @Override 362 public void super_onConfigurationChanged(Configuration newConfig) { 363 super.onConfigurationChanged(newConfig); 364 } 365 366 @Override 367 public boolean super_awakenScrollBars(int startDelay, boolean invalidate) { 368 return super.awakenScrollBars(startDelay, invalidate); 369 } 370 371 /////////////////////////////////////////////////////////////////////////////////////////////// 372 // End Implementation of ContentViewCore.InternalAccessDelegate // 373 /////////////////////////////////////////////////////////////////////////////////////////////// 374} 375