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.
5 package org.chromium.content.browser;
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.util.AttributeSet;
13 import android.view.KeyEvent;
14 import android.view.MotionEvent;
15 import android.view.View;
16 import android.view.accessibility.AccessibilityEvent;
17 import android.view.accessibility.AccessibilityNodeInfo;
18 import android.view.inputmethod.EditorInfo;
19 import android.view.inputmethod.InputConnection;
20 import android.widget.FrameLayout;
22 import com.google.common.annotations.VisibleForTesting;
24 import org.chromium.base.TraceEvent;
25 import org.chromium.ui.base.WindowAndroid;
28 * The containing view for {@link ContentViewCore} that exists in the Android UI hierarchy and
29 * exposes the various {@link View} functionality to it.
31 * TODO(joth): Remove any methods overrides from this class that were added for WebView
34 public class ContentView extends FrameLayout
35 implements ContentViewCore.InternalAccessDelegate, PageInfo {
37 private final ContentViewCore mContentViewCore;
39 private float mCurrentTouchOffsetX;
40 private float mCurrentTouchOffsetY;
41 private final int[] mLocationInWindow = new int[2];
44 * Creates an instance of a ContentView.
45 * @param context The Context the view is running in, through which it can
46 * access the current theme, resources, etc.
47 * @param nativeWebContents A pointer to the native web contents.
48 * @param windowAndroid An instance of the WindowAndroid.
49 * @return A ContentView instance.
51 public static ContentView newInstance(Context context, long nativeWebContents,
52 WindowAndroid windowAndroid) {
53 return newInstance(context, nativeWebContents, windowAndroid, null,
54 android.R.attr.webViewStyle);
58 * Creates an instance of a ContentView.
59 * @param context The Context the view is running in, through which it can
60 * access the current theme, resources, etc.
61 * @param nativeWebContents A pointer to the native web contents.
62 * @param windowAndroid An instance of the WindowAndroid.
63 * @param attrs The attributes of the XML tag that is inflating the view.
64 * @return A ContentView instance.
66 public static ContentView newInstance(Context context, long nativeWebContents,
67 WindowAndroid windowAndroid, AttributeSet attrs) {
68 // TODO(klobag): use the WebViewStyle as the default style for now. It enables scrollbar.
69 // When ContentView is moved to framework, we can define its own style in the res.
70 return newInstance(context, nativeWebContents, windowAndroid, attrs,
71 android.R.attr.webViewStyle);
75 * Creates an instance of a ContentView.
76 * @param context The Context the view is running in, through which it can
77 * access the current theme, resources, etc.
78 * @param nativeWebContents A pointer to the native web contents.
79 * @param windowAndroid An instance of the WindowAndroid.
80 * @param attrs The attributes of the XML tag that is inflating the view.
81 * @param defStyle The default style to apply to this view.
82 * @return A ContentView instance.
84 public static ContentView newInstance(Context context, long nativeWebContents,
85 WindowAndroid windowAndroid, AttributeSet attrs, int defStyle) {
86 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
87 return new ContentView(context, nativeWebContents, windowAndroid, attrs, defStyle);
89 return new JellyBeanContentView(context, nativeWebContents, windowAndroid, attrs,
94 protected ContentView(Context context, long nativeWebContents, WindowAndroid windowAndroid,
95 AttributeSet attrs, int defStyle) {
96 super(context, attrs, defStyle);
98 if (getScrollBarStyle() == View.SCROLLBARS_INSIDE_OVERLAY) {
99 setHorizontalScrollBarEnabled(false);
100 setVerticalScrollBarEnabled(false);
104 setFocusableInTouchMode(true);
106 mContentViewCore = new ContentViewCore(context);
107 mContentViewCore.initialize(this, this, nativeWebContents, windowAndroid);
111 * @return The URL of the page.
113 public String getUrl() {
114 return mContentViewCore.getUrl();
117 // PageInfo implementation.
120 public String getTitle() {
121 return mContentViewCore.getTitle();
125 public int getBackgroundColor() {
126 return mContentViewCore.getBackgroundColor();
130 public View getView() {
135 * @return The core component of the ContentView that handles JNI communication. Should only be
136 * used for passing to native.
138 public ContentViewCore getContentViewCore() {
139 return mContentViewCore;
143 * @return The cache of scales and positions used to convert coordinates from/to CSS.
145 public RenderCoordinates getRenderCoordinates() {
146 return mContentViewCore.getRenderCoordinates();
150 * Destroy the internal state of the WebView. This method may only be called
151 * after the WebView has been removed from the view system. No other methods
152 * may be called on this WebView after this method has been called.
154 public void destroy() {
155 mContentViewCore.destroy();
159 * Returns true initially, false after destroy() has been called.
160 * It is illegal to call any other public method after destroy().
162 public boolean isAlive() {
163 return mContentViewCore.isAlive();
166 public void setContentViewClient(ContentViewClient client) {
167 mContentViewCore.setContentViewClient(client);
171 public ContentViewClient getContentViewClient() {
172 return mContentViewCore.getContentViewClient();
176 * Load url without fixing up the url string. Consumers of ContentView are responsible for
177 * ensuring the URL passed in is properly formatted (i.e. the scheme has been added if left
178 * off during user input).
180 * @param params Parameters for this load.
182 public void loadUrl(LoadUrlParams params) {
183 mContentViewCore.loadUrl(params);
187 * @return Whether the current WebContents has a previous navigation entry.
189 public boolean canGoBack() {
190 return mContentViewCore.canGoBack();
194 * @return Whether the current WebContents has a navigation entry after the current one.
196 public boolean canGoForward() {
197 return mContentViewCore.canGoForward();
201 * Goes to the navigation entry before the current one.
203 public void goBack() {
204 mContentViewCore.goBack();
208 * Goes to the navigation entry following the current one.
210 public void goForward() {
211 mContentViewCore.goForward();
215 * Fling the ContentView from the current position.
216 * @param x Fling touch starting position
217 * @param y Fling touch starting position
218 * @param velocityX Initial velocity of the fling (X) measured in pixels per second.
219 * @param velocityY Initial velocity of the fling (Y) measured in pixels per second.
222 public void fling(long timeMs, int x, int y, int velocityX, int velocityY) {
223 mContentViewCore.flingForTest(timeMs, x, y, velocityX, velocityY);
227 * Injects the passed JavaScript code in the current page and evaluates it.
229 * @throws IllegalStateException If the ContentView has been destroyed.
231 public void evaluateJavaScript(String script) throws IllegalStateException {
232 mContentViewCore.evaluateJavaScript(script, null);
236 * To be called when the ContentView is shown.
238 public void onShow() {
239 mContentViewCore.onShow();
243 * To be called when the ContentView is hidden.
245 public void onHide() {
246 mContentViewCore.onHide();
250 * Hides the select action bar.
252 public void hideSelectActionBar() {
253 mContentViewCore.hideSelectActionBar();
256 // FrameLayout overrides.
258 // Needed by ContentViewCore.InternalAccessDelegate
260 public boolean drawChild(Canvas canvas, View child, long drawingTime) {
261 return super.drawChild(canvas, child, drawingTime);
264 // Needed by ContentViewCore.InternalAccessDelegate
266 public void onScrollChanged(int l, int t, int oldl, int oldt) {
267 super.onScrollChanged(l, t, oldl, oldt);
271 protected void onSizeChanged(int w, int h, int ow, int oh) {
273 super.onSizeChanged(w, h, ow, oh);
274 mContentViewCore.onSizeChanged(w, h, ow, oh);
279 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
280 super.onLayout(changed, left, top, right, bottom);
282 getLocationInWindow(mLocationInWindow);
283 mContentViewCore.onLocationInWindowChanged(mLocationInWindow[0], mLocationInWindow[1]);
288 public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
289 return mContentViewCore.onCreateInputConnection(outAttrs);
293 public boolean onCheckIsTextEditor() {
294 return mContentViewCore.onCheckIsTextEditor();
298 protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
300 super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
301 mContentViewCore.onFocusChanged(gainFocus);
306 public void onWindowFocusChanged(boolean hasWindowFocus) {
307 super.onWindowFocusChanged(hasWindowFocus);
308 mContentViewCore.onWindowFocusChanged(hasWindowFocus);
312 public boolean onKeyUp(int keyCode, KeyEvent event) {
313 return mContentViewCore.onKeyUp(keyCode, event);
317 public boolean dispatchKeyEventPreIme(KeyEvent event) {
318 return mContentViewCore.dispatchKeyEventPreIme(event);
322 public boolean dispatchKeyEvent(KeyEvent event) {
324 return mContentViewCore.dispatchKeyEvent(event);
326 return super.dispatchKeyEvent(event);
331 public boolean onTouchEvent(MotionEvent event) {
332 MotionEvent offset = createOffsetMotionEvent(event);
333 boolean consumed = mContentViewCore.onTouchEvent(offset);
339 * Mouse move events are sent on hover enter, hover move and hover exit.
340 * They are sent on hover exit because sometimes it acts as both a hover
341 * move and hover exit.
344 public boolean onHoverEvent(MotionEvent event) {
345 MotionEvent offset = createOffsetMotionEvent(event);
346 boolean consumed = mContentViewCore.onHoverEvent(offset);
348 if (!mContentViewCore.isTouchExplorationEnabled()) super.onHoverEvent(event);
353 public boolean onGenericMotionEvent(MotionEvent event) {
354 return mContentViewCore.onGenericMotionEvent(event);
358 public boolean performLongClick() {
363 * Sets the current amount to offset incoming touch events by. This is used to handle content
364 * moving and not lining up properly with the android input system.
365 * @param dx The X offset in pixels to shift touch events.
366 * @param dy The Y offset in pixels to shift touch events.
368 public void setCurrentMotionEventOffsets(float dx, float dy) {
369 mCurrentTouchOffsetX = dx;
370 mCurrentTouchOffsetY = dy;
373 private MotionEvent createOffsetMotionEvent(MotionEvent src) {
374 MotionEvent dst = MotionEvent.obtain(src);
375 dst.offsetLocation(mCurrentTouchOffsetX, mCurrentTouchOffsetY);
380 protected void onConfigurationChanged(Configuration newConfig) {
381 mContentViewCore.onConfigurationChanged(newConfig);
385 * Currently the ContentView scrolling happens in the native side. In
386 * the Java view system, it is always pinned at (0, 0). scrollBy() and scrollTo()
387 * are overridden, so that View's mScrollX and mScrollY will be unchanged at
388 * (0, 0). This is critical for drawing ContentView correctly.
391 public void scrollBy(int x, int y) {
392 mContentViewCore.scrollBy(x, y);
396 public void scrollTo(int x, int y) {
397 mContentViewCore.scrollTo(x, y);
401 protected int computeHorizontalScrollExtent() {
402 // TODO(dtrainor): Need to expose scroll events properly to public. Either make getScroll*
403 // work or expose computeHorizontalScrollOffset()/computeVerticalScrollOffset as public.
404 return mContentViewCore.computeHorizontalScrollExtent();
408 protected int computeHorizontalScrollOffset() {
409 return mContentViewCore.computeHorizontalScrollOffset();
413 protected int computeHorizontalScrollRange() {
414 return mContentViewCore.computeHorizontalScrollRange();
418 protected int computeVerticalScrollExtent() {
419 return mContentViewCore.computeVerticalScrollExtent();
423 protected int computeVerticalScrollOffset() {
424 return mContentViewCore.computeVerticalScrollOffset();
428 protected int computeVerticalScrollRange() {
429 return mContentViewCore.computeVerticalScrollRange();
432 // End FrameLayout overrides.
435 public boolean awakenScrollBars(int startDelay, boolean invalidate) {
436 return mContentViewCore.awakenScrollBars(startDelay, invalidate);
440 public boolean awakenScrollBars() {
441 return super.awakenScrollBars();
444 public int getSingleTapX() {
445 return mContentViewCore.getSingleTapX();
448 public int getSingleTapY() {
449 return mContentViewCore.getSingleTapY();
453 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
454 super.onInitializeAccessibilityNodeInfo(info);
455 mContentViewCore.onInitializeAccessibilityNodeInfo(info);
459 * Fills in scrolling values for AccessibilityEvents.
460 * @param event Event being fired.
463 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
464 super.onInitializeAccessibilityEvent(event);
465 mContentViewCore.onInitializeAccessibilityEvent(event);
469 protected void onAttachedToWindow() {
470 super.onAttachedToWindow();
471 mContentViewCore.onAttachedToWindow();
475 protected void onDetachedFromWindow() {
476 super.onDetachedFromWindow();
477 mContentViewCore.onDetachedFromWindow();
481 protected void onVisibilityChanged(View changedView, int visibility) {
482 super.onVisibilityChanged(changedView, visibility);
483 mContentViewCore.onVisibilityChanged(changedView, visibility);
487 * Return the current scale of the WebView
488 * @return The current scale.
490 public float getScale() {
491 return mContentViewCore.getScale();
495 * Enable or disable accessibility features.
497 public void setAccessibilityState(boolean state) {
498 mContentViewCore.setAccessibilityState(state);
502 * Inform WebKit that Fullscreen mode has been exited by the user.
504 public void exitFullscreen() {
505 mContentViewCore.exitFullscreen();
509 * Return content scroll y.
511 * @return The vertical scroll position in pixels.
513 public int getContentScrollY() {
514 return mContentViewCore.computeVerticalScrollOffset();
518 * Return content height.
520 * @return The height of the content in pixels.
522 public int getContentHeight() {
523 return mContentViewCore.computeVerticalScrollRange();
526 ///////////////////////////////////////////////////////////////////////////////////////////////
527 // Start Implementation of ContentViewCore.InternalAccessDelegate //
528 ///////////////////////////////////////////////////////////////////////////////////////////////
531 public boolean super_onKeyUp(int keyCode, KeyEvent event) {
532 return super.onKeyUp(keyCode, event);
536 public boolean super_dispatchKeyEventPreIme(KeyEvent event) {
537 return super.dispatchKeyEventPreIme(event);
541 public boolean super_dispatchKeyEvent(KeyEvent event) {
542 return super.dispatchKeyEvent(event);
546 public boolean super_onGenericMotionEvent(MotionEvent event) {
547 return super.onGenericMotionEvent(event);
551 public void super_onConfigurationChanged(Configuration newConfig) {
552 super.onConfigurationChanged(newConfig);
556 public boolean super_awakenScrollBars(int startDelay, boolean invalidate) {
557 return super.awakenScrollBars(startDelay, invalidate);
560 ///////////////////////////////////////////////////////////////////////////////////////////////
561 // End Implementation of ContentViewCore.InternalAccessDelegate //
562 ///////////////////////////////////////////////////////////////////////////////////////////////