1 /* 2 * Copyright (C) 2007 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.IntDef; 20 import android.content.res.CompatibilityInfo.Translator; 21 import android.graphics.Canvas; 22 import android.graphics.Matrix; 23 import android.graphics.Rect; 24 import android.graphics.SurfaceTexture; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 import android.util.Log; 28 29 import java.lang.annotation.Retention; 30 import java.lang.annotation.RetentionPolicy; 31 32 import dalvik.system.CloseGuard; 33 34 /** 35 * Handle onto a raw buffer that is being managed by the screen compositor. 36 * 37 * <p>A Surface is generally created by or from a consumer of image buffers (such as a 38 * {@link android.graphics.SurfaceTexture}, {@link android.media.MediaRecorder}, or 39 * {@link android.renderscript.Allocation}), and is handed to some kind of producer (such as 40 * {@link android.opengl.EGL14#eglCreateWindowSurface(android.opengl.EGLDisplay,android.opengl.EGLConfig,java.lang.Object,int[],int) OpenGL}, 41 * {@link android.media.MediaPlayer#setSurface MediaPlayer}, or 42 * {@link android.hardware.camera2.CameraDevice#createCaptureSession CameraDevice}) to draw 43 * into.</p> 44 * 45 * <p><strong>Note:</strong> A Surface acts like a 46 * {@link java.lang.ref.WeakReference weak reference} to the consumer it is associated with. By 47 * itself it will not keep its parent consumer from being reclaimed.</p> 48 */ 49 public class Surface implements Parcelable { 50 private static final String TAG = "Surface"; 51 nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)52 private static native long nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture) 53 throws OutOfResourcesException; nativeCreateFromSurfaceControl(long surfaceControlNativeObject)54 private static native long nativeCreateFromSurfaceControl(long surfaceControlNativeObject); 55 nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty)56 private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty) 57 throws OutOfResourcesException; nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas)58 private static native void nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas); 59 nativeRelease(long nativeObject)60 private static native void nativeRelease(long nativeObject); nativeIsValid(long nativeObject)61 private static native boolean nativeIsValid(long nativeObject); nativeIsConsumerRunningBehind(long nativeObject)62 private static native boolean nativeIsConsumerRunningBehind(long nativeObject); nativeReadFromParcel(long nativeObject, Parcel source)63 private static native long nativeReadFromParcel(long nativeObject, Parcel source); nativeWriteToParcel(long nativeObject, Parcel dest)64 private static native void nativeWriteToParcel(long nativeObject, Parcel dest); 65 nativeAllocateBuffers(long nativeObject)66 private static native void nativeAllocateBuffers(long nativeObject); 67 nativeGetWidth(long nativeObject)68 private static native int nativeGetWidth(long nativeObject); nativeGetHeight(long nativeObject)69 private static native int nativeGetHeight(long nativeObject); 70 nativeGetNextFrameNumber(long nativeObject)71 private static native long nativeGetNextFrameNumber(long nativeObject); nativeSetScalingMode(long nativeObject, int scalingMode)72 private static native int nativeSetScalingMode(long nativeObject, int scalingMode); nativeSetBuffersTransform(long nativeObject, long transform)73 private static native void nativeSetBuffersTransform(long nativeObject, long transform); nativeForceScopedDisconnect(long nativeObject)74 private static native int nativeForceScopedDisconnect(long nativeObject); 75 76 public static final Parcelable.Creator<Surface> CREATOR = 77 new Parcelable.Creator<Surface>() { 78 @Override 79 public Surface createFromParcel(Parcel source) { 80 try { 81 Surface s = new Surface(); 82 s.readFromParcel(source); 83 return s; 84 } catch (Exception e) { 85 Log.e(TAG, "Exception creating surface from parcel", e); 86 return null; 87 } 88 } 89 90 @Override 91 public Surface[] newArray(int size) { 92 return new Surface[size]; 93 } 94 }; 95 96 private final CloseGuard mCloseGuard = CloseGuard.get(); 97 98 // Guarded state. 99 final Object mLock = new Object(); // protects the native state 100 private String mName; 101 long mNativeObject; // package scope only for SurfaceControl access 102 private long mLockedObject; 103 private int mGenerationId; // incremented each time mNativeObject changes 104 private final Canvas mCanvas = new CompatibleCanvas(); 105 106 // A matrix to scale the matrix set by application. This is set to null for 107 // non compatibility mode. 108 private Matrix mCompatibleMatrix; 109 110 private HwuiContext mHwuiContext; 111 112 private boolean mIsSingleBuffered; 113 114 /** @hide */ 115 @Retention(RetentionPolicy.SOURCE) 116 @IntDef({SCALING_MODE_FREEZE, SCALING_MODE_SCALE_TO_WINDOW, 117 SCALING_MODE_SCALE_CROP, SCALING_MODE_NO_SCALE_CROP}) 118 public @interface ScalingMode {} 119 // From system/window.h 120 /** @hide */ 121 public static final int SCALING_MODE_FREEZE = 0; 122 /** @hide */ 123 public static final int SCALING_MODE_SCALE_TO_WINDOW = 1; 124 /** @hide */ 125 public static final int SCALING_MODE_SCALE_CROP = 2; 126 /** @hide */ 127 public static final int SCALING_MODE_NO_SCALE_CROP = 3; 128 129 /** @hide */ 130 @IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270}) 131 @Retention(RetentionPolicy.SOURCE) 132 public @interface Rotation {} 133 134 /** 135 * Rotation constant: 0 degree rotation (natural orientation) 136 */ 137 public static final int ROTATION_0 = 0; 138 139 /** 140 * Rotation constant: 90 degree rotation. 141 */ 142 public static final int ROTATION_90 = 1; 143 144 /** 145 * Rotation constant: 180 degree rotation. 146 */ 147 public static final int ROTATION_180 = 2; 148 149 /** 150 * Rotation constant: 270 degree rotation. 151 */ 152 public static final int ROTATION_270 = 3; 153 154 /** 155 * Create an empty surface, which will later be filled in by readFromParcel(). 156 * @hide 157 */ Surface()158 public Surface() { 159 } 160 161 /** 162 * Create Surface from a {@link SurfaceTexture}. 163 * 164 * Images drawn to the Surface will be made available to the {@link 165 * SurfaceTexture}, which can attach them to an OpenGL ES texture via {@link 166 * SurfaceTexture#updateTexImage}. 167 * 168 * @param surfaceTexture The {@link SurfaceTexture} that is updated by this 169 * Surface. 170 * @throws OutOfResourcesException if the surface could not be created. 171 */ Surface(SurfaceTexture surfaceTexture)172 public Surface(SurfaceTexture surfaceTexture) { 173 if (surfaceTexture == null) { 174 throw new IllegalArgumentException("surfaceTexture must not be null"); 175 } 176 mIsSingleBuffered = surfaceTexture.isSingleBuffered(); 177 synchronized (mLock) { 178 mName = surfaceTexture.toString(); 179 setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture)); 180 } 181 } 182 183 /* called from android_view_Surface_createFromIGraphicBufferProducer() */ Surface(long nativeObject)184 private Surface(long nativeObject) { 185 synchronized (mLock) { 186 setNativeObjectLocked(nativeObject); 187 } 188 } 189 190 @Override finalize()191 protected void finalize() throws Throwable { 192 try { 193 if (mCloseGuard != null) { 194 mCloseGuard.warnIfOpen(); 195 } 196 release(); 197 } finally { 198 super.finalize(); 199 } 200 } 201 202 /** 203 * Release the local reference to the server-side surface. 204 * Always call release() when you're done with a Surface. 205 * This will make the surface invalid. 206 */ release()207 public void release() { 208 synchronized (mLock) { 209 if (mNativeObject != 0) { 210 nativeRelease(mNativeObject); 211 setNativeObjectLocked(0); 212 } 213 if (mHwuiContext != null) { 214 mHwuiContext.destroy(); 215 mHwuiContext = null; 216 } 217 } 218 } 219 220 /** 221 * Free all server-side state associated with this surface and 222 * release this object's reference. This method can only be 223 * called from the process that created the service. 224 * @hide 225 */ destroy()226 public void destroy() { 227 release(); 228 } 229 230 /** 231 * Returns true if this object holds a valid surface. 232 * 233 * @return True if it holds a physical surface, so lockCanvas() will succeed. 234 * Otherwise returns false. 235 */ isValid()236 public boolean isValid() { 237 synchronized (mLock) { 238 if (mNativeObject == 0) return false; 239 return nativeIsValid(mNativeObject); 240 } 241 } 242 243 /** 244 * Gets the generation number of this surface, incremented each time 245 * the native surface contained within this object changes. 246 * 247 * @return The current generation number. 248 * @hide 249 */ getGenerationId()250 public int getGenerationId() { 251 synchronized (mLock) { 252 return mGenerationId; 253 } 254 } 255 256 /** 257 * Returns the next frame number which will be dequeued for rendering. 258 * Intended for use with SurfaceFlinger's deferred transactions API. 259 * 260 * @hide 261 */ getNextFrameNumber()262 public long getNextFrameNumber() { 263 synchronized (mLock) { 264 return nativeGetNextFrameNumber(mNativeObject); 265 } 266 } 267 268 /** 269 * Returns true if the consumer of this Surface is running behind the producer. 270 * 271 * @return True if the consumer is more than one buffer ahead of the producer. 272 * @hide 273 */ isConsumerRunningBehind()274 public boolean isConsumerRunningBehind() { 275 synchronized (mLock) { 276 checkNotReleasedLocked(); 277 return nativeIsConsumerRunningBehind(mNativeObject); 278 } 279 } 280 281 /** 282 * Gets a {@link Canvas} for drawing into this surface. 283 * 284 * After drawing into the provided {@link Canvas}, the caller must 285 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface. 286 * 287 * @param inOutDirty A rectangle that represents the dirty region that the caller wants 288 * to redraw. This function may choose to expand the dirty rectangle if for example 289 * the surface has been resized or if the previous contents of the surface were 290 * not available. The caller must redraw the entire dirty region as represented 291 * by the contents of the inOutDirty rectangle upon return from this function. 292 * The caller may also pass <code>null</code> instead, in the case where the 293 * entire surface should be redrawn. 294 * @return A canvas for drawing into the surface. 295 * 296 * @throws IllegalArgumentException If the inOutDirty rectangle is not valid. 297 * @throws OutOfResourcesException If the canvas cannot be locked. 298 */ lockCanvas(Rect inOutDirty)299 public Canvas lockCanvas(Rect inOutDirty) 300 throws Surface.OutOfResourcesException, IllegalArgumentException { 301 synchronized (mLock) { 302 checkNotReleasedLocked(); 303 if (mLockedObject != 0) { 304 // Ideally, nativeLockCanvas() would throw in this situation and prevent the 305 // double-lock, but that won't happen if mNativeObject was updated. We can't 306 // abandon the old mLockedObject because it might still be in use, so instead 307 // we just refuse to re-lock the Surface. 308 throw new IllegalArgumentException("Surface was already locked"); 309 } 310 mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty); 311 return mCanvas; 312 } 313 } 314 315 /** 316 * Posts the new contents of the {@link Canvas} to the surface and 317 * releases the {@link Canvas}. 318 * 319 * @param canvas The canvas previously obtained from {@link #lockCanvas}. 320 */ unlockCanvasAndPost(Canvas canvas)321 public void unlockCanvasAndPost(Canvas canvas) { 322 synchronized (mLock) { 323 checkNotReleasedLocked(); 324 325 if (mHwuiContext != null) { 326 mHwuiContext.unlockAndPost(canvas); 327 } else { 328 unlockSwCanvasAndPost(canvas); 329 } 330 } 331 } 332 unlockSwCanvasAndPost(Canvas canvas)333 private void unlockSwCanvasAndPost(Canvas canvas) { 334 if (canvas != mCanvas) { 335 throw new IllegalArgumentException("canvas object must be the same instance that " 336 + "was previously returned by lockCanvas"); 337 } 338 if (mNativeObject != mLockedObject) { 339 Log.w(TAG, "WARNING: Surface's mNativeObject (0x" + 340 Long.toHexString(mNativeObject) + ") != mLockedObject (0x" + 341 Long.toHexString(mLockedObject) +")"); 342 } 343 if (mLockedObject == 0) { 344 throw new IllegalStateException("Surface was not locked"); 345 } 346 try { 347 nativeUnlockCanvasAndPost(mLockedObject, canvas); 348 } finally { 349 nativeRelease(mLockedObject); 350 mLockedObject = 0; 351 } 352 } 353 354 /** 355 * Gets a {@link Canvas} for drawing into this surface. 356 * 357 * After drawing into the provided {@link Canvas}, the caller must 358 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface. 359 * 360 * Unlike {@link #lockCanvas(Rect)} this will return a hardware-accelerated 361 * canvas. See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported"> 362 * unsupported drawing operations</a> for a list of what is and isn't 363 * supported in a hardware-accelerated canvas. It is also required to 364 * fully cover the surface every time {@link #lockHardwareCanvas()} is 365 * called as the buffer is not preserved between frames. Partial updates 366 * are not supported. 367 * 368 * @return A canvas for drawing into the surface. 369 * 370 * @throws IllegalStateException If the canvas cannot be locked. 371 */ lockHardwareCanvas()372 public Canvas lockHardwareCanvas() { 373 synchronized (mLock) { 374 checkNotReleasedLocked(); 375 if (mHwuiContext == null) { 376 mHwuiContext = new HwuiContext(); 377 } 378 return mHwuiContext.lockCanvas( 379 nativeGetWidth(mNativeObject), 380 nativeGetHeight(mNativeObject)); 381 } 382 } 383 384 /** 385 * @deprecated This API has been removed and is not supported. Do not use. 386 */ 387 @Deprecated unlockCanvas(Canvas canvas)388 public void unlockCanvas(Canvas canvas) { 389 throw new UnsupportedOperationException(); 390 } 391 392 /** 393 * Sets the translator used to scale canvas's width/height in compatibility 394 * mode. 395 */ setCompatibilityTranslator(Translator translator)396 void setCompatibilityTranslator(Translator translator) { 397 if (translator != null) { 398 float appScale = translator.applicationScale; 399 mCompatibleMatrix = new Matrix(); 400 mCompatibleMatrix.setScale(appScale, appScale); 401 } 402 } 403 404 /** 405 * Copy another surface to this one. This surface now holds a reference 406 * to the same data as the original surface, and is -not- the owner. 407 * This is for use by the window manager when returning a window surface 408 * back from a client, converting it from the representation being managed 409 * by the window manager to the representation the client uses to draw 410 * in to it. 411 * @hide 412 */ copyFrom(SurfaceControl other)413 public void copyFrom(SurfaceControl other) { 414 if (other == null) { 415 throw new IllegalArgumentException("other must not be null"); 416 } 417 418 long surfaceControlPtr = other.mNativeObject; 419 if (surfaceControlPtr == 0) { 420 throw new NullPointerException( 421 "SurfaceControl native object is null. Are you using a released SurfaceControl?"); 422 } 423 long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr); 424 425 synchronized (mLock) { 426 if (mNativeObject != 0) { 427 nativeRelease(mNativeObject); 428 } 429 setNativeObjectLocked(newNativeObject); 430 } 431 } 432 433 /** 434 * This is intended to be used by {@link SurfaceView#updateWindow} only. 435 * @param other access is not thread safe 436 * @hide 437 * @deprecated 438 */ 439 @Deprecated transferFrom(Surface other)440 public void transferFrom(Surface other) { 441 if (other == null) { 442 throw new IllegalArgumentException("other must not be null"); 443 } 444 if (other != this) { 445 final long newPtr; 446 synchronized (other.mLock) { 447 newPtr = other.mNativeObject; 448 other.setNativeObjectLocked(0); 449 } 450 451 synchronized (mLock) { 452 if (mNativeObject != 0) { 453 nativeRelease(mNativeObject); 454 } 455 setNativeObjectLocked(newPtr); 456 } 457 } 458 } 459 460 @Override describeContents()461 public int describeContents() { 462 return 0; 463 } 464 readFromParcel(Parcel source)465 public void readFromParcel(Parcel source) { 466 if (source == null) { 467 throw new IllegalArgumentException("source must not be null"); 468 } 469 470 synchronized (mLock) { 471 // nativeReadFromParcel() will either return mNativeObject, or 472 // create a new native Surface and return it after reducing 473 // the reference count on mNativeObject. Either way, it is 474 // not necessary to call nativeRelease() here. 475 // NOTE: This must be kept synchronized with the native parceling code 476 // in frameworks/native/libs/Surface.cpp 477 mName = source.readString(); 478 mIsSingleBuffered = source.readInt() != 0; 479 setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source)); 480 } 481 } 482 483 @Override writeToParcel(Parcel dest, int flags)484 public void writeToParcel(Parcel dest, int flags) { 485 if (dest == null) { 486 throw new IllegalArgumentException("dest must not be null"); 487 } 488 synchronized (mLock) { 489 // NOTE: This must be kept synchronized with the native parceling code 490 // in frameworks/native/libs/Surface.cpp 491 dest.writeString(mName); 492 dest.writeInt(mIsSingleBuffered ? 1 : 0); 493 nativeWriteToParcel(mNativeObject, dest); 494 } 495 if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) { 496 release(); 497 } 498 } 499 500 @Override toString()501 public String toString() { 502 synchronized (mLock) { 503 return "Surface(name=" + mName + ")/@0x" + 504 Integer.toHexString(System.identityHashCode(this)); 505 } 506 } 507 setNativeObjectLocked(long ptr)508 private void setNativeObjectLocked(long ptr) { 509 if (mNativeObject != ptr) { 510 if (mNativeObject == 0 && ptr != 0) { 511 mCloseGuard.open("release"); 512 } else if (mNativeObject != 0 && ptr == 0) { 513 mCloseGuard.close(); 514 } 515 mNativeObject = ptr; 516 mGenerationId += 1; 517 if (mHwuiContext != null) { 518 mHwuiContext.updateSurface(); 519 } 520 } 521 } 522 checkNotReleasedLocked()523 private void checkNotReleasedLocked() { 524 if (mNativeObject == 0) { 525 throw new IllegalStateException("Surface has already been released."); 526 } 527 } 528 529 /** 530 * Allocate buffers ahead of time to avoid allocation delays during rendering 531 * @hide 532 */ allocateBuffers()533 public void allocateBuffers() { 534 synchronized (mLock) { 535 checkNotReleasedLocked(); 536 nativeAllocateBuffers(mNativeObject); 537 } 538 } 539 540 /** 541 * Set the scaling mode to be used for this surfaces buffers 542 * @hide 543 */ setScalingMode(@calingMode int scalingMode)544 void setScalingMode(@ScalingMode int scalingMode) { 545 synchronized (mLock) { 546 checkNotReleasedLocked(); 547 int err = nativeSetScalingMode(mNativeObject, scalingMode); 548 if (err != 0) { 549 throw new IllegalArgumentException("Invalid scaling mode: " + scalingMode); 550 } 551 } 552 } 553 forceScopedDisconnect()554 void forceScopedDisconnect() { 555 synchronized (mLock) { 556 checkNotReleasedLocked(); 557 int err = nativeForceScopedDisconnect(mNativeObject); 558 if (err != 0) { 559 throw new RuntimeException("Failed to disconnect Surface instance (bad object?)"); 560 } 561 } 562 } 563 564 /** 565 * Returns whether or not this Surface is backed by a single-buffered SurfaceTexture 566 * @hide 567 */ isSingleBuffered()568 public boolean isSingleBuffered() { 569 return mIsSingleBuffered; 570 } 571 572 /** 573 * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or 574 * when a SurfaceTexture could not successfully be allocated. 575 */ 576 @SuppressWarnings("serial") 577 public static class OutOfResourcesException extends RuntimeException { OutOfResourcesException()578 public OutOfResourcesException() { 579 } OutOfResourcesException(String name)580 public OutOfResourcesException(String name) { 581 super(name); 582 } 583 } 584 585 /** 586 * Returns a human readable representation of a rotation. 587 * 588 * @param rotation The rotation. 589 * @return The rotation symbolic name. 590 * 591 * @hide 592 */ rotationToString(int rotation)593 public static String rotationToString(int rotation) { 594 switch (rotation) { 595 case Surface.ROTATION_0: { 596 return "ROTATION_0"; 597 } 598 case Surface.ROTATION_90: { 599 return "ROATATION_90"; 600 } 601 case Surface.ROTATION_180: { 602 return "ROATATION_180"; 603 } 604 case Surface.ROTATION_270: { 605 return "ROATATION_270"; 606 } 607 default: { 608 throw new IllegalArgumentException("Invalid rotation: " + rotation); 609 } 610 } 611 } 612 613 /** 614 * A Canvas class that can handle the compatibility mode. 615 * This does two things differently. 616 * <ul> 617 * <li>Returns the width and height of the target metrics, rather than 618 * native. For example, the canvas returns 320x480 even if an app is running 619 * in WVGA high density. 620 * <li>Scales the matrix in setMatrix by the application scale, except if 621 * the matrix looks like obtained from getMatrix. This is a hack to handle 622 * the case that an application uses getMatrix to keep the original matrix, 623 * set matrix of its own, then set the original matrix back. There is no 624 * perfect solution that works for all cases, and there are a lot of cases 625 * that this model does not work, but we hope this works for many apps. 626 * </ul> 627 */ 628 private final class CompatibleCanvas extends Canvas { 629 // A temp matrix to remember what an application obtained via {@link getMatrix} 630 private Matrix mOrigMatrix = null; 631 632 @Override setMatrix(Matrix matrix)633 public void setMatrix(Matrix matrix) { 634 if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) { 635 // don't scale the matrix if it's not compatibility mode, or 636 // the matrix was obtained from getMatrix. 637 super.setMatrix(matrix); 638 } else { 639 Matrix m = new Matrix(mCompatibleMatrix); 640 m.preConcat(matrix); 641 super.setMatrix(m); 642 } 643 } 644 645 @SuppressWarnings("deprecation") 646 @Override getMatrix(Matrix m)647 public void getMatrix(Matrix m) { 648 super.getMatrix(m); 649 if (mOrigMatrix == null) { 650 mOrigMatrix = new Matrix(); 651 } 652 mOrigMatrix.set(m); 653 } 654 } 655 656 private final class HwuiContext { 657 private final RenderNode mRenderNode; 658 private long mHwuiRenderer; 659 private DisplayListCanvas mCanvas; 660 HwuiContext()661 HwuiContext() { 662 mRenderNode = RenderNode.create("HwuiCanvas", null); 663 mRenderNode.setClipToBounds(false); 664 mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject); 665 } 666 lockCanvas(int width, int height)667 Canvas lockCanvas(int width, int height) { 668 if (mCanvas != null) { 669 throw new IllegalStateException("Surface was already locked!"); 670 } 671 mCanvas = mRenderNode.start(width, height); 672 return mCanvas; 673 } 674 unlockAndPost(Canvas canvas)675 void unlockAndPost(Canvas canvas) { 676 if (canvas != mCanvas) { 677 throw new IllegalArgumentException("canvas object must be the same instance that " 678 + "was previously returned by lockCanvas"); 679 } 680 mRenderNode.end(mCanvas); 681 mCanvas = null; 682 nHwuiDraw(mHwuiRenderer); 683 } 684 updateSurface()685 void updateSurface() { 686 nHwuiSetSurface(mHwuiRenderer, mNativeObject); 687 } 688 destroy()689 void destroy() { 690 if (mHwuiRenderer != 0) { 691 nHwuiDestroy(mHwuiRenderer); 692 mHwuiRenderer = 0; 693 } 694 } 695 } 696 nHwuiCreate(long rootNode, long surface)697 private static native long nHwuiCreate(long rootNode, long surface); nHwuiSetSurface(long renderer, long surface)698 private static native void nHwuiSetSurface(long renderer, long surface); nHwuiDraw(long renderer)699 private static native void nHwuiDraw(long renderer); nHwuiDestroy(long renderer)700 private static native void nHwuiDestroy(long renderer); 701 } 702