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 5 package org.chromium.content.browser; 6 7 import android.content.Context; 8 import android.content.res.Configuration; 9 import android.graphics.Canvas; 10 import android.graphics.Rect; 11 import android.os.Build; 12 import android.os.Bundle; 13 import android.os.Handler; 14 import android.os.Message; 15 import android.util.Log; 16 import android.view.KeyEvent; 17 import android.view.MotionEvent; 18 import android.view.View; 19 import android.view.accessibility.AccessibilityEvent; 20 import android.view.accessibility.AccessibilityNodeInfo; 21 import android.view.inputmethod.EditorInfo; 22 import android.view.inputmethod.InputConnection; 23 import android.widget.FrameLayout; 24 25 import org.chromium.base.TraceEvent; 26 27 /** 28 * The containing view for {@link ContentViewCore} that exists in the Android UI hierarchy and 29 * exposes the various {@link View} functionality to it. 30 */ 31 public class ContentView extends FrameLayout 32 implements ContentViewCore.InternalAccessDelegate, SmartClipProvider { 33 34 private static final String TAG = "ContentView"; 35 36 protected final ContentViewCore mContentViewCore; 37 38 /** 39 * Creates an instance of a ContentView. 40 * @param context The Context the view is running in, through which it can 41 * access the current theme, resources, etc. 42 * @param cvc A pointer to the content view core managing this content view. 43 * @return A ContentView instance. 44 */ 45 public static ContentView newInstance(Context context, ContentViewCore cvc) { 46 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { 47 return new ContentView(context, cvc); 48 } else { 49 return new JellyBeanContentView(context, cvc); 50 } 51 } 52 53 protected ContentView(Context context, ContentViewCore cvc) { 54 super(context, null, android.R.attr.webViewStyle); 55 56 if (getScrollBarStyle() == View.SCROLLBARS_INSIDE_OVERLAY) { 57 setHorizontalScrollBarEnabled(false); 58 setVerticalScrollBarEnabled(false); 59 } 60 61 setFocusable(true); 62 setFocusableInTouchMode(true); 63 64 mContentViewCore = cvc; 65 } 66 67 // Needed by ContentViewCore.InternalAccessDelegate 68 @Override 69 public boolean drawChild(Canvas canvas, View child, long drawingTime) { 70 return super.drawChild(canvas, child, drawingTime); 71 } 72 73 // Needed by ContentViewCore.InternalAccessDelegate 74 @Override 75 public void onScrollChanged(int l, int t, int oldl, int oldt) { 76 super.onScrollChanged(l, t, oldl, oldt); 77 } 78 79 @Override 80 protected void onSizeChanged(int w, int h, int ow, int oh) { 81 TraceEvent.begin(); 82 super.onSizeChanged(w, h, ow, oh); 83 mContentViewCore.onSizeChanged(w, h, ow, oh); 84 TraceEvent.end(); 85 } 86 87 @Override 88 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 89 return mContentViewCore.onCreateInputConnection(outAttrs); 90 } 91 92 @Override 93 public boolean onCheckIsTextEditor() { 94 return mContentViewCore.onCheckIsTextEditor(); 95 } 96 97 @Override 98 protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { 99 TraceEvent.begin(); 100 super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); 101 mContentViewCore.onFocusChanged(gainFocus); 102 TraceEvent.end(); 103 } 104 105 @Override 106 public void onWindowFocusChanged(boolean hasWindowFocus) { 107 super.onWindowFocusChanged(hasWindowFocus); 108 mContentViewCore.onWindowFocusChanged(hasWindowFocus); 109 } 110 111 @Override 112 public boolean onKeyUp(int keyCode, KeyEvent event) { 113 return mContentViewCore.onKeyUp(keyCode, event); 114 } 115 116 @Override 117 public boolean dispatchKeyEventPreIme(KeyEvent event) { 118 return mContentViewCore.dispatchKeyEventPreIme(event); 119 } 120 121 @Override 122 public boolean dispatchKeyEvent(KeyEvent event) { 123 if (isFocused()) { 124 return mContentViewCore.dispatchKeyEvent(event); 125 } else { 126 return super.dispatchKeyEvent(event); 127 } 128 } 129 130 @Override 131 public boolean onTouchEvent(MotionEvent event) { 132 return mContentViewCore.onTouchEvent(event); 133 } 134 135 /** 136 * Mouse move events are sent on hover enter, hover move and hover exit. 137 * They are sent on hover exit because sometimes it acts as both a hover 138 * move and hover exit. 139 */ 140 @Override 141 public boolean onHoverEvent(MotionEvent event) { 142 boolean consumed = mContentViewCore.onHoverEvent(event); 143 if (!mContentViewCore.isTouchExplorationEnabled()) super.onHoverEvent(event); 144 return consumed; 145 } 146 147 @Override 148 public boolean onGenericMotionEvent(MotionEvent event) { 149 return mContentViewCore.onGenericMotionEvent(event); 150 } 151 152 @Override 153 public boolean performLongClick() { 154 return false; 155 } 156 157 @Override 158 protected void onConfigurationChanged(Configuration newConfig) { 159 mContentViewCore.onConfigurationChanged(newConfig); 160 } 161 162 /** 163 * Currently the ContentView scrolling happens in the native side. In 164 * the Java view system, it is always pinned at (0, 0). scrollBy() and scrollTo() 165 * are overridden, so that View's mScrollX and mScrollY will be unchanged at 166 * (0, 0). This is critical for drawing ContentView correctly. 167 */ 168 @Override 169 public void scrollBy(int x, int y) { 170 mContentViewCore.scrollBy(x, y); 171 } 172 173 @Override 174 public void scrollTo(int x, int y) { 175 mContentViewCore.scrollTo(x, y); 176 } 177 178 @Override 179 protected int computeHorizontalScrollExtent() { 180 // TODO(dtrainor): Need to expose scroll events properly to public. Either make getScroll* 181 // work or expose computeHorizontalScrollOffset()/computeVerticalScrollOffset as public. 182 return mContentViewCore.computeHorizontalScrollExtent(); 183 } 184 185 @Override 186 protected int computeHorizontalScrollOffset() { 187 return mContentViewCore.computeHorizontalScrollOffset(); 188 } 189 190 @Override 191 protected int computeHorizontalScrollRange() { 192 return mContentViewCore.computeHorizontalScrollRange(); 193 } 194 195 @Override 196 protected int computeVerticalScrollExtent() { 197 return mContentViewCore.computeVerticalScrollExtent(); 198 } 199 200 @Override 201 protected int computeVerticalScrollOffset() { 202 return mContentViewCore.computeVerticalScrollOffset(); 203 } 204 205 @Override 206 protected int computeVerticalScrollRange() { 207 return mContentViewCore.computeVerticalScrollRange(); 208 } 209 210 // End FrameLayout overrides. 211 212 @Override 213 public boolean awakenScrollBars(int startDelay, boolean invalidate) { 214 return mContentViewCore.awakenScrollBars(startDelay, invalidate); 215 } 216 217 @Override 218 public boolean awakenScrollBars() { 219 return super.awakenScrollBars(); 220 } 221 222 @Override 223 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 224 super.onInitializeAccessibilityNodeInfo(info); 225 mContentViewCore.onInitializeAccessibilityNodeInfo(info); 226 } 227 228 /** 229 * Fills in scrolling values for AccessibilityEvents. 230 * @param event Event being fired. 231 */ 232 @Override 233 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 234 super.onInitializeAccessibilityEvent(event); 235 mContentViewCore.onInitializeAccessibilityEvent(event); 236 } 237 238 @Override 239 protected void onAttachedToWindow() { 240 super.onAttachedToWindow(); 241 mContentViewCore.onAttachedToWindow(); 242 } 243 244 @Override 245 protected void onDetachedFromWindow() { 246 super.onDetachedFromWindow(); 247 mContentViewCore.onDetachedFromWindow(); 248 } 249 250 @Override 251 protected void onVisibilityChanged(View changedView, int visibility) { 252 super.onVisibilityChanged(changedView, visibility); 253 mContentViewCore.onVisibilityChanged(changedView, visibility); 254 } 255 256 // Implements SmartClipProvider 257 @Override 258 public void extractSmartClipData(int x, int y, int width, int height) { 259 mContentViewCore.extractSmartClipData(x, y, width, height); 260 } 261 262 // Implements SmartClipProvider 263 @Override 264 public void setSmartClipResultHandler(final Handler resultHandler) { 265 if (resultHandler == null) { 266 mContentViewCore.setSmartClipDataListener(null); 267 return; 268 } 269 mContentViewCore.setSmartClipDataListener(new ContentViewCore.SmartClipDataListener() { 270 public void onSmartClipDataExtracted(String text, String html, Rect clipRect) { 271 Bundle bundle = new Bundle(); 272 bundle.putString("url", mContentViewCore.getWebContents().getVisibleUrl()); 273 bundle.putString("title", mContentViewCore.getWebContents().getTitle()); 274 bundle.putParcelable("rect", clipRect); 275 bundle.putString("text", text); 276 bundle.putString("html", html); 277 try { 278 Message msg = Message.obtain(resultHandler, 0); 279 msg.setData(bundle); 280 msg.sendToTarget(); 281 } catch (Exception e) { 282 Log.e(TAG, "Error calling handler for smart clip data: ", e); 283 } 284 } 285 }); 286 } 287 288 /////////////////////////////////////////////////////////////////////////////////////////////// 289 // Start Implementation of ContentViewCore.InternalAccessDelegate // 290 /////////////////////////////////////////////////////////////////////////////////////////////// 291 292 @Override 293 public boolean super_onKeyUp(int keyCode, KeyEvent event) { 294 return super.onKeyUp(keyCode, event); 295 } 296 297 @Override 298 public boolean super_dispatchKeyEventPreIme(KeyEvent event) { 299 return super.dispatchKeyEventPreIme(event); 300 } 301 302 @Override 303 public boolean super_dispatchKeyEvent(KeyEvent event) { 304 return super.dispatchKeyEvent(event); 305 } 306 307 @Override 308 public boolean super_onGenericMotionEvent(MotionEvent event) { 309 return super.onGenericMotionEvent(event); 310 } 311 312 @Override 313 public void super_onConfigurationChanged(Configuration newConfig) { 314 super.onConfigurationChanged(newConfig); 315 } 316 317 @Override 318 public boolean super_awakenScrollBars(int startDelay, boolean invalidate) { 319 return super.awakenScrollBars(startDelay, invalidate); 320 } 321 322 /////////////////////////////////////////////////////////////////////////////////////////////// 323 // End Implementation of ContentViewCore.InternalAccessDelegate // 324 /////////////////////////////////////////////////////////////////////////////////////////////// 325 } 326