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