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