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