FileDocCategorySizeDatePackage
TextureView.javaAPI DocAndroid 5.1 API27986Thu Mar 12 22:22:10 GMT 2015android.view

TextureView

public class TextureView extends View

A TextureView can be used to display a content stream. Such a content stream can for instance be a video or an OpenGL scene. The content stream can come from the application's process as well as a remote process.

TextureView can only be used in a hardware accelerated window. When rendered in software, TextureView will draw nothing.

Unlike {@link SurfaceView}, TextureView does not create a separate window but behaves as a regular View. This key difference allows a TextureView to be moved, transformed, animated, etc. For instance, you can make a TextureView semi-translucent by calling myView.setAlpha(0.5f).

Using a TextureView is simple: all you need to do is get its {@link SurfaceTexture}. The {@link SurfaceTexture} can then be used to render content. The following example demonstrates how to render the camera preview into a TextureView:

public class LiveCameraActivity extends Activity implements TextureView.SurfaceTextureListener {
private Camera mCamera;
private TextureView mTextureView;

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

mTextureView = new TextureView(this);
mTextureView.setSurfaceTextureListener(this);

setContentView(mTextureView);
}

public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mCamera = Camera.open();

try {
mCamera.setPreviewTexture(surface);
mCamera.startPreview();
} catch (IOException ioe) {
// Something bad happened
}
}

public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Ignored, Camera does all the work for us
}

public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
mCamera.stopPreview();
mCamera.release();
return true;
}

public void onSurfaceTextureUpdated(SurfaceTexture surface) {
// Invoked every time there's a new Camera preview frame
}
}

A TextureView's SurfaceTexture can be obtained either by invoking {@link #getSurfaceTexture()} or by using a {@link SurfaceTextureListener}. It is important to know that a SurfaceTexture is available only after the TextureView is attached to a window (and {@link #onAttachedToWindow()} has been invoked.) It is therefore highly recommended you use a listener to be notified when the SurfaceTexture becomes available.

