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 mRenderNode.setIsTextureView(); 210 } 211 212 /** 213 * Creates a new TextureView. 214 * 215 * @param context The context to associate this view with. 216 * @param attrs The attributes of the XML tag that is inflating the view. 217 */ TextureView(@onNull Context context, @Nullable AttributeSet attrs)218 public TextureView(@NonNull Context context, @Nullable AttributeSet attrs) { 219 super(context, attrs); 220 mRenderNode.setIsTextureView(); 221 } 222 223 /** 224 * Creates a new TextureView. 225 * 226 * @param context The context to associate this view with. 227 * @param attrs The attributes of the XML tag that is inflating the view. 228 * @param defStyleAttr An attribute in the current theme that contains a 229 * reference to a style resource that supplies default values for 230 * the view. Can be 0 to not look for defaults. 231 */ TextureView(@onNull Context context, @Nullable AttributeSet attrs, int defStyleAttr)232 public TextureView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 233 super(context, attrs, defStyleAttr); 234 mRenderNode.setIsTextureView(); 235 } 236 237 /** 238 * Creates a new TextureView. 239 * 240 * @param context The context to associate this view with. 241 * @param attrs The attributes of the XML tag that is inflating the view. 242 * @param defStyleAttr An attribute in the current theme that contains a 243 * reference to a style resource that supplies default values for 244 * the view. Can be 0 to not look for defaults. 245 * @param defStyleRes A resource identifier of a style resource that 246 * supplies default values for the view, used only if 247 * defStyleAttr is 0 or can not be found in the theme. Can be 0 248 * to not look for defaults. 249 */ TextureView(@onNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)250 public TextureView(@NonNull Context context, @Nullable AttributeSet attrs, 251 int defStyleAttr, int defStyleRes) { 252 super(context, attrs, defStyleAttr, defStyleRes); 253 mRenderNode.setIsTextureView(); 254 } 255 256 /** 257 * {@inheritDoc} 258 */ 259 @Override isOpaque()260 public boolean isOpaque() { 261 return mOpaque; 262 } 263 264 /** 265 * Indicates whether the content of this TextureView is opaque. The 266 * content is assumed to be opaque by default. 267 * 268 * @param opaque True if the content of this TextureView is opaque, 269 * false otherwise 270 */ setOpaque(boolean opaque)271 public void setOpaque(boolean opaque) { 272 if (opaque != mOpaque) { 273 mOpaque = opaque; 274 if (mLayer != null) { 275 updateLayerAndInvalidate(); 276 } 277 } 278 } 279 280 @Override onAttachedToWindow()281 protected void onAttachedToWindow() { 282 super.onAttachedToWindow(); 283 284 if (!isHardwareAccelerated()) { 285 Log.w(LOG_TAG, "A TextureView or a subclass can only be " 286 + "used with hardware acceleration enabled."); 287 } 288 289 if (mHadSurface) { 290 invalidate(true); 291 mHadSurface = false; 292 } 293 } 294 295 /** @hide */ 296 @Override 297 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onDetachedFromWindowInternal()298 protected void onDetachedFromWindowInternal() { 299 destroyHardwareLayer(); 300 releaseSurfaceTexture(); 301 super.onDetachedFromWindowInternal(); 302 } 303 304 /** 305 * @hide 306 */ 307 @Override 308 @UnsupportedAppUsage destroyHardwareResources()309 protected void destroyHardwareResources() { 310 super.destroyHardwareResources(); 311 destroyHardwareLayer(); 312 } 313 314 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) destroyHardwareLayer()315 private void destroyHardwareLayer() { 316 if (mLayer != null) { 317 mLayer.detachSurfaceTexture(); 318 mLayer.close(); 319 mLayer = null; 320 mMatrixChanged = true; 321 } 322 } 323 releaseSurfaceTexture()324 private void releaseSurfaceTexture() { 325 if (mSurface != null) { 326 boolean shouldRelease = true; 327 328 if (mListener != null) { 329 shouldRelease = mListener.onSurfaceTextureDestroyed(mSurface); 330 } 331 332 synchronized (mNativeWindowLock) { 333 nDestroyNativeWindow(); 334 } 335 336 if (shouldRelease) { 337 mSurface.release(); 338 } 339 mSurface = null; 340 mHadSurface = true; 341 } 342 } 343 344 /** 345 * The layer type of a TextureView is ignored since a TextureView is always 346 * considered to act as a hardware layer. The optional paint supplied to this 347 * method will however be taken into account when rendering the content of 348 * this TextureView. 349 * 350 * @param layerType The type of layer to use with this view, must be one of 351 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 352 * {@link #LAYER_TYPE_HARDWARE} 353 * @param paint The paint used to compose the layer. This argument is optional 354 * and can be null. It is ignored when the layer type is 355 * {@link #LAYER_TYPE_NONE} 356 */ 357 @Override setLayerType(int layerType, @Nullable Paint paint)358 public void setLayerType(int layerType, @Nullable Paint paint) { 359 setLayerPaint(paint); 360 } 361 362 @Override setLayerPaint(@ullable Paint paint)363 public void setLayerPaint(@Nullable Paint paint) { 364 if (paint != mLayerPaint) { 365 mLayerPaint = paint; 366 invalidate(); 367 } 368 } 369 370 /** 371 * Always returns {@link #LAYER_TYPE_HARDWARE}. 372 */ 373 @Override getLayerType()374 public int getLayerType() { 375 return LAYER_TYPE_HARDWARE; 376 } 377 378 /** 379 * Calling this method has no effect. 380 */ 381 @Override buildLayer()382 public void buildLayer() { 383 } 384 385 @Override setForeground(Drawable foreground)386 public void setForeground(Drawable foreground) { 387 if (foreground != null && !sTextureViewIgnoresDrawableSetters) { 388 throw new UnsupportedOperationException( 389 "TextureView doesn't support displaying a foreground drawable"); 390 } 391 } 392 393 @Override setBackgroundDrawable(Drawable background)394 public void setBackgroundDrawable(Drawable background) { 395 if (background != null && !sTextureViewIgnoresDrawableSetters) { 396 throw new UnsupportedOperationException( 397 "TextureView doesn't support displaying a background drawable"); 398 } 399 } 400 401 /** 402 * Subclasses of TextureView cannot do their own rendering 403 * with the {@link Canvas} object. 404 * 405 * @param canvas The Canvas to which the View is rendered. 406 */ 407 @Override draw(Canvas canvas)408 public final void draw(Canvas canvas) { 409 // NOTE: Maintain this carefully (see View#draw) 410 mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 411 412 /* Simplify drawing to guarantee the layer is the only thing drawn - so e.g. no background, 413 scrolling, or fading edges. This guarantees all drawing is in the layer, so drawing 414 properties (alpha, layer paint) affect all of the content of a TextureView. */ 415 416 if (canvas.isHardwareAccelerated()) { 417 RecordingCanvas recordingCanvas = (RecordingCanvas) canvas; 418 419 TextureLayer layer = getTextureLayer(); 420 if (layer != null) { 421 applyUpdate(); 422 applyTransformMatrix(); 423 424 mLayer.setLayerPaint(mLayerPaint); // ensure layer paint is up to date 425 recordingCanvas.drawTextureLayer(layer); 426 } 427 } 428 } 429 430 /** 431 * Subclasses of TextureView cannot do their own rendering 432 * with the {@link Canvas} object. 433 * 434 * @param canvas The Canvas to which the View is rendered. 435 */ 436 @Override onDraw(Canvas canvas)437 protected final void onDraw(Canvas canvas) { 438 } 439 440 @Override onSizeChanged(int w, int h, int oldw, int oldh)441 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 442 super.onSizeChanged(w, h, oldw, oldh); 443 if (mSurface != null) { 444 mSurface.setDefaultBufferSize(getWidth(), getHeight()); 445 updateLayer(); 446 if (mListener != null) { 447 mListener.onSurfaceTextureSizeChanged(mSurface, getWidth(), getHeight()); 448 } 449 } 450 } 451 getTextureLayer()452 TextureLayer getTextureLayer() { 453 if (mLayer == null) { 454 if (mAttachInfo == null || mAttachInfo.mThreadedRenderer == null) { 455 return null; 456 } 457 458 mLayer = mAttachInfo.mThreadedRenderer.createTextureLayer(); 459 boolean createNewSurface = (mSurface == null); 460 if (createNewSurface) { 461 // Create a new SurfaceTexture for the layer. 462 mSurface = new SurfaceTexture(false); 463 nCreateNativeWindow(mSurface); 464 } 465 mLayer.setSurfaceTexture(mSurface); 466 mSurface.setDefaultBufferSize(getWidth(), getHeight()); 467 mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler); 468 469 if (mListener != null && createNewSurface) { 470 mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight()); 471 } 472 mLayer.setLayerPaint(mLayerPaint); 473 } 474 475 if (mUpdateSurface) { 476 // Someone has requested that we use a specific SurfaceTexture, so 477 // tell mLayer about it and set the SurfaceTexture to use the 478 // current view size. 479 mUpdateSurface = false; 480 481 // Since we are updating the layer, force an update to ensure its 482 // parameters are correct (width, height, transform, etc.) 483 updateLayer(); 484 mMatrixChanged = true; 485 486 mLayer.setSurfaceTexture(mSurface); 487 mSurface.setDefaultBufferSize(getWidth(), getHeight()); 488 } 489 490 return mLayer; 491 } 492 493 @Override onVisibilityChanged(View changedView, int visibility)494 protected void onVisibilityChanged(View changedView, int visibility) { 495 super.onVisibilityChanged(changedView, visibility); 496 497 if (mSurface != null) { 498 // When the view becomes invisible, stop updating it, it's a waste of CPU 499 // To cancel updates, the easiest thing to do is simply to remove the 500 // updates listener 501 if (visibility == VISIBLE) { 502 if (mLayer != null) { 503 mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler); 504 } 505 updateLayerAndInvalidate(); 506 } else { 507 mSurface.setOnFrameAvailableListener(null); 508 } 509 } 510 } 511 updateLayer()512 private void updateLayer() { 513 synchronized (mLock) { 514 mUpdateLayer = true; 515 } 516 } 517 updateLayerAndInvalidate()518 private void updateLayerAndInvalidate() { 519 synchronized (mLock) { 520 mUpdateLayer = true; 521 } 522 invalidate(); 523 } 524 applyUpdate()525 private void applyUpdate() { 526 if (mLayer == null) { 527 return; 528 } 529 530 synchronized (mLock) { 531 if (mUpdateLayer) { 532 mUpdateLayer = false; 533 } else { 534 return; 535 } 536 } 537 538 mLayer.prepare(getWidth(), getHeight(), mOpaque); 539 mLayer.updateSurfaceTexture(); 540 541 if (mListener != null) { 542 mListener.onSurfaceTextureUpdated(mSurface); 543 } 544 } 545 546 /** 547 * <p>Sets the transform to associate with this texture view. 548 * The specified transform applies to the underlying surface 549 * texture and does not affect the size or position of the view 550 * itself, only of its content.</p> 551 * 552 * <p>Some transforms might prevent the content from drawing 553 * all the pixels contained within this view's bounds. In such 554 * situations, make sure this texture view is not marked opaque.</p> 555 * 556 * @param transform The transform to apply to the content of 557 * this view. If null the transform will be set to identity. 558 * 559 * @see #getTransform(android.graphics.Matrix) 560 * @see #isOpaque() 561 * @see #setOpaque(boolean) 562 */ setTransform(@ullable Matrix transform)563 public void setTransform(@Nullable Matrix transform) { 564 mMatrix.set(transform); 565 mMatrixChanged = true; 566 invalidateParentIfNeeded(); 567 } 568 569 /** 570 * Returns the transform associated with this texture view. 571 * 572 * @param transform The {@link Matrix} in which to copy the current 573 * transform. Can be null. 574 * 575 * @return The specified matrix if not null or a new {@link Matrix} 576 * instance otherwise. 577 * 578 * @see #setTransform(android.graphics.Matrix) 579 */ getTransform(@ullable Matrix transform)580 public @NonNull Matrix getTransform(@Nullable Matrix transform) { 581 if (transform == null) { 582 transform = new Matrix(); 583 } 584 585 transform.set(mMatrix); 586 587 return transform; 588 } 589 applyTransformMatrix()590 private void applyTransformMatrix() { 591 if (mMatrixChanged && mLayer != null) { 592 mLayer.setTransform(mMatrix); 593 mMatrixChanged = false; 594 } 595 } 596 597 /** 598 * <p>Returns a {@link android.graphics.Bitmap} representation of the content 599 * of the associated surface texture. If the surface texture is not available, 600 * this method returns null.</p> 601 * 602 * <p>The bitmap returned by this method uses the {@link Bitmap.Config#ARGB_8888} 603 * pixel format and its dimensions are the same as this view's.</p> 604 * 605 * <p><strong>Do not</strong> invoke this method from a drawing method 606 * ({@link #onDraw(android.graphics.Canvas)} for instance).</p> 607 * 608 * <p>If an error occurs during the copy, an empty bitmap will be returned.</p> 609 * 610 * @return A valid {@link Bitmap.Config#ARGB_8888} bitmap, or null if the surface 611 * texture is not available or the width <= 0 or the height <= 0 612 * 613 * @see #isAvailable() 614 * @see #getBitmap(android.graphics.Bitmap) 615 * @see #getBitmap(int, int) 616 */ getBitmap()617 public @Nullable Bitmap getBitmap() { 618 return getBitmap(getWidth(), getHeight()); 619 } 620 621 /** 622 * <p>Returns a {@link android.graphics.Bitmap} representation of the content 623 * of the associated surface texture. If the surface texture is not available, 624 * this method returns null.</p> 625 * 626 * <p>The bitmap returned by this method uses the {@link Bitmap.Config#ARGB_8888} 627 * pixel format.</p> 628 * 629 * <p><strong>Do not</strong> invoke this method from a drawing method 630 * ({@link #onDraw(android.graphics.Canvas)} for instance).</p> 631 * 632 * <p>If an error occurs during the copy, an empty bitmap will be returned.</p> 633 * 634 * @param width The width of the bitmap to create 635 * @param height The height of the bitmap to create 636 * 637 * @return A valid {@link Bitmap.Config#ARGB_8888} bitmap, or null if the surface 638 * texture is not available or width is <= 0 or height is <= 0 639 * 640 * @see #isAvailable() 641 * @see #getBitmap(android.graphics.Bitmap) 642 * @see #getBitmap() 643 */ getBitmap(int width, int height)644 public @Nullable Bitmap getBitmap(int width, int height) { 645 if (isAvailable() && width > 0 && height > 0) { 646 return getBitmap(Bitmap.createBitmap(getResources().getDisplayMetrics(), 647 width, height, Bitmap.Config.ARGB_8888)); 648 } 649 return null; 650 } 651 652 /** 653 * <p>Copies the content of this view's surface texture into the specified 654 * bitmap. If the surface texture is not available, the copy is not executed. 655 * The content of the surface texture will be scaled to fit exactly inside 656 * the specified bitmap.</p> 657 * 658 * <p><strong>Do not</strong> invoke this method from a drawing method 659 * ({@link #onDraw(android.graphics.Canvas)} for instance).</p> 660 * 661 * <p>If an error occurs, the bitmap is left unchanged.</p> 662 * 663 * @param bitmap The bitmap to copy the content of the surface texture into, 664 * cannot be null, all configurations are supported 665 * 666 * @return The bitmap specified as a parameter 667 * 668 * @see #isAvailable() 669 * @see #getBitmap(int, int) 670 * @see #getBitmap() 671 * 672 * @throws IllegalStateException if the hardware rendering context cannot be 673 * acquired to capture the bitmap 674 */ getBitmap(@onNull Bitmap bitmap)675 public @NonNull Bitmap getBitmap(@NonNull Bitmap bitmap) { 676 if (bitmap != null && isAvailable()) { 677 applyUpdate(); 678 applyTransformMatrix(); 679 680 // This case can happen if the app invokes setSurfaceTexture() before 681 // we are able to create the hardware layer. We can safely initialize 682 // the layer here thanks to the validate() call at the beginning of 683 // this method 684 if (mLayer == null && mUpdateSurface) { 685 getTextureLayer(); 686 } 687 688 if (mLayer != null) { 689 mLayer.copyInto(bitmap); 690 } 691 } 692 return bitmap; 693 } 694 695 /** 696 * Returns true if the {@link SurfaceTexture} associated with this 697 * TextureView is available for rendering. When this method returns 698 * true, {@link #getSurfaceTexture()} returns a valid surface texture. 699 */ isAvailable()700 public boolean isAvailable() { 701 return mSurface != null; 702 } 703 704 /** 705 * <p>Start editing the pixels in the surface. The returned Canvas can be used 706 * to draw into the surface's bitmap. A null is returned if the surface has 707 * not been created or otherwise cannot be edited. You will usually need 708 * to implement 709 * {@link SurfaceTextureListener#onSurfaceTextureAvailable(android.graphics.SurfaceTexture, int, int)} 710 * to find out when the Surface is available for use.</p> 711 * 712 * <p>The content of the Surface is never preserved between unlockCanvas() 713 * and lockCanvas(), for this reason, every pixel within the Surface area 714 * must be written. The only exception to this rule is when a dirty 715 * rectangle is specified, in which case, non-dirty pixels will be 716 * preserved.</p> 717 * 718 * <p>This method can only be used if the underlying surface is not already 719 * owned by another producer. For instance, if the TextureView is being used 720 * to render the camera's preview you cannot invoke this method.</p> 721 * 722 * @return A Canvas used to draw into the surface, or null if the surface cannot be locked for 723 * drawing (see {@link #isAvailable()}). 724 * 725 * @see #lockCanvas(android.graphics.Rect) 726 * @see #unlockCanvasAndPost(android.graphics.Canvas) 727 */ lockCanvas()728 public @Nullable Canvas lockCanvas() { 729 return lockCanvas(null); 730 } 731 732 /** 733 * Just like {@link #lockCanvas()} but allows specification of a dirty 734 * rectangle. Every pixel within that rectangle must be written; however 735 * pixels outside the dirty rectangle will be preserved by the next call 736 * to lockCanvas(). 737 * 738 * This method can return null if the underlying surface texture is not 739 * available (see {@link #isAvailable()} or if the surface texture is 740 * already connected to an image producer (for instance: the camera, 741 * OpenGL, a media player, etc.) 742 * 743 * @param dirty Area of the surface that will be modified. If null the area of the entire 744 * surface is used. 745 746 * @return A Canvas used to draw into the surface, or null if the surface cannot be locked for 747 * drawing (see {@link #isAvailable()}). 748 * 749 * @see #lockCanvas() 750 * @see #unlockCanvasAndPost(android.graphics.Canvas) 751 * @see #isAvailable() 752 */ lockCanvas(@ullable Rect dirty)753 public @Nullable Canvas lockCanvas(@Nullable Rect dirty) { 754 if (!isAvailable()) return null; 755 756 if (mCanvas == null) { 757 mCanvas = new Canvas(); 758 } 759 760 synchronized (mNativeWindowLock) { 761 if (!nLockCanvas(mNativeWindow, mCanvas, dirty)) { 762 return null; 763 } 764 } 765 mSaveCount = mCanvas.save(); 766 767 return mCanvas; 768 } 769 770 /** 771 * Finish editing pixels in the surface. After this call, the surface's 772 * current pixels will be shown on the screen, but its content is lost, 773 * in particular there is no guarantee that the content of the Surface 774 * will remain unchanged when lockCanvas() is called again. 775 * 776 * @param canvas The Canvas previously returned by lockCanvas() 777 * 778 * @see #lockCanvas() 779 * @see #lockCanvas(android.graphics.Rect) 780 */ unlockCanvasAndPost(@onNull Canvas canvas)781 public void unlockCanvasAndPost(@NonNull Canvas canvas) { 782 if (mCanvas != null && canvas == mCanvas) { 783 canvas.restoreToCount(mSaveCount); 784 mSaveCount = 0; 785 786 synchronized (mNativeWindowLock) { 787 nUnlockCanvasAndPost(mNativeWindow, mCanvas); 788 } 789 } 790 } 791 792 /** 793 * Returns the {@link SurfaceTexture} used by this view. This method 794 * may return null if the view is not attached to a window or if the surface 795 * texture has not been initialized yet. 796 * 797 * @see #isAvailable() 798 */ getSurfaceTexture()799 public @Nullable SurfaceTexture getSurfaceTexture() { 800 return mSurface; 801 } 802 803 /** 804 * Set the {@link SurfaceTexture} for this view to use. If a {@link 805 * SurfaceTexture} is already being used by this view, it is immediately 806 * released and not usable any more. The {@link 807 * SurfaceTextureListener#onSurfaceTextureDestroyed} callback is <b>not</b> 808 * called for the previous {@link SurfaceTexture}. Similarly, the {@link 809 * SurfaceTextureListener#onSurfaceTextureAvailable} callback is <b>not</b> 810 * called for the {@link SurfaceTexture} passed to setSurfaceTexture. 811 * 812 * The {@link SurfaceTexture} object must be detached from all OpenGL ES 813 * contexts prior to calling this method. 814 * 815 * @param surfaceTexture The {@link SurfaceTexture} that the view should use. 816 * @see SurfaceTexture#detachFromGLContext() 817 */ setSurfaceTexture(@onNull SurfaceTexture surfaceTexture)818 public void setSurfaceTexture(@NonNull SurfaceTexture surfaceTexture) { 819 if (surfaceTexture == null) { 820 throw new NullPointerException("surfaceTexture must not be null"); 821 } 822 if (surfaceTexture == mSurface) { 823 throw new IllegalArgumentException("Trying to setSurfaceTexture to " + 824 "the same SurfaceTexture that's already set."); 825 } 826 if (surfaceTexture.isReleased()) { 827 throw new IllegalArgumentException("Cannot setSurfaceTexture to a " + 828 "released SurfaceTexture"); 829 } 830 if (mSurface != null) { 831 nDestroyNativeWindow(); 832 mSurface.release(); 833 } 834 mSurface = surfaceTexture; 835 nCreateNativeWindow(mSurface); 836 837 /* 838 * If the view is visible and we already made a layer, update the 839 * listener in the new surface to use the existing listener in the view. 840 * Otherwise this will be called when the view becomes visible or the 841 * layer is created 842 */ 843 if (((mViewFlags & VISIBILITY_MASK) == VISIBLE) && mLayer != null) { 844 mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler); 845 } 846 mUpdateSurface = true; 847 invalidateParentIfNeeded(); 848 } 849 850 /** 851 * Returns the {@link SurfaceTextureListener} currently associated with this 852 * texture view. 853 * 854 * @see #setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener) 855 * @see SurfaceTextureListener 856 */ getSurfaceTextureListener()857 public @Nullable SurfaceTextureListener getSurfaceTextureListener() { 858 return mListener; 859 } 860 861 /** 862 * Sets the {@link SurfaceTextureListener} used to listen to surface 863 * texture events. 864 * 865 * @see #getSurfaceTextureListener() 866 * @see SurfaceTextureListener 867 */ setSurfaceTextureListener(@ullable SurfaceTextureListener listener)868 public void setSurfaceTextureListener(@Nullable SurfaceTextureListener listener) { 869 mListener = listener; 870 } 871 872 @UnsupportedAppUsage 873 private final SurfaceTexture.OnFrameAvailableListener mUpdateListener = 874 surfaceTexture -> { 875 updateLayer(); 876 invalidate(); 877 }; 878 879 /** 880 * This listener can be used to be notified when the surface texture 881 * associated with this texture view is available. 882 */ 883 public interface SurfaceTextureListener { 884 /** 885 * Invoked when a {@link TextureView}'s SurfaceTexture is ready for use. 886 * 887 * @param surface The surface returned by 888 * {@link android.view.TextureView#getSurfaceTexture()} 889 * @param width The width of the surface 890 * @param height The height of the surface 891 */ onSurfaceTextureAvailable(@onNull SurfaceTexture surface, int width, int height)892 void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height); 893 894 /** 895 * Invoked when the {@link SurfaceTexture}'s buffers size changed. 896 * 897 * @param surface The surface returned by 898 * {@link android.view.TextureView#getSurfaceTexture()} 899 * @param width The new width of the surface 900 * @param height The new height of the surface 901 */ onSurfaceTextureSizeChanged(@onNull SurfaceTexture surface, int width, int height)902 void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height); 903 904 /** 905 * Invoked when the specified {@link SurfaceTexture} is about to be destroyed. 906 * If returns true, no rendering should happen inside the surface texture after this method 907 * is invoked. If returns false, the client needs to call {@link SurfaceTexture#release()}. 908 * Most applications should return true. 909 * 910 * @param surface The surface about to be destroyed 911 */ onSurfaceTextureDestroyed(@onNull SurfaceTexture surface)912 boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface); 913 914 /** 915 * Invoked when the specified {@link SurfaceTexture} is updated through 916 * {@link SurfaceTexture#updateTexImage()}. 917 * 918 * @param surface The surface just updated 919 */ onSurfaceTextureUpdated(@onNull SurfaceTexture surface)920 void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface); 921 } 922 923 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) nCreateNativeWindow(SurfaceTexture surface)924 private native void nCreateNativeWindow(SurfaceTexture surface); 925 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) nDestroyNativeWindow()926 private native void nDestroyNativeWindow(); 927 nLockCanvas(long nativeWindow, Canvas canvas, Rect dirty)928 private static native boolean nLockCanvas(long nativeWindow, Canvas canvas, Rect dirty); nUnlockCanvasAndPost(long nativeWindow, Canvas canvas)929 private static native void nUnlockCanvasAndPost(long nativeWindow, Canvas canvas); 930 } 931