blob: 83999a1c3a7972439f8bfe46ccc39cd517285ab3 [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;
Romain Guy77a81162011-06-14 16:45:55 -070020import android.graphics.Bitmap;
Romain Guyaa6c24c2011-04-28 18:40:04 -070021import android.graphics.Canvas;
Romain Guy302a9df2011-08-16 13:55:02 -070022import android.graphics.Matrix;
Romain Guyaa6c24c2011-04-28 18:40:04 -070023import android.graphics.Paint;
Romain Guy6be3d552011-07-14 18:08:37 -070024import android.graphics.Rect;
Romain Guyaa6c24c2011-04-28 18:40:04 -070025import android.graphics.SurfaceTexture;
26import android.util.AttributeSet;
27import android.util.Log;
28
29/**
30 * <p>A TextureView can be used to display a content stream. Such a content
31 * stream can for instance be a video or an OpenGL scene. The content stream
32 * can come from the application's process as well as a remote process.</p>
33 *
34 * <p>TextureView can only be used in a hardware accelerated window. When
35 * rendered in software, TextureView will draw nothing.</p>
36 *
37 * <p>Unlike {@link SurfaceView}, TextureView does not create a separate
38 * window but behaves as a regular View. This key difference allows a
39 * TextureView to be moved, transformed, animated, etc. For instance, you
40 * can make a TextureView semi-translucent by calling
41 * <code>myView.setAlpha(0.5f)</code>.</p>
42 *
43 * <p>Using a TextureView is simple: all you need to do is get its
44 * {@link SurfaceTexture}. The {@link SurfaceTexture} can then be used to
45 * render content. The following example demonstrates how to render the
46 * camera preview into a TextureView:</p>
47 *
48 * <pre>
49 * public class LiveCameraActivity extends Activity implements TextureView.SurfaceTextureListener {
50 * private Camera mCamera;
51 * private TextureView mTextureView;
52 *
Romain Guyaa6c24c2011-04-28 18:40:04 -070053 * protected void onCreate(Bundle savedInstanceState) {
54 * super.onCreate(savedInstanceState);
55 *
56 * mTextureView = new TextureView(this);
57 * mTextureView.setSurfaceTextureListener(this);
58 *
59 * setContentView(mTextureView);
60 * }
61 *
Romain Guy451ce442011-06-10 15:40:36 -070062 * public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Romain Guyaa6c24c2011-04-28 18:40:04 -070063 * mCamera = Camera.open();
64 *
65 * try {
66 * mCamera.setPreviewTexture(surface);
67 * mCamera.startPreview();
68 * } catch (IOException ioe) {
69 * // Something bad happened
70 * }
71 * }
Grace Klobacf559372011-06-22 23:05:40 -070072 *
Romain Guy8f0095c2011-05-02 17:24:22 -070073 * public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
74 * // Ignored, Camera does all the work for us
75 * }
Grace Klobacf559372011-06-22 23:05:40 -070076 *
Grace Kloba402f0552011-08-09 18:47:17 -070077 * public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
Romain Guy451ce442011-06-10 15:40:36 -070078 * mCamera.stopPreview();
79 * mCamera.release();
Grace Kloba402f0552011-08-09 18:47:17 -070080 * return true;
Romain Guy451ce442011-06-10 15:40:36 -070081 * }
Grace Klobacf559372011-06-22 23:05:40 -070082 *
83 * public void onSurfaceTextureUpdated(SurfaceTexture surface) {
Romain Guy58f4edb2011-06-24 14:51:38 -070084 * // Invoked every time there's a new Camera preview frame
Grace Klobacf559372011-06-22 23:05:40 -070085 * }
Romain Guyaa6c24c2011-04-28 18:40:04 -070086 * }
87 * </pre>
88 *
89 * <p>A TextureView's SurfaceTexture can be obtained either by invoking
90 * {@link #getSurfaceTexture()} or by using a {@link SurfaceTextureListener}.
91 * It is important to know that a SurfaceTexture is available only after the
92 * TextureView is attached to a window (and {@link #onAttachedToWindow()} has
93 * been invoked.) It is therefore highly recommended you use a listener to
94 * be notified when the SurfaceTexture becomes available.</p>
95 *
Romain Guy462785f2011-09-27 17:42:10 -070096 * <p>It is important to note that only one producer can use the TextureView.
97 * For instance, if you use a TextureView to display the camera preview, you
98 * cannot use {@link #lockCanvas()} to draw onto the TextureView at the same
99 * time.</p>
100 *
Romain Guyaa6c24c2011-04-28 18:40:04 -0700101 * @see SurfaceView
102 * @see SurfaceTexture
103 */
104public class TextureView extends View {
Romain Guy77a81162011-06-14 16:45:55 -0700105 private static final String LOG_TAG = "TextureView";
106
Romain Guyaa6c24c2011-04-28 18:40:04 -0700107 private HardwareLayer mLayer;
108 private SurfaceTexture mSurface;
109 private SurfaceTextureListener mListener;
Romain Guyaa6c24c2011-04-28 18:40:04 -0700110
Romain Guya9489272011-06-22 20:58:11 -0700111 private boolean mOpaque = true;
Romain Guyc989d862011-06-22 14:53:39 -0700112
Romain Guy302a9df2011-08-16 13:55:02 -0700113 private final Matrix mMatrix = new Matrix();
114 private boolean mMatrixChanged;
115
Romain Guy58f4edb2011-06-24 14:51:38 -0700116 private final Object[] mLock = new Object[0];
117 private boolean mUpdateLayer;
118
Romain Guy8f0095c2011-05-02 17:24:22 -0700119 private SurfaceTexture.OnFrameAvailableListener mUpdateListener;
Romain Guyaa6c24c2011-04-28 18:40:04 -0700120
Romain Guy6be3d552011-07-14 18:08:37 -0700121 private Canvas mCanvas;
122 private int mSaveCount;
123
124 private final Object[] mNativeWindowLock = new Object[0];
125 // Used from native code, do not write!
126 @SuppressWarnings({"UnusedDeclaration"})
127 private int mNativeWindow;
128
Romain Guyaa6c24c2011-04-28 18:40:04 -0700129 /**
130 * Creates a new TextureView.
131 *
132 * @param context The context to associate this view with.
133 */
134 public TextureView(Context context) {
135 super(context);
136 init();
137 }
138
139 /**
140 * Creates a new TextureView.
141 *
142 * @param context The context to associate this view with.
143 * @param attrs The attributes of the XML tag that is inflating the view.
144 */
145 @SuppressWarnings({"UnusedDeclaration"})
146 public TextureView(Context context, AttributeSet attrs) {
147 super(context, attrs);
148 init();
149 }
150
151 /**
152 * Creates a new TextureView.
153 *
154 * @param context The context to associate this view with.
155 * @param attrs The attributes of the XML tag that is inflating the view.
156 * @param defStyle The default style to apply to this view. If 0, no style
157 * will be applied (beyond what is included in the theme). This may
158 * either be an attribute resource, whose value will be retrieved
159 * from the current theme, or an explicit style resource.
160 */
161 @SuppressWarnings({"UnusedDeclaration"})
162 public TextureView(Context context, AttributeSet attrs, int defStyle) {
163 super(context, attrs, defStyle);
164 init();
165 }
166
167 private void init() {
168 mLayerPaint = new Paint();
169 }
170
Romain Guya9489272011-06-22 20:58:11 -0700171 /**
172 * {@inheritDoc}
173 */
174 @Override
175 public boolean isOpaque() {
176 return mOpaque;
177 }
178
179 /**
180 * Indicates whether the content of this TextureView is opaque. The
181 * content is assumed to be opaque by default.
182 *
183 * @param opaque True if the content of this TextureView is opaque,
184 * false otherwise
185 */
186 public void setOpaque(boolean opaque) {
187 if (opaque != mOpaque) {
188 mOpaque = opaque;
Romain Guy58f4edb2011-06-24 14:51:38 -0700189 updateLayer();
Romain Guya9489272011-06-22 20:58:11 -0700190 }
191 }
192
Romain Guyaa6c24c2011-04-28 18:40:04 -0700193 @Override
194 protected void onAttachedToWindow() {
195 super.onAttachedToWindow();
196
197 if (!isHardwareAccelerated()) {
Romain Guy77a81162011-06-14 16:45:55 -0700198 Log.w(LOG_TAG, "A TextureView or a subclass can only be "
Romain Guyaa6c24c2011-04-28 18:40:04 -0700199 + "used with hardware acceleration enabled.");
200 }
201 }
202
Romain Guy451ce442011-06-10 15:40:36 -0700203 @Override
204 protected void onDetachedFromWindow() {
205 super.onDetachedFromWindow();
Romain Guy31f2c2e2011-11-21 10:55:41 -0800206 destroySurface();
207 }
Romain Guy451ce442011-06-10 15:40:36 -0700208
Romain Guy31f2c2e2011-11-21 10:55:41 -0800209 private void destroySurface() {
Romain Guy80429c42011-06-24 17:20:32 -0700210 if (mLayer != null) {
Grace Kloba402f0552011-08-09 18:47:17 -0700211 boolean shouldRelease = true;
Romain Guy451ce442011-06-10 15:40:36 -0700212 if (mListener != null) {
Grace Kloba402f0552011-08-09 18:47:17 -0700213 shouldRelease = mListener.onSurfaceTextureDestroyed(mSurface);
Romain Guy451ce442011-06-10 15:40:36 -0700214 }
215
Romain Guy6be3d552011-07-14 18:08:37 -0700216 synchronized (mNativeWindowLock) {
217 nDestroyNativeWindow();
218 }
219
220 mLayer.destroy();
Grace Kloba402f0552011-08-09 18:47:17 -0700221 if (shouldRelease) mSurface.release();
Romain Guy451ce442011-06-10 15:40:36 -0700222 mSurface = null;
223 mLayer = null;
224 }
225 }
226
Romain Guyaa6c24c2011-04-28 18:40:04 -0700227 /**
228 * The layer type of a TextureView is ignored since a TextureView is always
229 * considered to act as a hardware layer. The optional paint supplied to this
230 * method will however be taken into account when rendering the content of
231 * this TextureView.
232 *
233 * @param layerType The ype of layer to use with this view, must be one of
234 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
235 * {@link #LAYER_TYPE_HARDWARE}
236 * @param paint The paint used to compose the layer. This argument is optional
237 * and can be null. It is ignored when the layer type is
238 * {@link #LAYER_TYPE_NONE}
239 */
240 @Override
241 public void setLayerType(int layerType, Paint paint) {
242 if (paint != mLayerPaint) {
243 mLayerPaint = paint;
244 invalidate();
245 }
246 }
247
248 /**
249 * Always returns {@link #LAYER_TYPE_HARDWARE}.
250 */
251 @Override
252 public int getLayerType() {
253 return LAYER_TYPE_HARDWARE;
254 }
255
Romain Guy59c7f802011-09-29 17:21:45 -0700256 @Override
257 boolean hasStaticLayer() {
258 return true;
259 }
260
Romain Guyaa6c24c2011-04-28 18:40:04 -0700261 /**
262 * Calling this method has no effect.
263 */
264 @Override
265 public void buildLayer() {
266 }
267
268 /**
269 * Subclasses of TextureView cannot do their own rendering
270 * with the {@link Canvas} object.
271 *
272 * @param canvas The Canvas to which the View is rendered.
273 */
274 @Override
275 public final void draw(Canvas canvas) {
Romain Guy58f4edb2011-06-24 14:51:38 -0700276 applyUpdate();
Alexandre Eliasc01391f2011-08-19 16:03:16 -0700277 applyTransformMatrix();
Romain Guyaa6c24c2011-04-28 18:40:04 -0700278 }
279
280 /**
281 * Subclasses of TextureView cannot do their own rendering
282 * with the {@link Canvas} object.
283 *
284 * @param canvas The Canvas to which the View is rendered.
285 */
286 @Override
287 protected final void onDraw(Canvas canvas) {
288 }
289
290 @Override
Romain Guy8f0095c2011-05-02 17:24:22 -0700291 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
292 super.onSizeChanged(w, h, oldw, oldh);
293 if (mSurface != null) {
Romain Guye5e0c502011-06-15 15:18:31 -0700294 nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
Romain Guy451ce442011-06-10 15:40:36 -0700295 if (mListener != null) {
296 mListener.onSurfaceTextureSizeChanged(mSurface, getWidth(), getHeight());
297 }
Romain Guy8f0095c2011-05-02 17:24:22 -0700298 }
299 }
300
301 @Override
Romain Guya998dff2012-03-23 18:58:36 -0700302 boolean destroyLayer(boolean valid) {
Romain Guy16260e72011-09-01 14:26:11 -0700303 return false;
304 }
305
Romain Guy1766b0e2011-11-21 18:28:49 -0800306 /**
307 * @hide
308 */
Romain Guy16260e72011-09-01 14:26:11 -0700309 @Override
Romain Guy31f2c2e2011-11-21 10:55:41 -0800310 protected void destroyHardwareResources() {
311 super.destroyHardwareResources();
312 destroySurface();
313 invalidateParentCaches();
314 invalidate(true);
315 }
316
317 @Override
Michael Jurka7e52caf2012-03-06 15:57:06 -0800318 HardwareLayer getHardwareLayer() {
Romain Guyaa6c24c2011-04-28 18:40:04 -0700319 if (mLayer == null) {
Romain Guy58f4edb2011-06-24 14:51:38 -0700320 if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
321 return null;
322 }
323
Romain Guya9489272011-06-22 20:58:11 -0700324 mLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer(mOpaque);
Romain Guye5e0c502011-06-15 15:18:31 -0700325 mSurface = mAttachInfo.mHardwareRenderer.createSurfaceTexture(mLayer);
326 nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
Romain Guy6be3d552011-07-14 18:08:37 -0700327 nCreateNativeWindow(mSurface);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700328
Romain Guy8f0095c2011-05-02 17:24:22 -0700329 mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() {
Romain Guyaa6c24c2011-04-28 18:40:04 -0700330 @Override
331 public void onFrameAvailable(SurfaceTexture surfaceTexture) {
332 // Per SurfaceTexture's documentation, the callback may be invoked
333 // from an arbitrary thread
Romain Guy58f4edb2011-06-24 14:51:38 -0700334 synchronized (mLock) {
335 mUpdateLayer = true;
336 }
Jeff Brown6cb7b462012-03-05 13:21:17 -0800337 postInvalidate();
Romain Guyaa6c24c2011-04-28 18:40:04 -0700338 }
Romain Guy8f0095c2011-05-02 17:24:22 -0700339 };
340 mSurface.setOnFrameAvailableListener(mUpdateListener);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700341
342 if (mListener != null) {
Romain Guy451ce442011-06-10 15:40:36 -0700343 mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight());
Romain Guyaa6c24c2011-04-28 18:40:04 -0700344 }
345 }
346
Romain Guy58f4edb2011-06-24 14:51:38 -0700347 applyUpdate();
Alexandre Eliasc01391f2011-08-19 16:03:16 -0700348 applyTransformMatrix();
Romain Guy302a9df2011-08-16 13:55:02 -0700349
Romain Guyaa6c24c2011-04-28 18:40:04 -0700350 return mLayer;
351 }
352
Romain Guy8f0095c2011-05-02 17:24:22 -0700353 @Override
354 protected void onVisibilityChanged(View changedView, int visibility) {
355 super.onVisibilityChanged(changedView, visibility);
356
357 if (mSurface != null) {
358 // When the view becomes invisible, stop updating it, it's a waste of CPU
359 // To cancel updates, the easiest thing to do is simply to remove the
360 // updates listener
361 if (visibility == VISIBLE) {
362 mSurface.setOnFrameAvailableListener(mUpdateListener);
Romain Guya9489272011-06-22 20:58:11 -0700363 updateLayer();
Romain Guy8f0095c2011-05-02 17:24:22 -0700364 } else {
365 mSurface.setOnFrameAvailableListener(null);
366 }
367 }
368 }
369
Romain Guya9489272011-06-22 20:58:11 -0700370 private void updateLayer() {
Romain Guy58f4edb2011-06-24 14:51:38 -0700371 mUpdateLayer = true;
372 invalidate();
373 }
374
375 private void applyUpdate() {
376 if (mLayer == null) {
Romain Guya9489272011-06-22 20:58:11 -0700377 return;
378 }
379
Romain Guy58f4edb2011-06-24 14:51:38 -0700380 synchronized (mLock) {
381 if (mUpdateLayer) {
382 mUpdateLayer = false;
383 } else {
384 return;
385 }
386 }
387
Romain Guy02ccac62011-06-24 13:20:23 -0700388 mLayer.update(getWidth(), getHeight(), mOpaque);
Romain Guya9489272011-06-22 20:58:11 -0700389
Grace Klobacf559372011-06-22 23:05:40 -0700390 if (mListener != null) {
391 mListener.onSurfaceTextureUpdated(mSurface);
392 }
Romain Guya9489272011-06-22 20:58:11 -0700393 }
394
Romain Guyaa6c24c2011-04-28 18:40:04 -0700395 /**
Romain Guy302a9df2011-08-16 13:55:02 -0700396 * <p>Sets the transform to associate with this texture view.
397 * The specified transform applies to the underlying surface
398 * texture and does not affect the size or position of the view
399 * itself, only of its content.</p>
400 *
401 * <p>Some transforms might prevent the content from drawing
402 * all the pixels contained within this view's bounds. In such
403 * situations, make sure this texture view is not marked opaque.</p>
404 *
405 * @param transform The transform to apply to the content of
406 * this view.
407 *
408 * @see #getTransform(android.graphics.Matrix)
409 * @see #isOpaque()
410 * @see #setOpaque(boolean)
411 */
412 public void setTransform(Matrix transform) {
413 mMatrix.set(transform);
414 mMatrixChanged = true;
Alexandre Eliasc01391f2011-08-19 16:03:16 -0700415 invalidateParentIfNeeded();
Romain Guy302a9df2011-08-16 13:55:02 -0700416 }
417
418 /**
419 * Returns the transform associated with this texture view.
420 *
421 * @param transform The {@link Matrix} in which to copy the current
422 * transform. Can be null.
423 *
424 * @return The specified matrix if not null or a new {@link Matrix}
425 * instance otherwise.
426 *
427 * @see #setTransform(android.graphics.Matrix)
428 */
429 public Matrix getTransform(Matrix transform) {
430 if (transform == null) {
431 transform = new Matrix();
432 }
433
434 transform.set(mMatrix);
435
436 return transform;
437 }
438
Alexandre Eliasc01391f2011-08-19 16:03:16 -0700439 private void applyTransformMatrix() {
440 if (mMatrixChanged) {
441 mLayer.setTransform(mMatrix);
442 mMatrixChanged = false;
443 }
444 }
445
Romain Guy302a9df2011-08-16 13:55:02 -0700446 /**
Romain Guy77a81162011-06-14 16:45:55 -0700447 * <p>Returns a {@link android.graphics.Bitmap} representation of the content
448 * of the associated surface texture. If the surface texture is not available,
449 * this method returns null.</p>
450 *
451 * <p>The bitmap returned by this method uses the {@link Bitmap.Config#ARGB_8888}
452 * pixel format and its dimensions are the same as this view's.</p>
453 *
454 * <p><strong>Do not</strong> invoke this method from a drawing method
455 * ({@link #onDraw(android.graphics.Canvas)} for instance).</p>
456 *
Romain Guyd6b2a002011-06-17 17:45:59 -0700457 * <p>If an error occurs during the copy, an empty bitmap will be returned.</p>
458 *
Romain Guy77a81162011-06-14 16:45:55 -0700459 * @return A valid {@link Bitmap.Config#ARGB_8888} bitmap, or null if the surface
460 * texture is not available or the width &lt;= 0 or the height &lt;= 0
461 *
462 * @see #isAvailable()
463 * @see #getBitmap(android.graphics.Bitmap)
464 * @see #getBitmap(int, int)
465 */
466 public Bitmap getBitmap() {
467 return getBitmap(getWidth(), getHeight());
468 }
469
470 /**
471 * <p>Returns a {@link android.graphics.Bitmap} representation of the content
472 * of the associated surface texture. If the surface texture is not available,
473 * this method returns null.</p>
474 *
475 * <p>The bitmap returned by this method uses the {@link Bitmap.Config#ARGB_8888}
476 * pixel format.</p>
477 *
478 * <p><strong>Do not</strong> invoke this method from a drawing method
479 * ({@link #onDraw(android.graphics.Canvas)} for instance).</p>
480 *
Romain Guyd6b2a002011-06-17 17:45:59 -0700481 * <p>If an error occurs during the copy, an empty bitmap will be returned.</p>
482 *
Romain Guy77a81162011-06-14 16:45:55 -0700483 * @param width The width of the bitmap to create
484 * @param height The height of the bitmap to create
485 *
486 * @return A valid {@link Bitmap.Config#ARGB_8888} bitmap, or null if the surface
487 * texture is not available or width is &lt;= 0 or height is &lt;= 0
488 *
489 * @see #isAvailable()
490 * @see #getBitmap(android.graphics.Bitmap)
491 * @see #getBitmap()
492 */
493 public Bitmap getBitmap(int width, int height) {
494 if (isAvailable() && width > 0 && height > 0) {
495 return getBitmap(Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888));
496 }
497 return null;
498 }
499
500 /**
501 * <p>Copies the content of this view's surface texture into the specified
502 * bitmap. If the surface texture is not available, the copy is not executed.
503 * The content of the surface texture will be scaled to fit exactly inside
504 * the specified bitmap.</p>
505 *
506 * <p><strong>Do not</strong> invoke this method from a drawing method
507 * ({@link #onDraw(android.graphics.Canvas)} for instance).</p>
508 *
Romain Guyd6b2a002011-06-17 17:45:59 -0700509 * <p>If an error occurs, the bitmap is left unchanged.</p>
510 *
Romain Guy77a81162011-06-14 16:45:55 -0700511 * @param bitmap The bitmap to copy the content of the surface texture into,
512 * cannot be null, all configurations are supported
513 *
514 * @return The bitmap specified as a parameter
515 *
516 * @see #isAvailable()
517 * @see #getBitmap(int, int)
518 * @see #getBitmap()
Romain Guy589b0bb2011-10-10 13:57:47 -0700519 *
520 * @throws IllegalStateException if the hardware rendering context cannot be
521 * acquired to capture the bitmap
Romain Guy77a81162011-06-14 16:45:55 -0700522 */
523 public Bitmap getBitmap(Bitmap bitmap) {
524 if (bitmap != null && isAvailable()) {
Romain Guy589b0bb2011-10-10 13:57:47 -0700525 AttachInfo info = mAttachInfo;
526 if (info != null && info.mHardwareRenderer != null &&
527 info.mHardwareRenderer.isEnabled()) {
528 if (!info.mHardwareRenderer.validate()) {
529 throw new IllegalStateException("Could not acquire hardware rendering context");
530 }
531 }
532
533 applyUpdate();
534 applyTransformMatrix();
535
Romain Guy02ccac62011-06-24 13:20:23 -0700536 mLayer.copyInto(bitmap);
Romain Guy77a81162011-06-14 16:45:55 -0700537 }
538 return bitmap;
539 }
540
541 /**
542 * Returns true if the {@link SurfaceTexture} associated with this
543 * TextureView is available for rendering. When this method returns
544 * true, {@link #getSurfaceTexture()} returns a valid surface texture.
545 */
546 public boolean isAvailable() {
547 return mSurface != null;
548 }
549
550 /**
Romain Guy6be3d552011-07-14 18:08:37 -0700551 * <p>Start editing the pixels in the surface. The returned Canvas can be used
552 * to draw into the surface's bitmap. A null is returned if the surface has
553 * not been created or otherwise cannot be edited. You will usually need
554 * to implement
555 * {@link SurfaceTextureListener#onSurfaceTextureAvailable(android.graphics.SurfaceTexture, int, int)}
556 * to find out when the Surface is available for use.</p>
557 *
558 * <p>The content of the Surface is never preserved between unlockCanvas()
559 * and lockCanvas(), for this reason, every pixel within the Surface area
560 * must be written. The only exception to this rule is when a dirty
561 * rectangle is specified, in which case, non-dirty pixels will be
562 * preserved.</p>
563 *
Romain Guy462785f2011-09-27 17:42:10 -0700564 * <p>This method can only be used if the underlying surface is not already
565 * owned by another producer. For instance, if the TextureView is being used
566 * to render the camera's preview you cannot invoke this method.</p>
567 *
Romain Guy6be3d552011-07-14 18:08:37 -0700568 * @return A Canvas used to draw into the surface.
569 *
570 * @see #lockCanvas(android.graphics.Rect)
571 * @see #unlockCanvasAndPost(android.graphics.Canvas)
572 */
573 public Canvas lockCanvas() {
574 return lockCanvas(null);
575 }
576
577 /**
578 * Just like {@link #lockCanvas()} but allows specification of a dirty
579 * rectangle. Every pixel within that rectangle must be written; however
580 * pixels outside the dirty rectangle will be preserved by the next call
581 * to lockCanvas().
582 *
583 * @param dirty Area of the surface that will be modified.
584
585 * @return A Canvas used to draw into the surface.
586 *
587 * @see #lockCanvas()
588 * @see #unlockCanvasAndPost(android.graphics.Canvas)
589 */
590 public Canvas lockCanvas(Rect dirty) {
591 if (!isAvailable()) return null;
592
593 if (mCanvas == null) {
594 mCanvas = new Canvas();
595 }
596
597 synchronized (mNativeWindowLock) {
598 nLockCanvas(mNativeWindow, mCanvas, dirty);
599 }
600 mSaveCount = mCanvas.save();
601
602 return mCanvas;
603 }
604
605 /**
606 * Finish editing pixels in the surface. After this call, the surface's
607 * current pixels will be shown on the screen, but its content is lost,
608 * in particular there is no guarantee that the content of the Surface
609 * will remain unchanged when lockCanvas() is called again.
610 *
611 * @param canvas The Canvas previously returned by lockCanvas()
612 *
613 * @see #lockCanvas()
614 * @see #lockCanvas(android.graphics.Rect)
615 */
616 public void unlockCanvasAndPost(Canvas canvas) {
617 if (mCanvas != null && canvas == mCanvas) {
618 canvas.restoreToCount(mSaveCount);
619 mSaveCount = 0;
620
621 synchronized (mNativeWindowLock) {
622 nUnlockCanvasAndPost(mNativeWindow, mCanvas);
623 }
624 }
625 }
626
627 /**
Romain Guyaa6c24c2011-04-28 18:40:04 -0700628 * Returns the {@link SurfaceTexture} used by this view. This method
Romain Guy77a81162011-06-14 16:45:55 -0700629 * may return null if the view is not attached to a window or if the surface
630 * texture has not been initialized yet.
631 *
632 * @see #isAvailable()
Romain Guyaa6c24c2011-04-28 18:40:04 -0700633 */
634 public SurfaceTexture getSurfaceTexture() {
635 return mSurface;
636 }
637
638 /**
639 * Returns the {@link SurfaceTextureListener} currently associated with this
640 * texture view.
641 *
642 * @see #setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener)
643 * @see SurfaceTextureListener
644 */
645 public SurfaceTextureListener getSurfaceTextureListener() {
646 return mListener;
647 }
648
649 /**
650 * Sets the {@link SurfaceTextureListener} used to listen to surface
651 * texture events.
652 *
653 * @see #getSurfaceTextureListener()
654 * @see SurfaceTextureListener
655 */
656 public void setSurfaceTextureListener(SurfaceTextureListener listener) {
657 mListener = listener;
658 }
659
660 /**
661 * This listener can be used to be notified when the surface texture
662 * associated with this texture view is available.
663 */
664 public static interface SurfaceTextureListener {
665 /**
666 * Invoked when a {@link TextureView}'s SurfaceTexture is ready for use.
667 *
668 * @param surface The surface returned by
669 * {@link android.view.TextureView#getSurfaceTexture()}
Romain Guy451ce442011-06-10 15:40:36 -0700670 * @param width The width of the surface
671 * @param height The height of the surface
Romain Guyaa6c24c2011-04-28 18:40:04 -0700672 */
Romain Guy451ce442011-06-10 15:40:36 -0700673 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height);
Romain Guy8f0095c2011-05-02 17:24:22 -0700674
675 /**
676 * Invoked when the {@link SurfaceTexture}'s buffers size changed.
677 *
678 * @param surface The surface returned by
679 * {@link android.view.TextureView#getSurfaceTexture()}
680 * @param width The new width of the surface
681 * @param height The new height of the surface
682 */
683 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height);
Romain Guy451ce442011-06-10 15:40:36 -0700684
685 /**
686 * Invoked when the specified {@link SurfaceTexture} is about to be destroyed.
Grace Kloba402f0552011-08-09 18:47:17 -0700687 * If returns true, no rendering should happen inside the surface texture after this method
688 * is invoked. If returns false, the client needs to call {@link SurfaceTexture#release()}.
Romain Guy451ce442011-06-10 15:40:36 -0700689 *
690 * @param surface The surface about to be destroyed
691 */
Grace Kloba402f0552011-08-09 18:47:17 -0700692 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface);
Grace Klobacf559372011-06-22 23:05:40 -0700693
694 /**
695 * Invoked when the specified {@link SurfaceTexture} is updated through
696 * {@link SurfaceTexture#updateTexImage()}.
697 *
698 * @param surface The surface just updated
699 */
700 public void onSurfaceTextureUpdated(SurfaceTexture surface);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700701 }
Romain Guy8f0095c2011-05-02 17:24:22 -0700702
Romain Guy6be3d552011-07-14 18:08:37 -0700703 private native void nCreateNativeWindow(SurfaceTexture surface);
704 private native void nDestroyNativeWindow();
705
Romain Guyd6b2a002011-06-17 17:45:59 -0700706 private static native void nSetDefaultBufferSize(SurfaceTexture surfaceTexture,
707 int width, int height);
Romain Guy6be3d552011-07-14 18:08:37 -0700708
709 private static native void nLockCanvas(int nativeWindow, Canvas canvas, Rect dirty);
710 private static native void nUnlockCanvasAndPost(int nativeWindow, Canvas canvas);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700711}