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