blob: 755ecf5a2c464928a1ca6f585d19012f78c4828b [file] [log] [blame]
Romain Guyaa6c24c2011-04-28 18:40:04 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
19import android.content.Context;
20import android.graphics.Canvas;
21import android.graphics.Paint;
22import android.graphics.SurfaceTexture;
23import android.util.AttributeSet;
24import android.util.Log;
25
26/**
27 * <p>A TextureView can be used to display a content stream. Such a content
28 * stream can for instance be a video or an OpenGL scene. The content stream
29 * can come from the application's process as well as a remote process.</p>
30 *
31 * <p>TextureView can only be used in a hardware accelerated window. When
32 * rendered in software, TextureView will draw nothing.</p>
33 *
34 * <p>Unlike {@link SurfaceView}, TextureView does not create a separate
35 * window but behaves as a regular View. This key difference allows a
36 * TextureView to be moved, transformed, animated, etc. For instance, you
37 * can make a TextureView semi-translucent by calling
38 * <code>myView.setAlpha(0.5f)</code>.</p>
39 *
40 * <p>Using a TextureView is simple: all you need to do is get its
41 * {@link SurfaceTexture}. The {@link SurfaceTexture} can then be used to
42 * render content. The following example demonstrates how to render the
43 * camera preview into a TextureView:</p>
44 *
45 * <pre>
46 * public class LiveCameraActivity extends Activity implements TextureView.SurfaceTextureListener {
47 * private Camera mCamera;
48 * private TextureView mTextureView;
49 *
Romain Guyaa6c24c2011-04-28 18:40:04 -070050 * protected void onCreate(Bundle savedInstanceState) {
51 * super.onCreate(savedInstanceState);
52 *
53 * mTextureView = new TextureView(this);
54 * mTextureView.setSurfaceTextureListener(this);
55 *
56 * setContentView(mTextureView);
57 * }
58 *
Romain Guyaa6c24c2011-04-28 18:40:04 -070059 * protected void onDestroy() {
60 * super.onDestroy();
61 *
62 * mCamera.stopPreview();
63 * mCamera.release();
64 * }
65 *
Romain Guyaa6c24c2011-04-28 18:40:04 -070066 * public void onSurfaceTextureAvailable(SurfaceTexture surface) {
67 * mCamera = Camera.open();
68 *
69 * try {
70 * mCamera.setPreviewTexture(surface);
71 * mCamera.startPreview();
72 * } catch (IOException ioe) {
73 * // Something bad happened
74 * }
75 * }
Romain Guy8f0095c2011-05-02 17:24:22 -070076 *
77 * public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
78 * // Ignored, Camera does all the work for us
79 * }
Romain Guyaa6c24c2011-04-28 18:40:04 -070080 * }
81 * </pre>
82 *
83 * <p>A TextureView's SurfaceTexture can be obtained either by invoking
84 * {@link #getSurfaceTexture()} or by using a {@link SurfaceTextureListener}.
85 * It is important to know that a SurfaceTexture is available only after the
86 * TextureView is attached to a window (and {@link #onAttachedToWindow()} has
87 * been invoked.) It is therefore highly recommended you use a listener to
88 * be notified when the SurfaceTexture becomes available.</p>
89 *
90 * @see SurfaceView
91 * @see SurfaceTexture
92 */
93public class TextureView extends View {
94 private HardwareLayer mLayer;
95 private SurfaceTexture mSurface;
96 private SurfaceTextureListener mListener;
Romain Guyaa6c24c2011-04-28 18:40:04 -070097
98 private final Runnable mUpdateLayerAction = new Runnable() {
99 @Override
100 public void run() {
101 updateLayer();
102 }
103 };
Romain Guy8f0095c2011-05-02 17:24:22 -0700104 private SurfaceTexture.OnFrameAvailableListener mUpdateListener;
Romain Guyaa6c24c2011-04-28 18:40:04 -0700105
106 /**
107 * Creates a new TextureView.
108 *
109 * @param context The context to associate this view with.
110 */
111 public TextureView(Context context) {
112 super(context);
113 init();
114 }
115
116 /**
117 * Creates a new TextureView.
118 *
119 * @param context The context to associate this view with.
120 * @param attrs The attributes of the XML tag that is inflating the view.
121 */
122 @SuppressWarnings({"UnusedDeclaration"})
123 public TextureView(Context context, AttributeSet attrs) {
124 super(context, attrs);
125 init();
126 }
127
128 /**
129 * Creates a new TextureView.
130 *
131 * @param context The context to associate this view with.
132 * @param attrs The attributes of the XML tag that is inflating the view.
133 * @param defStyle The default style to apply to this view. If 0, no style
134 * will be applied (beyond what is included in the theme). This may
135 * either be an attribute resource, whose value will be retrieved
136 * from the current theme, or an explicit style resource.
137 */
138 @SuppressWarnings({"UnusedDeclaration"})
139 public TextureView(Context context, AttributeSet attrs, int defStyle) {
140 super(context, attrs, defStyle);
141 init();
142 }
143
144 private void init() {
145 mLayerPaint = new Paint();
146 }
147
148 @Override
149 protected void onAttachedToWindow() {
150 super.onAttachedToWindow();
151
152 if (!isHardwareAccelerated()) {
153 Log.w("TextureView", "A TextureView or a subclass can only be "
154 + "used with hardware acceleration enabled.");
155 }
156 }
157
158 /**
159 * The layer type of a TextureView is ignored since a TextureView is always
160 * considered to act as a hardware layer. The optional paint supplied to this
161 * method will however be taken into account when rendering the content of
162 * this TextureView.
163 *
164 * @param layerType The ype of layer to use with this view, must be one of
165 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
166 * {@link #LAYER_TYPE_HARDWARE}
167 * @param paint The paint used to compose the layer. This argument is optional
168 * and can be null. It is ignored when the layer type is
169 * {@link #LAYER_TYPE_NONE}
170 */
171 @Override
172 public void setLayerType(int layerType, Paint paint) {
173 if (paint != mLayerPaint) {
174 mLayerPaint = paint;
175 invalidate();
176 }
177 }
178
179 /**
180 * Always returns {@link #LAYER_TYPE_HARDWARE}.
181 */
182 @Override
183 public int getLayerType() {
184 return LAYER_TYPE_HARDWARE;
185 }
186
187 /**
188 * Calling this method has no effect.
189 */
190 @Override
191 public void buildLayer() {
192 }
193
194 /**
195 * Subclasses of TextureView cannot do their own rendering
196 * with the {@link Canvas} object.
197 *
198 * @param canvas The Canvas to which the View is rendered.
199 */
200 @Override
201 public final void draw(Canvas canvas) {
202 super.draw(canvas);
203 }
204
205 /**
206 * Subclasses of TextureView cannot do their own rendering
207 * with the {@link Canvas} object.
208 *
209 * @param canvas The Canvas to which the View is rendered.
210 */
211 @Override
212 protected final void onDraw(Canvas canvas) {
213 }
214
215 @Override
Romain Guy8f0095c2011-05-02 17:24:22 -0700216 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
217 super.onSizeChanged(w, h, oldw, oldh);
218 if (mSurface != null) {
219 nSetDefaultBufferSize(mSurface.mSurfaceTexture, getWidth(), getHeight());
220 }
221 }
222
223 @Override
Romain Guyaa6c24c2011-04-28 18:40:04 -0700224 HardwareLayer getHardwareLayer() {
225 if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
226 return null;
227 }
228
229 if (mLayer == null) {
230 mLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer();
231 mSurface = mAttachInfo.mHardwareRenderer.createSuraceTexture(mLayer);
Romain Guy8f0095c2011-05-02 17:24:22 -0700232 nSetDefaultBufferSize(mSurface.mSurfaceTexture, getWidth(), getHeight());
Romain Guyaa6c24c2011-04-28 18:40:04 -0700233
Romain Guy8f0095c2011-05-02 17:24:22 -0700234 mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() {
Romain Guyaa6c24c2011-04-28 18:40:04 -0700235 @Override
236 public void onFrameAvailable(SurfaceTexture surfaceTexture) {
237 // Per SurfaceTexture's documentation, the callback may be invoked
238 // from an arbitrary thread
239 post(mUpdateLayerAction);
240 }
Romain Guy8f0095c2011-05-02 17:24:22 -0700241 };
242 mSurface.setOnFrameAvailableListener(mUpdateListener);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700243
244 if (mListener != null) {
245 mListener.onSurfaceTextureAvailable(mSurface);
246 }
247 }
248
249 return mLayer;
250 }
251
Romain Guy8f0095c2011-05-02 17:24:22 -0700252 @Override
253 protected void onVisibilityChanged(View changedView, int visibility) {
254 super.onVisibilityChanged(changedView, visibility);
255
256 if (mSurface != null) {
257 // When the view becomes invisible, stop updating it, it's a waste of CPU
258 // To cancel updates, the easiest thing to do is simply to remove the
259 // updates listener
260 if (visibility == VISIBLE) {
261 mSurface.setOnFrameAvailableListener(mUpdateListener);
262 updateLayer();
263 } else {
264 mSurface.setOnFrameAvailableListener(null);
265 }
266 }
267 }
268
Romain Guyaa6c24c2011-04-28 18:40:04 -0700269 private void updateLayer() {
270 if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
271 return;
272 }
273
Romain Guy8f0095c2011-05-02 17:24:22 -0700274 mAttachInfo.mHardwareRenderer.updateTextureLayer(mLayer, getWidth(), getHeight(), mSurface);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700275
276 invalidate();
277 }
278
279 /**
280 * Returns the {@link SurfaceTexture} used by this view. This method
281 * may return null if the view is not attached to a window.
282 */
283 public SurfaceTexture getSurfaceTexture() {
284 return mSurface;
285 }
286
287 /**
288 * Returns the {@link SurfaceTextureListener} currently associated with this
289 * texture view.
290 *
291 * @see #setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener)
292 * @see SurfaceTextureListener
293 */
294 public SurfaceTextureListener getSurfaceTextureListener() {
295 return mListener;
296 }
297
298 /**
299 * Sets the {@link SurfaceTextureListener} used to listen to surface
300 * texture events.
301 *
302 * @see #getSurfaceTextureListener()
303 * @see SurfaceTextureListener
304 */
305 public void setSurfaceTextureListener(SurfaceTextureListener listener) {
306 mListener = listener;
307 }
308
309 /**
310 * This listener can be used to be notified when the surface texture
311 * associated with this texture view is available.
312 */
313 public static interface SurfaceTextureListener {
314 /**
315 * Invoked when a {@link TextureView}'s SurfaceTexture is ready for use.
316 *
317 * @param surface The surface returned by
318 * {@link android.view.TextureView#getSurfaceTexture()}
319 */
320 public void onSurfaceTextureAvailable(SurfaceTexture surface);
Romain Guy8f0095c2011-05-02 17:24:22 -0700321
322 /**
323 * Invoked when the {@link SurfaceTexture}'s buffers size changed.
324 *
325 * @param surface The surface returned by
326 * {@link android.view.TextureView#getSurfaceTexture()}
327 * @param width The new width of the surface
328 * @param height The new height of the surface
329 */
330 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700331 }
Romain Guy8f0095c2011-05-02 17:24:22 -0700332
333 private static native void nSetDefaultBufferSize(int surfaceTexture, int width, int height);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700334}