• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package android.view;
18 
19 import android.annotation.Nullable;
20 import android.content.Context;
21 import android.graphics.Bitmap;
22 import android.graphics.Canvas;
23 import android.graphics.Matrix;
24 import android.graphics.Paint;
25 import android.graphics.Rect;
26 import android.graphics.SurfaceTexture;
27 import android.graphics.drawable.Drawable;
28 import android.util.AttributeSet;
29 import android.util.Log;
30 
31 /**
32  * <p>A TextureView can be used to display a content stream. Such a content
33  * stream can for instance be a video or an OpenGL scene. The content stream
34  * can come from the application's process as well as a remote process.</p>
35  *
36  * <p>TextureView can only be used in a hardware accelerated window. When
37  * rendered in software, TextureView will draw nothing.</p>
38  *
39  * <p>Unlike {@link SurfaceView}, TextureView does not create a separate
40  * window but behaves as a regular View. This key difference allows a
41  * TextureView to be moved, transformed, animated, etc. For instance, you
42  * can make a TextureView semi-translucent by calling
43  * <code>myView.setAlpha(0.5f)</code>.</p>
44  *
45  * <p>Using a TextureView is simple: all you need to do is get its
46  * {@link SurfaceTexture}. The {@link SurfaceTexture} can then be used to
47  * render content. The following example demonstrates how to render the
48  * camera preview into a TextureView:</p>
49  *
50  * <pre>
51  *  public class LiveCameraActivity extends Activity implements TextureView.SurfaceTextureListener {
52  *      private Camera mCamera;
53  *      private TextureView mTextureView;
54  *
55  *      protected void onCreate(Bundle savedInstanceState) {
56  *          super.onCreate(savedInstanceState);
57  *
58  *          mTextureView = new TextureView(this);
59  *          mTextureView.setSurfaceTextureListener(this);
60  *
61  *          setContentView(mTextureView);
62  *      }
63  *
64  *      public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
65  *          mCamera = Camera.open();
66  *
67  *          try {
68  *              mCamera.setPreviewTexture(surface);
69  *              mCamera.startPreview();
70  *          } catch (IOException ioe) {
71  *              // Something bad happened
72  *          }
73  *      }
74  *
75  *      public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
76  *          // Ignored, Camera does all the work for us
77  *      }
78  *
79  *      public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
80  *          mCamera.stopPreview();
81  *          mCamera.release();
82  *          return true;
83  *      }
84  *
85  *      public void onSurfaceTextureUpdated(SurfaceTexture surface) {
86  *          // Invoked every time there's a new Camera preview frame
87  *      }
88  *  }
89  * </pre>
90  *
91  * <p>A TextureView's SurfaceTexture can be obtained either by invoking
92  * {@link #getSurfaceTexture()} or by using a {@link SurfaceTextureListener}.
93  * It is important to know that a SurfaceTexture is available only after the
94  * TextureView is attached to a window (and {@link #onAttachedToWindow()} has
95  * been invoked.) It is therefore highly recommended you use a listener to
96  * be notified when the SurfaceTexture becomes available.</p>
97  *
98  * <p>It is important to note that only one producer can use the TextureView.
99  * For instance, if you use a TextureView to display the camera preview, you
100  * cannot use {@link #lockCanvas()} to draw onto the TextureView at the same
101  * time.</p>
102  *
103  * @see SurfaceView
104  * @see SurfaceTexture
105  */
106 public class TextureView extends View {
107     private static final String LOG_TAG = "TextureView";
108 
109     private HardwareLayer mLayer;
110     private SurfaceTexture mSurface;
111     private SurfaceTextureListener mListener;
112     private boolean mHadSurface;
113 
114     private boolean mOpaque = true;
115 
116     private final Matrix mMatrix = new Matrix();
117     private boolean mMatrixChanged;
118 
119     private final Object[] mLock = new Object[0];
120     private boolean mUpdateLayer;
121     private boolean mUpdateSurface;
122 
123     private Canvas mCanvas;
124     private int mSaveCount;
125 
126     private final Object[] mNativeWindowLock = new Object[0];
127     // Set by native code, do not write!
128     private long mNativeWindow;
129 
130     /**
131      * Creates a new TextureView.
132      *
133      * @param context The context to associate this view with.
134      */
TextureView(Context context)135     public TextureView(Context context) {
136         super(context);
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      */
TextureView(Context context, AttributeSet attrs)145     public TextureView(Context context, AttributeSet attrs) {
146         super(context, attrs);
147     }
148 
149     /**
150      * Creates a new TextureView.
151      *
152      * @param context The context to associate this view with.
153      * @param attrs The attributes of the XML tag that is inflating the view.
154      * @param defStyleAttr An attribute in the current theme that contains a
155      *        reference to a style resource that supplies default values for
156      *        the view. Can be 0 to not look for defaults.
157      */
TextureView(Context context, AttributeSet attrs, int defStyleAttr)158     public TextureView(Context context, AttributeSet attrs, int defStyleAttr) {
159         super(context, attrs, defStyleAttr);
160     }
161 
162     /**
163      * Creates a new TextureView.
164      *
165      * @param context The context to associate this view with.
166      * @param attrs The attributes of the XML tag that is inflating the view.
167      * @param defStyleAttr An attribute in the current theme that contains a
168      *        reference to a style resource that supplies default values for
169      *        the view. Can be 0 to not look for defaults.
170      * @param defStyleRes A resource identifier of a style resource that
171      *        supplies default values for the view, used only if
172      *        defStyleAttr is 0 or can not be found in the theme. Can be 0
173      *        to not look for defaults.
174      */
TextureView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)175     public TextureView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
176         super(context, attrs, defStyleAttr, defStyleRes);
177     }
178 
179     /**
180      * {@inheritDoc}
181      */
182     @Override
isOpaque()183     public boolean isOpaque() {
184         return mOpaque;
185     }
186 
187     /**
188      * Indicates whether the content of this TextureView is opaque. The
189      * content is assumed to be opaque by default.
190      *
191      * @param opaque True if the content of this TextureView is opaque,
192      *               false otherwise
193      */
setOpaque(boolean opaque)194     public void setOpaque(boolean opaque) {
195         if (opaque != mOpaque) {
196             mOpaque = opaque;
197             if (mLayer != null) {
198                 updateLayerAndInvalidate();
199             }
200         }
201     }
202 
203     @Override
onAttachedToWindow()204     protected void onAttachedToWindow() {
205         super.onAttachedToWindow();
206 
207         if (!isHardwareAccelerated()) {
208             Log.w(LOG_TAG, "A TextureView or a subclass can only be "
209                     + "used with hardware acceleration enabled.");
210         }
211 
212         if (mHadSurface) {
213             invalidate(true);
214             mHadSurface = false;
215         }
216     }
217 
218     /** @hide */
219     @Override
onDetachedFromWindowInternal()220     protected void onDetachedFromWindowInternal() {
221         destroyHardwareLayer();
222         releaseSurfaceTexture();
223         super.onDetachedFromWindowInternal();
224     }
225 
226     /**
227      * @hide
228      */
229     @Override
destroyHardwareResources()230     protected void destroyHardwareResources() {
231         destroyHardwareLayer();
232     }
233 
destroyHardwareLayer()234     private void destroyHardwareLayer() {
235         if (mLayer != null) {
236             mLayer.detachSurfaceTexture();
237             mLayer.destroy();
238             mLayer = null;
239             mMatrixChanged = true;
240         }
241     }
242 
releaseSurfaceTexture()243     private void releaseSurfaceTexture() {
244         if (mSurface != null) {
245             boolean shouldRelease = true;
246 
247             if (mListener != null) {
248                 shouldRelease = mListener.onSurfaceTextureDestroyed(mSurface);
249             }
250 
251             synchronized (mNativeWindowLock) {
252                 nDestroyNativeWindow();
253             }
254 
255             if (shouldRelease) {
256                 mSurface.release();
257             }
258             mSurface = null;
259             mHadSurface = true;
260         }
261     }
262 
263     /**
264      * The layer type of a TextureView is ignored since a TextureView is always
265      * considered to act as a hardware layer. The optional paint supplied to this
266      * method will however be taken into account when rendering the content of
267      * this TextureView.
268      *
269      * @param layerType The type of layer to use with this view, must be one of
270      *        {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
271      *        {@link #LAYER_TYPE_HARDWARE}
272      * @param paint The paint used to compose the layer. This argument is optional
273      *        and can be null. It is ignored when the layer type is
274      *        {@link #LAYER_TYPE_NONE}
275      */
276     @Override
setLayerType(int layerType, @Nullable Paint paint)277     public void setLayerType(int layerType, @Nullable Paint paint) {
278         setLayerPaint(paint);
279     }
280 
281     @Override
setLayerPaint(@ullable Paint paint)282     public void setLayerPaint(@Nullable Paint paint) {
283         if (paint != mLayerPaint) {
284             mLayerPaint = paint;
285             invalidate();
286         }
287     }
288 
289     /**
290      * Always returns {@link #LAYER_TYPE_HARDWARE}.
291      */
292     @Override
getLayerType()293     public int getLayerType() {
294         return LAYER_TYPE_HARDWARE;
295     }
296 
297     /**
298      * Calling this method has no effect.
299      */
300     @Override
buildLayer()301     public void buildLayer() {
302     }
303 
304     @Override
setForeground(Drawable foreground)305     public void setForeground(Drawable foreground) {
306         if (foreground != null && !sTextureViewIgnoresDrawableSetters) {
307             throw new UnsupportedOperationException(
308                     "TextureView doesn't support displaying a foreground drawable");
309         }
310     }
311 
312     @Override
setBackgroundDrawable(Drawable background)313     public void setBackgroundDrawable(Drawable background) {
314         if (background != null && !sTextureViewIgnoresDrawableSetters) {
315             throw new UnsupportedOperationException(
316                     "TextureView doesn't support displaying a background drawable");
317         }
318     }
319 
320     /**
321      * Subclasses of TextureView cannot do their own rendering
322      * with the {@link Canvas} object.
323      *
324      * @param canvas The Canvas to which the View is rendered.
325      */
326     @Override
draw(Canvas canvas)327     public final void draw(Canvas canvas) {
328         // NOTE: Maintain this carefully (see View#draw)
329         mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
330 
331         /* Simplify drawing to guarantee the layer is the only thing drawn - so e.g. no background,
332         scrolling, or fading edges. This guarantees all drawing is in the layer, so drawing
333         properties (alpha, layer paint) affect all of the content of a TextureView. */
334 
335         if (canvas.isHardwareAccelerated()) {
336             DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
337 
338             HardwareLayer layer = getHardwareLayer();
339             if (layer != null) {
340                 applyUpdate();
341                 applyTransformMatrix();
342 
343                 mLayer.setLayerPaint(mLayerPaint); // ensure layer paint is up to date
344                 displayListCanvas.drawHardwareLayer(layer);
345             }
346         }
347     }
348 
349     /**
350      * Subclasses of TextureView cannot do their own rendering
351      * with the {@link Canvas} object.
352      *
353      * @param canvas The Canvas to which the View is rendered.
354      */
355     @Override
onDraw(Canvas canvas)356     protected final void onDraw(Canvas canvas) {
357     }
358 
359     @Override
onSizeChanged(int w, int h, int oldw, int oldh)360     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
361         super.onSizeChanged(w, h, oldw, oldh);
362         if (mSurface != null) {
363             mSurface.setDefaultBufferSize(getWidth(), getHeight());
364             updateLayer();
365             if (mListener != null) {
366                 mListener.onSurfaceTextureSizeChanged(mSurface, getWidth(), getHeight());
367             }
368         }
369     }
370 
getHardwareLayer()371     HardwareLayer getHardwareLayer() {
372         if (mLayer == null) {
373             if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
374                 return null;
375             }
376 
377             mLayer = mAttachInfo.mHardwareRenderer.createTextureLayer();
378             boolean createNewSurface = (mSurface == null);
379             if (createNewSurface) {
380                 // Create a new SurfaceTexture for the layer.
381                 mSurface = new SurfaceTexture(false);
382                 nCreateNativeWindow(mSurface);
383             }
384             mLayer.setSurfaceTexture(mSurface);
385             mSurface.setDefaultBufferSize(getWidth(), getHeight());
386             mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
387 
388             if (mListener != null && createNewSurface) {
389                 mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight());
390             }
391             mLayer.setLayerPaint(mLayerPaint);
392         }
393 
394         if (mUpdateSurface) {
395             // Someone has requested that we use a specific SurfaceTexture, so
396             // tell mLayer about it and set the SurfaceTexture to use the
397             // current view size.
398             mUpdateSurface = false;
399 
400             // Since we are updating the layer, force an update to ensure its
401             // parameters are correct (width, height, transform, etc.)
402             updateLayer();
403             mMatrixChanged = true;
404 
405             mLayer.setSurfaceTexture(mSurface);
406             mSurface.setDefaultBufferSize(getWidth(), getHeight());
407         }
408 
409         return mLayer;
410     }
411 
412     @Override
onVisibilityChanged(View changedView, int visibility)413     protected void onVisibilityChanged(View changedView, int visibility) {
414         super.onVisibilityChanged(changedView, visibility);
415 
416         if (mSurface != null) {
417             // When the view becomes invisible, stop updating it, it's a waste of CPU
418             // To cancel updates, the easiest thing to do is simply to remove the
419             // updates listener
420             if (visibility == VISIBLE) {
421                 if (mLayer != null) {
422                     mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
423                 }
424                 updateLayerAndInvalidate();
425             } else {
426                 mSurface.setOnFrameAvailableListener(null);
427             }
428         }
429     }
430 
updateLayer()431     private void updateLayer() {
432         synchronized (mLock) {
433             mUpdateLayer = true;
434         }
435     }
436 
updateLayerAndInvalidate()437     private void updateLayerAndInvalidate() {
438         synchronized (mLock) {
439             mUpdateLayer = true;
440         }
441         invalidate();
442     }
443 
applyUpdate()444     private void applyUpdate() {
445         if (mLayer == null) {
446             return;
447         }
448 
449         synchronized (mLock) {
450             if (mUpdateLayer) {
451                 mUpdateLayer = false;
452             } else {
453                 return;
454             }
455         }
456 
457         mLayer.prepare(getWidth(), getHeight(), mOpaque);
458         mLayer.updateSurfaceTexture();
459 
460         if (mListener != null) {
461             mListener.onSurfaceTextureUpdated(mSurface);
462         }
463     }
464 
465     /**
466      * <p>Sets the transform to associate with this texture view.
467      * The specified transform applies to the underlying surface
468      * texture and does not affect the size or position of the view
469      * itself, only of its content.</p>
470      *
471      * <p>Some transforms might prevent the content from drawing
472      * all the pixels contained within this view's bounds. In such
473      * situations, make sure this texture view is not marked opaque.</p>
474      *
475      * @param transform The transform to apply to the content of
476      *        this view.
477      *
478      * @see #getTransform(android.graphics.Matrix)
479      * @see #isOpaque()
480      * @see #setOpaque(boolean)
481      */
setTransform(Matrix transform)482     public void setTransform(Matrix transform) {
483         mMatrix.set(transform);
484         mMatrixChanged = true;
485         invalidateParentIfNeeded();
486     }
487 
488     /**
489      * Returns the transform associated with this texture view.
490      *
491      * @param transform The {@link Matrix} in which to copy the current
492      *        transform. Can be null.
493      *
494      * @return The specified matrix if not null or a new {@link Matrix}
495      *         instance otherwise.
496      *
497      * @see #setTransform(android.graphics.Matrix)
498      */
getTransform(Matrix transform)499     public Matrix getTransform(Matrix transform) {
500         if (transform == null) {
501             transform = new Matrix();
502         }
503 
504         transform.set(mMatrix);
505 
506         return transform;
507     }
508 
applyTransformMatrix()509     private void applyTransformMatrix() {
510         if (mMatrixChanged && mLayer != null) {
511             mLayer.setTransform(mMatrix);
512             mMatrixChanged = false;
513         }
514     }
515 
516     /**
517      * <p>Returns a {@link android.graphics.Bitmap} representation of the content
518      * of the associated surface texture. If the surface texture is not available,
519      * this method returns null.</p>
520      *
521      * <p>The bitmap returned by this method uses the {@link Bitmap.Config#ARGB_8888}
522      * pixel format and its dimensions are the same as this view's.</p>
523      *
524      * <p><strong>Do not</strong> invoke this method from a drawing method
525      * ({@link #onDraw(android.graphics.Canvas)} for instance).</p>
526      *
527      * <p>If an error occurs during the copy, an empty bitmap will be returned.</p>
528      *
529      * @return A valid {@link Bitmap.Config#ARGB_8888} bitmap, or null if the surface
530      *         texture is not available or the width &lt;= 0 or the height &lt;= 0
531      *
532      * @see #isAvailable()
533      * @see #getBitmap(android.graphics.Bitmap)
534      * @see #getBitmap(int, int)
535      */
getBitmap()536     public Bitmap getBitmap() {
537         return getBitmap(getWidth(), getHeight());
538     }
539 
540     /**
541      * <p>Returns a {@link android.graphics.Bitmap} representation of the content
542      * of the associated surface texture. If the surface texture is not available,
543      * this method returns null.</p>
544      *
545      * <p>The bitmap returned by this method uses the {@link Bitmap.Config#ARGB_8888}
546      * pixel format.</p>
547      *
548      * <p><strong>Do not</strong> invoke this method from a drawing method
549      * ({@link #onDraw(android.graphics.Canvas)} for instance).</p>
550      *
551      * <p>If an error occurs during the copy, an empty bitmap will be returned.</p>
552      *
553      * @param width The width of the bitmap to create
554      * @param height The height of the bitmap to create
555      *
556      * @return A valid {@link Bitmap.Config#ARGB_8888} bitmap, or null if the surface
557      *         texture is not available or width is &lt;= 0 or height is &lt;= 0
558      *
559      * @see #isAvailable()
560      * @see #getBitmap(android.graphics.Bitmap)
561      * @see #getBitmap()
562      */
getBitmap(int width, int height)563     public Bitmap getBitmap(int width, int height) {
564         if (isAvailable() && width > 0 && height > 0) {
565             return getBitmap(Bitmap.createBitmap(getResources().getDisplayMetrics(),
566                     width, height, Bitmap.Config.ARGB_8888));
567         }
568         return null;
569     }
570 
571     /**
572      * <p>Copies the content of this view's surface texture into the specified
573      * bitmap. If the surface texture is not available, the copy is not executed.
574      * The content of the surface texture will be scaled to fit exactly inside
575      * the specified bitmap.</p>
576      *
577      * <p><strong>Do not</strong> invoke this method from a drawing method
578      * ({@link #onDraw(android.graphics.Canvas)} for instance).</p>
579      *
580      * <p>If an error occurs, the bitmap is left unchanged.</p>
581      *
582      * @param bitmap The bitmap to copy the content of the surface texture into,
583      *               cannot be null, all configurations are supported
584      *
585      * @return The bitmap specified as a parameter
586      *
587      * @see #isAvailable()
588      * @see #getBitmap(int, int)
589      * @see #getBitmap()
590      *
591      * @throws IllegalStateException if the hardware rendering context cannot be
592      *         acquired to capture the bitmap
593      */
getBitmap(Bitmap bitmap)594     public Bitmap getBitmap(Bitmap bitmap) {
595         if (bitmap != null && isAvailable()) {
596             applyUpdate();
597             applyTransformMatrix();
598 
599             // This case can happen if the app invokes setSurfaceTexture() before
600             // we are able to create the hardware layer. We can safely initialize
601             // the layer here thanks to the validate() call at the beginning of
602             // this method
603             if (mLayer == null && mUpdateSurface) {
604                 getHardwareLayer();
605             }
606 
607             if (mLayer != null) {
608                 mLayer.copyInto(bitmap);
609             }
610         }
611         return bitmap;
612     }
613 
614     /**
615      * Returns true if the {@link SurfaceTexture} associated with this
616      * TextureView is available for rendering. When this method returns
617      * true, {@link #getSurfaceTexture()} returns a valid surface texture.
618      */
isAvailable()619     public boolean isAvailable() {
620         return mSurface != null;
621     }
622 
623     /**
624      * <p>Start editing the pixels in the surface.  The returned Canvas can be used
625      * to draw into the surface's bitmap.  A null is returned if the surface has
626      * not been created or otherwise cannot be edited. You will usually need
627      * to implement
628      * {@link SurfaceTextureListener#onSurfaceTextureAvailable(android.graphics.SurfaceTexture, int, int)}
629      * to find out when the Surface is available for use.</p>
630      *
631      * <p>The content of the Surface is never preserved between unlockCanvas()
632      * and lockCanvas(), for this reason, every pixel within the Surface area
633      * must be written. The only exception to this rule is when a dirty
634      * rectangle is specified, in which case, non-dirty pixels will be
635      * preserved.</p>
636      *
637      * <p>This method can only be used if the underlying surface is not already
638      * owned by another producer. For instance, if the TextureView is being used
639      * to render the camera's preview you cannot invoke this method.</p>
640      *
641      * @return A Canvas used to draw into the surface.
642      *
643      * @see #lockCanvas(android.graphics.Rect)
644      * @see #unlockCanvasAndPost(android.graphics.Canvas)
645      */
lockCanvas()646     public Canvas lockCanvas() {
647         return lockCanvas(null);
648     }
649 
650     /**
651      * Just like {@link #lockCanvas()} but allows specification of a dirty
652      * rectangle. Every pixel within that rectangle must be written; however
653      * pixels outside the dirty rectangle will be preserved by the next call
654      * to lockCanvas().
655      *
656      * This method can return null if the underlying surface texture is not
657      * available (see {@link #isAvailable()} or if the surface texture is
658      * already connected to an image producer (for instance: the camera,
659      * OpenGL, a media player, etc.)
660      *
661      * @param dirty Area of the surface that will be modified.
662 
663      * @return A Canvas used to draw into the surface.
664      *
665      * @see #lockCanvas()
666      * @see #unlockCanvasAndPost(android.graphics.Canvas)
667      * @see #isAvailable()
668      */
lockCanvas(Rect dirty)669     public Canvas lockCanvas(Rect dirty) {
670         if (!isAvailable()) return null;
671 
672         if (mCanvas == null) {
673             mCanvas = new Canvas();
674         }
675 
676         synchronized (mNativeWindowLock) {
677             if (!nLockCanvas(mNativeWindow, mCanvas, dirty)) {
678                 return null;
679             }
680         }
681         mSaveCount = mCanvas.save();
682 
683         return mCanvas;
684     }
685 
686     /**
687      * Finish editing pixels in the surface. After this call, the surface's
688      * current pixels will be shown on the screen, but its content is lost,
689      * in particular there is no guarantee that the content of the Surface
690      * will remain unchanged when lockCanvas() is called again.
691      *
692      * @param canvas The Canvas previously returned by lockCanvas()
693      *
694      * @see #lockCanvas()
695      * @see #lockCanvas(android.graphics.Rect)
696      */
unlockCanvasAndPost(Canvas canvas)697     public void unlockCanvasAndPost(Canvas canvas) {
698         if (mCanvas != null && canvas == mCanvas) {
699             canvas.restoreToCount(mSaveCount);
700             mSaveCount = 0;
701 
702             synchronized (mNativeWindowLock) {
703                 nUnlockCanvasAndPost(mNativeWindow, mCanvas);
704             }
705         }
706     }
707 
708     /**
709      * Returns the {@link SurfaceTexture} used by this view. This method
710      * may return null if the view is not attached to a window or if the surface
711      * texture has not been initialized yet.
712      *
713      * @see #isAvailable()
714      */
getSurfaceTexture()715     public SurfaceTexture getSurfaceTexture() {
716         return mSurface;
717     }
718 
719     /**
720      * Set the {@link SurfaceTexture} for this view to use. If a {@link
721      * SurfaceTexture} is already being used by this view, it is immediately
722      * released and not be usable any more.  The {@link
723      * SurfaceTextureListener#onSurfaceTextureDestroyed} callback is <b>not</b>
724      * called for the previous {@link SurfaceTexture}.  Similarly, the {@link
725      * SurfaceTextureListener#onSurfaceTextureAvailable} callback is <b>not</b>
726      * called for the {@link SurfaceTexture} passed to setSurfaceTexture.
727      *
728      * The {@link SurfaceTexture} object must be detached from all OpenGL ES
729      * contexts prior to calling this method.
730      *
731      * @param surfaceTexture The {@link SurfaceTexture} that the view should use.
732      * @see SurfaceTexture#detachFromGLContext()
733      */
setSurfaceTexture(SurfaceTexture surfaceTexture)734     public void setSurfaceTexture(SurfaceTexture surfaceTexture) {
735         if (surfaceTexture == null) {
736             throw new NullPointerException("surfaceTexture must not be null");
737         }
738         if (surfaceTexture == mSurface) {
739             throw new IllegalArgumentException("Trying to setSurfaceTexture to " +
740                     "the same SurfaceTexture that's already set.");
741         }
742         if (surfaceTexture.isReleased()) {
743             throw new IllegalArgumentException("Cannot setSurfaceTexture to a " +
744                     "released SurfaceTexture");
745         }
746         if (mSurface != null) {
747             nDestroyNativeWindow();
748             mSurface.release();
749         }
750         mSurface = surfaceTexture;
751         nCreateNativeWindow(mSurface);
752 
753         /*
754          * If the view is visible and we already made a layer, update the
755          * listener in the new surface to use the existing listener in the view.
756          * Otherwise this will be called when the view becomes visible or the
757          * layer is created
758          */
759         if (((mViewFlags & VISIBILITY_MASK) == VISIBLE) && mLayer != null) {
760             mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
761         }
762         mUpdateSurface = true;
763         invalidateParentIfNeeded();
764     }
765 
766     /**
767      * Returns the {@link SurfaceTextureListener} currently associated with this
768      * texture view.
769      *
770      * @see #setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener)
771      * @see SurfaceTextureListener
772      */
getSurfaceTextureListener()773     public SurfaceTextureListener getSurfaceTextureListener() {
774         return mListener;
775     }
776 
777     /**
778      * Sets the {@link SurfaceTextureListener} used to listen to surface
779      * texture events.
780      *
781      * @see #getSurfaceTextureListener()
782      * @see SurfaceTextureListener
783      */
setSurfaceTextureListener(SurfaceTextureListener listener)784     public void setSurfaceTextureListener(SurfaceTextureListener listener) {
785         mListener = listener;
786     }
787 
788     private final SurfaceTexture.OnFrameAvailableListener mUpdateListener =
789             new SurfaceTexture.OnFrameAvailableListener() {
790         @Override
791         public void onFrameAvailable(SurfaceTexture surfaceTexture) {
792             updateLayer();
793             invalidate();
794         }
795     };
796 
797     /**
798      * This listener can be used to be notified when the surface texture
799      * associated with this texture view is available.
800      */
801     public static interface SurfaceTextureListener {
802         /**
803          * Invoked when a {@link TextureView}'s SurfaceTexture is ready for use.
804          *
805          * @param surface The surface returned by
806          *                {@link android.view.TextureView#getSurfaceTexture()}
807          * @param width The width of the surface
808          * @param height The height of the surface
809          */
onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)810         public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height);
811 
812         /**
813          * Invoked when the {@link SurfaceTexture}'s buffers size changed.
814          *
815          * @param surface The surface returned by
816          *                {@link android.view.TextureView#getSurfaceTexture()}
817          * @param width The new width of the surface
818          * @param height The new height of the surface
819          */
onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)820         public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height);
821 
822         /**
823          * Invoked when the specified {@link SurfaceTexture} is about to be destroyed.
824          * If returns true, no rendering should happen inside the surface texture after this method
825          * is invoked. If returns false, the client needs to call {@link SurfaceTexture#release()}.
826          * Most applications should return true.
827          *
828          * @param surface The surface about to be destroyed
829          */
onSurfaceTextureDestroyed(SurfaceTexture surface)830         public boolean onSurfaceTextureDestroyed(SurfaceTexture surface);
831 
832         /**
833          * Invoked when the specified {@link SurfaceTexture} is updated through
834          * {@link SurfaceTexture#updateTexImage()}.
835          *
836          * @param surface The surface just updated
837          */
onSurfaceTextureUpdated(SurfaceTexture surface)838         public void onSurfaceTextureUpdated(SurfaceTexture surface);
839     }
840 
nCreateNativeWindow(SurfaceTexture surface)841     private native void nCreateNativeWindow(SurfaceTexture surface);
nDestroyNativeWindow()842     private native void nDestroyNativeWindow();
843 
nLockCanvas(long nativeWindow, Canvas canvas, Rect dirty)844     private static native boolean nLockCanvas(long nativeWindow, Canvas canvas, Rect dirty);
nUnlockCanvasAndPost(long nativeWindow, Canvas canvas)845     private static native void nUnlockCanvasAndPost(long nativeWindow, Canvas canvas);
846 }
847