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