ContentViewRenderView.java revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright (c) 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.os.Build;
9import android.view.Surface;
10import android.view.SurfaceView;
11import android.view.SurfaceHolder;
12import android.widget.FrameLayout;
13
14import org.chromium.base.JNINamespace;
15
16/***
17 * This view is used by a ContentView to render its content.
18 * Call {@link #setCurrentContentView(ContentView)} with the contentView that should be displayed.
19 * Note that only one ContentView can be shown at a time.
20 */
21@JNINamespace("content")
22public class ContentViewRenderView extends FrameLayout {
23
24    // The native side of this object.
25    private int mNativeContentViewRenderView = 0;
26
27    private SurfaceView mSurfaceView;
28
29    private ContentView mCurrentContentView;
30
31    private final VSyncMonitor mVSyncMonitor;
32
33    // The VSyncMonitor gives the timebase for the actual vsync, but we don't want render until
34    // we have had a chance for input events to propagate to the compositor thread. This takes
35    // 3 ms typically, so we adjust the vsync timestamps forward by a bit to give input events a
36    // chance to arrive.
37    private static final long INPUT_EVENT_LAG_FROM_VSYNC_MICROSECONDS = 3200;
38
39    /**
40     * Constructs a new ContentViewRenderView that should be can to a view hierarchy.
41     * Native code should add/remove the layers to be rendered through the ContentViewLayerRenderer.
42     * @param context The context used to create this.
43     */
44    public ContentViewRenderView(Context context) {
45        super(context);
46
47        mNativeContentViewRenderView = nativeInit();
48        assert mNativeContentViewRenderView != 0;
49
50        mSurfaceView = new SurfaceView(getContext());
51        mSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
52            @Override
53            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
54                nativeSurfaceSetSize(mNativeContentViewRenderView, width, height);
55                if (mCurrentContentView != null) {
56                    mCurrentContentView.getContentViewCore().onPhysicalBackingSizeChanged(
57                            width, height);
58                }
59            }
60
61            @Override
62            public void surfaceCreated(SurfaceHolder holder) {
63                nativeSurfaceCreated(mNativeContentViewRenderView, holder.getSurface());
64                onReadyToRender();
65            }
66
67            @Override
68            public void surfaceDestroyed(SurfaceHolder holder) {
69                nativeSurfaceDestroyed(mNativeContentViewRenderView);
70            }
71        });
72
73        mVSyncMonitor = new VSyncMonitor(getContext(), new VSyncMonitor.Listener() {
74            @Override
75            public void onVSync(VSyncMonitor monitor, long vsyncTimeMicros) {
76                if (mCurrentContentView == null) return;
77                // Compensate for input event lag. Input events are delivered immediately on
78                // pre-JB releases, so this adjustment is only done for later versions.
79                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
80                    vsyncTimeMicros += INPUT_EVENT_LAG_FROM_VSYNC_MICROSECONDS;
81                }
82                mCurrentContentView.getContentViewCore().updateVSync(vsyncTimeMicros,
83                        mVSyncMonitor.getVSyncPeriodInMicroseconds());
84            }
85        });
86
87        addView(mSurfaceView,
88                new FrameLayout.LayoutParams(
89                        FrameLayout.LayoutParams.MATCH_PARENT,
90                        FrameLayout.LayoutParams.MATCH_PARENT));
91    }
92
93    /**
94     * Should be called when the ContentViewRenderView is not needed anymore so its associated
95     * native resource can be freed.
96     */
97    public void destroy() {
98        nativeDestroy(mNativeContentViewRenderView);
99    }
100
101    /**
102     * Makes the passed ContentView the one displayed by this ContentViewRenderView.
103     */
104    public void setCurrentContentView(ContentView contentView) {
105        nativeSetCurrentContentView(mNativeContentViewRenderView,
106                contentView.getContentViewCore().getNativeContentViewCore());
107
108        mCurrentContentView = contentView;
109        mCurrentContentView.getContentViewCore().onPhysicalBackingSizeChanged(
110                getWidth(), getHeight());
111        mVSyncMonitor.requestUpdate();
112    }
113
114    /**
115     * This method should be subclassed to provide actions to be performed once the view is ready to
116     * render.
117     */
118    protected void onReadyToRender() {
119    }
120
121    /**
122     * @return whether the surface view is initialized and ready to render.
123     */
124    public boolean isInitialized() {
125        return mSurfaceView.getHolder().getSurface() != null;
126    }
127
128    private static native int nativeInit();
129    private native void nativeDestroy(int nativeContentViewRenderView);
130    private native void nativeSetCurrentContentView(int nativeContentViewRenderView,
131            int nativeContentView);
132    private native void nativeSurfaceCreated(int nativeContentViewRenderView, Surface surface);
133    private native void nativeSurfaceDestroyed(int nativeContentViewRenderView);
134    private native void nativeSurfaceSetSize(int nativeContentViewRenderView,
135            int width, int height);
136}
137