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