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