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