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