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