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