ContentView.java revision 116680a4aac90f2aa7413d9095a592090648e557
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.os.Bundle;
13import android.os.Handler;
14import android.os.Message;
15import android.util.Log;
16import android.view.KeyEvent;
17import android.view.MotionEvent;
18import android.view.View;
19import android.view.accessibility.AccessibilityEvent;
20import android.view.accessibility.AccessibilityNodeInfo;
21import android.view.inputmethod.EditorInfo;
22import android.view.inputmethod.InputConnection;
23import android.widget.FrameLayout;
24
25import 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 */
31public 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