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