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