/** * 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. * * <p><strong>Do not</strong> invoke this method from a drawing method ({@link * #onDraw(android.graphics.Canvas)} for instance). * * <p>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 */ public Bitmap getBitmap(Bitmap bitmap) { if (bitmap != null && isAvailable()) { AttachInfo info = mAttachInfo; if (info != null && info.mHardwareRenderer != null && info.mHardwareRenderer.isEnabled()) { if (!info.mHardwareRenderer.validate()) { throw new IllegalStateException("Could not acquire hardware rendering context"); } } 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; }
private void destroySurface() { if (mLayer != null) { mSurface.detachFromGLContext(); // SurfaceTexture owns the texture name and detachFromGLContext // should have deleted it mLayer.clearStorage(); 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; } }
private void applyUpdate() { if (mLayer == null) { return; } synchronized (mLock) { if (mUpdateLayer) { mUpdateLayer = false; } else { return; } } mLayer.update(getWidth(), getHeight(), mOpaque); if (mListener != null) { mListener.onSurfaceTextureUpdated(mSurface); } }
private void applyTransformMatrix() { if (mMatrixChanged && mLayer != null) { mLayer.setTransform(mMatrix); mMatrixChanged = false; } }
@Override HardwareLayer getHardwareLayer() { // 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.createHardwareLayer(mOpaque); if (!mUpdateSurface) { // Create a new SurfaceTexture for the layer. mSurface = mAttachInfo.mHardwareRenderer.createSurfaceTexture(mLayer); } mSurface.setDefaultBufferSize(getWidth(), getHeight()); nCreateNativeWindow(mSurface); mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() { @Override public void onFrameAvailable(SurfaceTexture surfaceTexture) { // Per SurfaceTexture's documentation, the callback may be invoked // from an arbitrary thread updateLayer(); if (Looper.myLooper() == Looper.getMainLooper()) { invalidate(); } else { postInvalidate(); } } }; mSurface.setOnFrameAvailableListener(mUpdateListener); 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; mAttachInfo.mHardwareRenderer.setSurfaceTexture(mLayer, mSurface); mSurface.setDefaultBufferSize(getWidth(), getHeight()); } applyUpdate(); applyTransformMatrix(); return mLayer; }