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