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