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