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