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