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