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.Bitmap;
10 import android.graphics.Canvas;
11 import android.graphics.Rect;
12 import android.os.Build;
13 import android.util.AttributeSet;
14 import android.view.KeyEvent;
15 import android.view.MotionEvent;
16 import android.view.View;
17 import android.view.accessibility.AccessibilityEvent;
18 import android.view.accessibility.AccessibilityNodeInfo;
19 import android.view.inputmethod.EditorInfo;
20 import android.view.inputmethod.InputConnection;
21 import android.widget.FrameLayout;
23 import com.google.common.annotations.VisibleForTesting;
25 import org.chromium.base.TraceEvent;
26 import org.chromium.ui.base.WindowAndroid;
29 * The containing view for {@link ContentViewCore} that exists in the Android UI hierarchy and
30 * exposes the various {@link View} functionality to it.
32 * TODO(joth): Remove any methods overrides from this class that were added for WebView
35 public class ContentView extends FrameLayout
36 implements ContentViewCore.InternalAccessDelegate, PageInfo {
38 private final ContentViewCore mContentViewCore;
40 private float mCurrentTouchOffsetX;
41 private float mCurrentTouchOffsetY;
42 private final int[] mLocationInWindow = new int[2];
45 * Creates an instance of a ContentView.
46 * @param context The Context the view is running in, through which it can
47 * access the current theme, resources, etc.
48 * @param nativeWebContents A pointer to the native web contents.
49 * @param windowAndroid An instance of the WindowAndroid.
50 * @return A ContentView instance.
52 public static ContentView newInstance(Context context, long nativeWebContents,
53 WindowAndroid windowAndroid) {
54 return newInstance(context, nativeWebContents, windowAndroid, null,
55 android.R.attr.webViewStyle);
59 * Creates an instance of a ContentView.
60 * @param context The Context the view is running in, through which it can
61 * access the current theme, resources, etc.
62 * @param nativeWebContents A pointer to the native web contents.
63 * @param windowAndroid An instance of the WindowAndroid.
64 * @param attrs The attributes of the XML tag that is inflating the view.
65 * @return A ContentView instance.
67 public static ContentView newInstance(Context context, long nativeWebContents,
68 WindowAndroid windowAndroid, AttributeSet attrs) {
69 // TODO(klobag): use the WebViewStyle as the default style for now. It enables scrollbar.
70 // When ContentView is moved to framework, we can define its own style in the res.
71 return newInstance(context, nativeWebContents, windowAndroid, attrs,
72 android.R.attr.webViewStyle);
76 * Creates an instance of a ContentView.
77 * @param context The Context the view is running in, through which it can
78 * access the current theme, resources, etc.
79 * @param nativeWebContents A pointer to the native web contents.
80 * @param windowAndroid An instance of the WindowAndroid.
81 * @param attrs The attributes of the XML tag that is inflating the view.
82 * @param defStyle The default style to apply to this view.
83 * @return A ContentView instance.
85 public static ContentView newInstance(Context context, long nativeWebContents,
86 WindowAndroid windowAndroid, AttributeSet attrs, int defStyle) {
87 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
88 return new ContentView(context, nativeWebContents, windowAndroid, attrs, defStyle);
90 return new JellyBeanContentView(context, nativeWebContents, windowAndroid, attrs,
95 protected ContentView(Context context, long nativeWebContents, WindowAndroid windowAndroid,
96 AttributeSet attrs, int defStyle) {
97 super(context, attrs, defStyle);
99 if (getScrollBarStyle() == View.SCROLLBARS_INSIDE_OVERLAY) {
100 setHorizontalScrollBarEnabled(false);
101 setVerticalScrollBarEnabled(false);
105 setFocusableInTouchMode(true);
107 mContentViewCore = new ContentViewCore(context);
108 mContentViewCore.initialize(this, this, nativeWebContents, windowAndroid);
112 * @return The URL of the page.
114 public String getUrl() {
115 return mContentViewCore.getUrl();
118 // PageInfo implementation.
121 public String getTitle() {
122 return mContentViewCore.getTitle();
126 public boolean isReadyForSnapshot() {
127 return mContentViewCore.isReady();
131 public Bitmap getBitmap() {
132 return getBitmap(getWidth(), getHeight());
136 public Bitmap getBitmap(int width, int height) {
137 return mContentViewCore.getBitmap(width, height);
141 public int getBackgroundColor() {
142 return mContentViewCore.getBackgroundColor();
146 public View getView() {
151 * @return The core component of the ContentView that handles JNI communication. Should only be
152 * used for passing to native.
154 public ContentViewCore getContentViewCore() {
155 return mContentViewCore;
159 * @return The cache of scales and positions used to convert coordinates from/to CSS.
161 public RenderCoordinates getRenderCoordinates() {
162 return mContentViewCore.getRenderCoordinates();
166 * Destroy the internal state of the WebView. This method may only be called
167 * after the WebView has been removed from the view system. No other methods
168 * may be called on this WebView after this method has been called.
170 public void destroy() {
171 mContentViewCore.destroy();
175 * Returns true initially, false after destroy() has been called.
176 * It is illegal to call any other public method after destroy().
178 public boolean isAlive() {
179 return mContentViewCore.isAlive();
182 public void setContentViewClient(ContentViewClient client) {
183 mContentViewCore.setContentViewClient(client);
187 public ContentViewClient getContentViewClient() {
188 return mContentViewCore.getContentViewClient();
192 * Load url without fixing up the url string. Consumers of ContentView are responsible for
193 * ensuring the URL passed in is properly formatted (i.e. the scheme has been added if left
194 * off during user input).
196 * @param params Parameters for this load.
198 public void loadUrl(LoadUrlParams params) {
199 mContentViewCore.loadUrl(params);
203 * @return Whether the current WebContents has a previous navigation entry.
205 public boolean canGoBack() {
206 return mContentViewCore.canGoBack();
210 * @return Whether the current WebContents has a navigation entry after the current one.
212 public boolean canGoForward() {
213 return mContentViewCore.canGoForward();
217 * Goes to the navigation entry before the current one.
219 public void goBack() {
220 mContentViewCore.goBack();
224 * Goes to the navigation entry following the current one.
226 public void goForward() {
227 mContentViewCore.goForward();
231 * Fling the ContentView from the current position.
232 * @param x Fling touch starting position
233 * @param y Fling touch starting position
234 * @param velocityX Initial velocity of the fling (X) measured in pixels per second.
235 * @param velocityY Initial velocity of the fling (Y) measured in pixels per second.
238 public void fling(long timeMs, int x, int y, int velocityX, int velocityY) {
239 mContentViewCore.flingForTest(timeMs, x, y, velocityX, velocityY);
243 * Injects the passed JavaScript code in the current page and evaluates it.
245 * @throws IllegalStateException If the ContentView has been destroyed.
247 public void evaluateJavaScript(String script) throws IllegalStateException {
248 mContentViewCore.evaluateJavaScript(script, null);
252 * To be called when the ContentView is shown.
254 public void onShow() {
255 mContentViewCore.onShow();
259 * To be called when the ContentView is hidden.
261 public void onHide() {
262 mContentViewCore.onHide();
266 * Hides the select action bar.
268 public void hideSelectActionBar() {
269 mContentViewCore.hideSelectActionBar();
272 // FrameLayout overrides.
274 // Needed by ContentViewCore.InternalAccessDelegate
276 public boolean drawChild(Canvas canvas, View child, long drawingTime) {
277 return super.drawChild(canvas, child, drawingTime);
280 // Needed by ContentViewCore.InternalAccessDelegate
282 public void onScrollChanged(int l, int t, int oldl, int oldt) {
283 super.onScrollChanged(l, t, oldl, oldt);
287 protected void onSizeChanged(int w, int h, int ow, int oh) {
289 super.onSizeChanged(w, h, ow, oh);
290 mContentViewCore.onSizeChanged(w, h, ow, oh);
295 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
296 super.onLayout(changed, left, top, right, bottom);
298 getLocationInWindow(mLocationInWindow);
299 mContentViewCore.onLocationInWindowChanged(mLocationInWindow[0], mLocationInWindow[1]);
304 public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
305 return mContentViewCore.onCreateInputConnection(outAttrs);
309 public boolean onCheckIsTextEditor() {
310 return mContentViewCore.onCheckIsTextEditor();
314 protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
316 super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
317 mContentViewCore.onFocusChanged(gainFocus);
322 public void onWindowFocusChanged(boolean hasWindowFocus) {
323 super.onWindowFocusChanged(hasWindowFocus);
324 mContentViewCore.onWindowFocusChanged(hasWindowFocus);
328 public boolean onKeyUp(int keyCode, KeyEvent event) {
329 return mContentViewCore.onKeyUp(keyCode, event);
333 public boolean dispatchKeyEventPreIme(KeyEvent event) {
334 return mContentViewCore.dispatchKeyEventPreIme(event);
338 public boolean dispatchKeyEvent(KeyEvent event) {
340 return mContentViewCore.dispatchKeyEvent(event);
342 return super.dispatchKeyEvent(event);
347 public boolean onTouchEvent(MotionEvent event) {
348 MotionEvent offset = createOffsetMotionEvent(event);
349 boolean consumed = mContentViewCore.onTouchEvent(offset);
355 * Mouse move events are sent on hover enter, hover move and hover exit.
356 * They are sent on hover exit because sometimes it acts as both a hover
357 * move and hover exit.
360 public boolean onHoverEvent(MotionEvent event) {
361 MotionEvent offset = createOffsetMotionEvent(event);
362 boolean consumed = mContentViewCore.onHoverEvent(offset);
364 super.onHoverEvent(event);
369 public boolean onGenericMotionEvent(MotionEvent event) {
370 return mContentViewCore.onGenericMotionEvent(event);
374 public boolean performLongClick() {
379 * Sets the current amount to offset incoming touch events by. This is used to handle content
380 * moving and not lining up properly with the android input system.
381 * @param dx The X offset in pixels to shift touch events.
382 * @param dy The Y offset in pixels to shift touch events.
384 public void setCurrentMotionEventOffsets(float dx, float dy) {
385 mCurrentTouchOffsetX = dx;
386 mCurrentTouchOffsetY = dy;
389 private MotionEvent createOffsetMotionEvent(MotionEvent src) {
390 MotionEvent dst = MotionEvent.obtain(src);
391 dst.offsetLocation(mCurrentTouchOffsetX, mCurrentTouchOffsetY);
396 protected void onConfigurationChanged(Configuration newConfig) {
397 mContentViewCore.onConfigurationChanged(newConfig);
401 * Currently the ContentView scrolling happens in the native side. In
402 * the Java view system, it is always pinned at (0, 0). scrollBy() and scrollTo()
403 * are overridden, so that View's mScrollX and mScrollY will be unchanged at
404 * (0, 0). This is critical for drawing ContentView correctly.
407 public void scrollBy(int x, int y) {
408 mContentViewCore.scrollBy(x, y);
412 public void scrollTo(int x, int y) {
413 mContentViewCore.scrollTo(x, y);
417 protected int computeHorizontalScrollExtent() {
418 // TODO(dtrainor): Need to expose scroll events properly to public. Either make getScroll*
419 // work or expose computeHorizontalScrollOffset()/computeVerticalScrollOffset as public.
420 return mContentViewCore.computeHorizontalScrollExtent();
424 protected int computeHorizontalScrollOffset() {
425 return mContentViewCore.computeHorizontalScrollOffset();
429 protected int computeHorizontalScrollRange() {
430 return mContentViewCore.computeHorizontalScrollRange();
434 protected int computeVerticalScrollExtent() {
435 return mContentViewCore.computeVerticalScrollExtent();
439 protected int computeVerticalScrollOffset() {
440 return mContentViewCore.computeVerticalScrollOffset();
444 protected int computeVerticalScrollRange() {
445 return mContentViewCore.computeVerticalScrollRange();
448 // End FrameLayout overrides.
451 public boolean awakenScrollBars(int startDelay, boolean invalidate) {
452 return mContentViewCore.awakenScrollBars(startDelay, invalidate);
456 public boolean awakenScrollBars() {
457 return super.awakenScrollBars();
460 public int getSingleTapX() {
461 return mContentViewCore.getSingleTapX();
464 public int getSingleTapY() {
465 return mContentViewCore.getSingleTapY();
469 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
470 super.onInitializeAccessibilityNodeInfo(info);
471 mContentViewCore.onInitializeAccessibilityNodeInfo(info);
475 * Fills in scrolling values for AccessibilityEvents.
476 * @param event Event being fired.
479 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
480 super.onInitializeAccessibilityEvent(event);
481 mContentViewCore.onInitializeAccessibilityEvent(event);
485 protected void onAttachedToWindow() {
486 super.onAttachedToWindow();
487 mContentViewCore.onAttachedToWindow();
491 protected void onDetachedFromWindow() {
492 super.onDetachedFromWindow();
493 mContentViewCore.onDetachedFromWindow();
497 protected void onVisibilityChanged(View changedView, int visibility) {
498 super.onVisibilityChanged(changedView, visibility);
499 mContentViewCore.onVisibilityChanged(changedView, visibility);
503 * Return the current scale of the WebView
504 * @return The current scale.
506 public float getScale() {
507 return mContentViewCore.getScale();
511 * Enable or disable accessibility features.
513 public void setAccessibilityState(boolean state) {
514 mContentViewCore.setAccessibilityState(state);
518 * Inform WebKit that Fullscreen mode has been exited by the user.
520 public void exitFullscreen() {
521 mContentViewCore.exitFullscreen();
525 * Return content scroll y.
527 * @return The vertical scroll position in pixels.
529 public int getContentScrollY() {
530 return mContentViewCore.computeVerticalScrollOffset();
534 * Return content height.
536 * @return The height of the content in pixels.
538 public int getContentHeight() {
539 return mContentViewCore.computeVerticalScrollRange();
542 ///////////////////////////////////////////////////////////////////////////////////////////////
543 // Start Implementation of ContentViewCore.InternalAccessDelegate //
544 ///////////////////////////////////////////////////////////////////////////////////////////////
547 public boolean super_onKeyUp(int keyCode, KeyEvent event) {
548 return super.onKeyUp(keyCode, event);
552 public boolean super_dispatchKeyEventPreIme(KeyEvent event) {
553 return super.dispatchKeyEventPreIme(event);
557 public boolean super_dispatchKeyEvent(KeyEvent event) {
558 return super.dispatchKeyEvent(event);
562 public boolean super_onGenericMotionEvent(MotionEvent event) {
563 return super.onGenericMotionEvent(event);
567 public void super_onConfigurationChanged(Configuration newConfig) {
568 super.onConfigurationChanged(newConfig);
572 public boolean super_awakenScrollBars(int startDelay, boolean invalidate) {
573 return super.awakenScrollBars(startDelay, invalidate);
576 ///////////////////////////////////////////////////////////////////////////////////////////////
577 // End Implementation of ContentViewCore.InternalAccessDelegate //
578 ///////////////////////////////////////////////////////////////////////////////////////////////