It is important to note that only one producer can use the TextureView. For instance, if you use a TextureView to display the camera preview, you cannot use {@link #lockCanvas()} to draw onto the TextureView at the same time.

see
SurfaceView
see
SurfaceTexture

Fields Summary
private static final String
LOG_TAG
private HardwareLayer
mLayer
private android.graphics.SurfaceTexture
mSurface
private SurfaceTextureListener
mListener
private boolean
mHadSurface
private boolean
mOpaque
private final android.graphics.Matrix
mMatrix
private boolean
mMatrixChanged
private final Object[]
mLock
private boolean
mUpdateLayer
private boolean
mUpdateSurface
private android.graphics.Canvas
mCanvas
private int
mSaveCount
private final Object[]
mNativeWindowLock
private long
mNativeWindow
private final SurfaceTexture.OnFrameAvailableListener
mUpdateListener
Constructors Summary
public TextureView(android.content.Context context)
Creates a new TextureView.

param
context The context to associate this view with.


                       
       
        super(context);
        init();
    
public TextureView(android.content.Context context, android.util.AttributeSet attrs)
Creates a new TextureView.

param
context The context to associate this view with.
param
attrs The attributes of the XML tag that is inflating the view.

        super(context, attrs);
        init();
    
public TextureView(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr)
Creates a new TextureView.

param
context The context to associate this view with.
param
attrs The attributes of the XML tag that is inflating the view.
param
defStyleAttr An attribute in the current theme that contains a reference to a style resource that supplies default values for the view. Can be 0 to not look for defaults.

        super(context, attrs, defStyleAttr);
        init();
    
public TextureView(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr, int defStyleRes)
Creates a new TextureView.

param
context The context to associate this view with.
param
attrs The attributes of the XML tag that is inflating the view.
param
defStyleAttr An attribute in the current theme that contains a reference to a style resource that supplies default values for the view. Can be 0 to not look for defaults.
param
defStyleRes A resource identifier of a style resource that supplies default values for the view, used only if defStyleAttr is 0 or can not be found in the theme. Can be 0 to not look for defaults.

        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    
Methods Summary
private voidapplyTransformMatrix()

        if (mMatrixChanged && mLayer != null) {
            mLayer.setTransform(mMatrix);
            mMatrixChanged = false;
        }
    
private voidapplyUpdate()

        if (mLayer == null) {
            return;
        }

        synchronized (mLock) {
            if (mUpdateLayer) {
                mUpdateLayer = false;
            } else {
                return;
            }
        }
        
        mLayer.prepare(getWidth(), getHeight(), mOpaque);
        mLayer.updateSurfaceTexture();

        if (mListener != null) {
            mListener.onSurfaceTextureUpdated(mSurface);
        }
    
public voidbuildLayer()
Calling this method has no effect.

    
protected voiddestroyHardwareResources()

hide

        super.destroyHardwareResources();
        destroySurface();
        invalidateParentCaches();
        invalidate(true);
    
private voiddestroySurface()

        if (mLayer != null) {
            mLayer.detachSurfaceTexture();

            boolean shouldRelease = true;
            if (mListener != null) {
                shouldRelease = mListener.onSurfaceTextureDestroyed(mSurface);
            }

            synchronized (mNativeWindowLock) {
                nDestroyNativeWindow();
            }

            mLayer.destroy();
            if (shouldRelease) mSurface.release();
            mSurface = null;
            mLayer = null;

            mHadSurface = true;
        }
    
public final voiddraw(android.graphics.Canvas canvas)
Subclasses of TextureView cannot do their own rendering with the {@link Canvas} object.

param
canvas The Canvas to which the View is rendered.

        // NOTE: Maintain this carefully (see View.java)
        mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;

        applyUpdate();
        applyTransformMatrix();
    
public android.graphics.BitmapgetBitmap()

Returns a {@link android.graphics.Bitmap} representation of the content of the associated surface texture. If the surface texture is not available, this method returns null.

The bitmap returned by this method uses the {@link Bitmap.Config#ARGB_8888} pixel format and its dimensions are the same as this view's.

Do not invoke this method from a drawing method ({@link #onDraw(android.graphics.Canvas)} for instance).

If an error occurs during the copy, an empty bitmap will be returned.

return
A valid {@link Bitmap.Config#ARGB_8888} bitmap, or null if the surface texture is not available or the width <= 0 or the height <= 0
see
#isAvailable()
see
#getBitmap(android.graphics.Bitmap)
see
#getBitmap(int, int)

        return getBitmap(getWidth(), getHeight());
    
public android.graphics.BitmapgetBitmap(int width, int height)

Returns a {@link android.graphics.Bitmap} representation of the content of the associated surface texture. If the surface texture is not available, this method returns null.

The bitmap returned by this method uses the {@link Bitmap.Config#ARGB_8888} pixel format.

Do not invoke this method from a drawing method ({@link #onDraw(android.graphics.Canvas)} for instance).

If an error occurs during the copy, an empty bitmap will be returned.

param
width The width of the bitmap to create
param
height The height of the bitmap to create
return
A valid {@link Bitmap.Config#ARGB_8888} bitmap, or null if the surface texture is not available or width is <= 0 or height is <= 0
see
#isAvailable()
see
#getBitmap(android.graphics.Bitmap)
see
#getBitmap()

        if (isAvailable() && width > 0 && height > 0) {
            return getBitmap(Bitmap.createBitmap(getResources().getDisplayMetrics(),
                    width, height, Bitmap.Config.ARGB_8888));
        }
        return null;
    
public android.graphics.BitmapgetBitmap(android.graphics.Bitmap bitmap)

Copies the content of this view's surface texture into the specified bitmap. If the surface texture is not available, the copy is not executed. The content of the surface texture will be scaled to fit exactly inside the specified bitmap.

Do not invoke this method from a drawing method ({@link #onDraw(android.graphics.Canvas)} for instance).

If an error occurs, the bitmap is left unchanged.

param
bitmap The bitmap to copy the content of the surface texture into, cannot be null, all configurations are supported
return
The bitmap specified as a parameter
see
#isAvailable()
see
#getBitmap(int, int)
see
#getBitmap()
throws
IllegalStateException if the hardware rendering context cannot be acquired to capture the bitmap

        if (bitmap != null && isAvailable()) {
            applyUpdate();
            applyTransformMatrix();

            // This case can happen if the app invokes setSurfaceTexture() before
            // we are able to create the hardware layer. We can safely initialize
            // the layer here thanks to the validate() call at the beginning of
            // this method
            if (mLayer == null && mUpdateSurface) {
                getHardwareLayer();
            }

            if (mLayer != null) {
                mLayer.copyInto(bitmap);
            }
        }
        return bitmap;
    
HardwareLayergetHardwareLayer()

        // NOTE: Maintain these two lines very carefully (see View.java)
        mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
        mPrivateFlags &= ~PFLAG_DIRTY_MASK;

        if (mLayer == null) {
            if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
                return null;
            }

            mLayer = mAttachInfo.mHardwareRenderer.createTextureLayer();
            if (!mUpdateSurface) {
                // Create a new SurfaceTexture for the layer.
                mSurface = new SurfaceTexture(false);
                mLayer.setSurfaceTexture(mSurface);
            }
            mSurface.setDefaultBufferSize(getWidth(), getHeight());
            nCreateNativeWindow(mSurface);

            mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);

            if (mListener != null && !mUpdateSurface) {
                mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight());
            }
            mLayer.setLayerPaint(mLayerPaint);
        }

        if (mUpdateSurface) {
            // Someone has requested that we use a specific SurfaceTexture, so
            // tell mLayer about it and set the SurfaceTexture to use the
            // current view size.
            mUpdateSurface = false;

            // Since we are updating the layer, force an update to ensure its
            // parameters are correct (width, height, transform, etc.)
            updateLayer();
            mMatrixChanged = true;

            mLayer.setSurfaceTexture(mSurface);
            mSurface.setDefaultBufferSize(getWidth(), getHeight());
        }

        applyUpdate();
        applyTransformMatrix();

        return mLayer;
    
public intgetLayerType()
Always returns {@link #LAYER_TYPE_HARDWARE}.

        return LAYER_TYPE_HARDWARE;
    
public android.graphics.SurfaceTexturegetSurfaceTexture()
Returns the {@link SurfaceTexture} used by this view. This method may return null if the view is not attached to a window or if the surface texture has not been initialized yet.

see
#isAvailable()

        return mSurface;
    
public android.view.TextureView$SurfaceTextureListenergetSurfaceTextureListener()
Returns the {@link SurfaceTextureListener} currently associated with this texture view.

see
#setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener)
see
SurfaceTextureListener

        return mListener;
    
public android.graphics.MatrixgetTransform(android.graphics.Matrix transform)
Returns the transform associated with this texture view.

param
transform The {@link Matrix} in which to copy the current transform. Can be null.
return
The specified matrix if not null or a new {@link Matrix} instance otherwise.
see
#setTransform(android.graphics.Matrix)

        if (transform == null) {
            transform = new Matrix();
        }

        transform.set(mMatrix);

        return transform;
    
booleanhasStaticLayer()

        return true;
    
private voidinit()

        mLayerPaint = new Paint();
    
public booleanisAvailable()
Returns true if the {@link SurfaceTexture} associated with this TextureView is available for rendering. When this method returns true, {@link #getSurfaceTexture()} returns a valid surface texture.

        return mSurface != null;
    
public booleanisOpaque()
{@inheritDoc}

        return mOpaque;
    
public android.graphics.CanvaslockCanvas()

Start editing the pixels in the surface. The returned Canvas can be used to draw into the surface's bitmap. A null is returned if the surface has not been created or otherwise cannot be edited. You will usually need to implement {@link SurfaceTextureListener#onSurfaceTextureAvailable(android.graphics.SurfaceTexture, int, int)} to find out when the Surface is available for use.

The content of the Surface is never preserved between unlockCanvas() and lockCanvas(), for this reason, every pixel within the Surface area must be written. The only exception to this rule is when a dirty rectangle is specified, in which case, non-dirty pixels will be preserved.

This method can only be used if the underlying surface is not already owned by another producer. For instance, if the TextureView is being used to render the camera's preview you cannot invoke this method.

return
A Canvas used to draw into the surface.
see
#lockCanvas(android.graphics.Rect)
see
#unlockCanvasAndPost(android.graphics.Canvas)

        return lockCanvas(null);
    
public android.graphics.CanvaslockCanvas(android.graphics.Rect dirty)
Just like {@link #lockCanvas()} but allows specification of a dirty rectangle. Every pixel within that rectangle must be written; however pixels outside the dirty rectangle will be preserved by the next call to lockCanvas(). This method can return null if the underlying surface texture is not available (see {@link #isAvailable()} or if the surface texture is already connected to an image producer (for instance: the camera, OpenGL, a media player, etc.)

param
dirty Area of the surface that will be modified.
return
A Canvas used to draw into the surface.
see
#lockCanvas()
see
#unlockCanvasAndPost(android.graphics.Canvas)
see
#isAvailable()

        if (!isAvailable()) return null;

        if (mCanvas == null) {
            mCanvas = new Canvas();
        }

        synchronized (mNativeWindowLock) {
            if (!nLockCanvas(mNativeWindow, mCanvas, dirty)) {
                return null;
            }
        }
        mSaveCount = mCanvas.save();

        return mCanvas;
    
private native voidnCreateNativeWindow(android.graphics.SurfaceTexture surface)

private native voidnDestroyNativeWindow()

private static native booleannLockCanvas(long nativeWindow, android.graphics.Canvas canvas, android.graphics.Rect dirty)

private static native voidnUnlockCanvasAndPost(long nativeWindow, android.graphics.Canvas canvas)

protected voidonAttachedToWindow()

        super.onAttachedToWindow();

        if (!isHardwareAccelerated()) {
            Log.w(LOG_TAG, "A TextureView or a subclass can only be "
                    + "used with hardware acceleration enabled.");
        }

        if (mHadSurface) {
            invalidate(true);
            mHadSurface = false;
        }
    
protected voidonDetachedFromWindowInternal()

hide

        destroySurface();
        super.onDetachedFromWindowInternal();
    
protected final voidonDraw(android.graphics.Canvas canvas)
Subclasses of TextureView cannot do their own rendering with the {@link Canvas} object.

param
canvas The Canvas to which the View is rendered.

    
protected voidonSizeChanged(int w, int h, int oldw, int oldh)

        super.onSizeChanged(w, h, oldw, oldh);
        if (mSurface != null) {
            mSurface.setDefaultBufferSize(getWidth(), getHeight());
            updateLayer();
            if (mListener != null) {
                mListener.onSurfaceTextureSizeChanged(mSurface, getWidth(), getHeight());
            }
        }
    
protected voidonVisibilityChanged(View changedView, int visibility)

        super.onVisibilityChanged(changedView, visibility);

        if (mSurface != null) {
            // When the view becomes invisible, stop updating it, it's a waste of CPU
            // To cancel updates, the easiest thing to do is simply to remove the
            // updates listener
            if (visibility == VISIBLE) {
                if (mLayer != null) {
                    mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
                }
                updateLayerAndInvalidate();
            } else {
                mSurface.setOnFrameAvailableListener(null);
            }
        }
    
public voidsetLayerPaint(android.graphics.Paint paint)

        setLayerType(/* ignored */ 0, paint);
    
public voidsetLayerType(int layerType, android.graphics.Paint paint)
The layer type of a TextureView is ignored since a TextureView is always considered to act as a hardware layer. The optional paint supplied to this method will however be taken into account when rendering the content of this TextureView.

param
layerType The ype of layer to use with this view, must be one of {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or {@link #LAYER_TYPE_HARDWARE}
param
paint The paint used to compose the layer. This argument is optional and can be null. It is ignored when the layer type is {@link #LAYER_TYPE_NONE}

        if (paint != mLayerPaint) {
            mLayerPaint = paint == null ? new Paint() : paint;
            invalidate();
        }
    
public voidsetOpaque(boolean opaque)
Indicates whether the content of this TextureView is opaque. The content is assumed to be opaque by default.

param
opaque True if the content of this TextureView is opaque, false otherwise

        if (opaque != mOpaque) {
            mOpaque = opaque;
            if (mLayer != null) {
                updateLayerAndInvalidate();
            }
        }
    
public voidsetSurfaceTexture(android.graphics.SurfaceTexture surfaceTexture)
Set the {@link SurfaceTexture} for this view to use. If a {@link SurfaceTexture} is already being used by this view, it is immediately released and not be usable any more. The {@link SurfaceTextureListener#onSurfaceTextureDestroyed} callback is not called for the previous {@link SurfaceTexture}. Similarly, the {@link SurfaceTextureListener#onSurfaceTextureAvailable} callback is not called for the {@link SurfaceTexture} passed to setSurfaceTexture. The {@link SurfaceTexture} object must be detached from all OpenGL ES contexts prior to calling this method.

param
surfaceTexture The {@link SurfaceTexture} that the view should use.
see
SurfaceTexture#detachFromGLContext()

        if (surfaceTexture == null) {
            throw new NullPointerException("surfaceTexture must not be null");
        }
        if (mSurface != null) {
            mSurface.release();
        }
        mSurface = surfaceTexture;
        mUpdateSurface = true;
        invalidateParentIfNeeded();
    
public voidsetSurfaceTextureListener(android.view.TextureView$SurfaceTextureListener listener)
Sets the {@link SurfaceTextureListener} used to listen to surface texture events.

see
#getSurfaceTextureListener()
see
SurfaceTextureListener

        mListener = listener;
    
public voidsetTransform(android.graphics.Matrix transform)

Sets the transform to associate with this texture view. The specified transform applies to the underlying surface texture and does not affect the size or position of the view itself, only of its content.

Some transforms might prevent the content from drawing all the pixels contained within this view's bounds. In such situations, make sure this texture view is not marked opaque.

param
transform The transform to apply to the content of this view.
see
#getTransform(android.graphics.Matrix)
see
#isOpaque()
see
#setOpaque(boolean)

        mMatrix.set(transform);
        mMatrixChanged = true;
        invalidateParentIfNeeded();
    
public voidunlockCanvasAndPost(android.graphics.Canvas canvas)
Finish editing pixels in the surface. After this call, the surface's current pixels will be shown on the screen, but its content is lost, in particular there is no guarantee that the content of the Surface will remain unchanged when lockCanvas() is called again.

param
canvas The Canvas previously returned by lockCanvas()
see
#lockCanvas()
see
#lockCanvas(android.graphics.Rect)

        if (mCanvas != null && canvas == mCanvas) {
            canvas.restoreToCount(mSaveCount);
            mSaveCount = 0;

            synchronized (mNativeWindowLock) {
                nUnlockCanvasAndPost(mNativeWindow, mCanvas);
            }
        }
    
private voidupdateLayer()

        synchronized (mLock) {
            mUpdateLayer = true;
        }
    
private voidupdateLayerAndInvalidate()

        synchronized (mLock) {
            mUpdateLayer = true;
        }
        invalidate();