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