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 static android.system.OsConstants.EINVAL; 20 21 import android.annotation.FloatRange; 22 import android.annotation.IntDef; 23 import android.annotation.NonNull; 24 import android.compat.annotation.UnsupportedAppUsage; 25 import android.content.pm.ActivityInfo; 26 import android.content.res.CompatibilityInfo.Translator; 27 import android.graphics.BLASTBufferQueue; 28 import android.graphics.Canvas; 29 import android.graphics.ColorSpace; 30 import android.graphics.HardwareRenderer; 31 import android.graphics.Matrix; 32 import android.graphics.Point; 33 import android.graphics.RecordingCanvas; 34 import android.graphics.Rect; 35 import android.graphics.RenderNode; 36 import android.graphics.SurfaceTexture; 37 import android.hardware.HardwareBuffer; 38 import android.os.Build; 39 import android.os.Parcel; 40 import android.os.Parcelable; 41 import android.util.Log; 42 43 import dalvik.system.CloseGuard; 44 45 import java.lang.annotation.Retention; 46 import java.lang.annotation.RetentionPolicy; 47 48 /** 49 * Handle onto a raw buffer that is being managed by the screen compositor. 50 * 51 * <p>A Surface is generally created by or from a consumer of image buffers (such as a 52 * {@link android.graphics.SurfaceTexture}, {@link android.media.MediaRecorder}, or 53 * {@link android.renderscript.Allocation}), and is handed to some kind of producer (such as 54 * {@link android.opengl.EGL14#eglCreateWindowSurface(android.opengl.EGLDisplay,android.opengl.EGLConfig,java.lang.Object,int[],int) OpenGL}, 55 * {@link android.media.MediaPlayer#setSurface MediaPlayer}, or 56 * {@link android.hardware.camera2.CameraDevice#createCaptureSession CameraDevice}) to draw 57 * into.</p> 58 * 59 * <p><strong>Note:</strong> A Surface acts like a 60 * {@link java.lang.ref.WeakReference weak reference} to the consumer it is associated with. By 61 * itself it will not keep its parent consumer from being reclaimed.</p> 62 */ 63 public class Surface implements Parcelable { 64 private static final String TAG = "Surface"; 65 nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)66 private static native long nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture) 67 throws OutOfResourcesException; 68 nativeCreateFromSurfaceControl(long surfaceControlNativeObject)69 private static native long nativeCreateFromSurfaceControl(long surfaceControlNativeObject); nativeGetFromSurfaceControl(long surfaceObject, long surfaceControlNativeObject)70 private static native long nativeGetFromSurfaceControl(long surfaceObject, 71 long surfaceControlNativeObject); nativeGetFromBlastBufferQueue(long surfaceObject, long blastBufferQueueNativeObject)72 private static native long nativeGetFromBlastBufferQueue(long surfaceObject, 73 long blastBufferQueueNativeObject); 74 nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty)75 private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty) 76 throws OutOfResourcesException; nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas)77 private static native void nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas); 78 79 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) nativeRelease(long nativeObject)80 private static native void nativeRelease(long nativeObject); nativeIsValid(long nativeObject)81 private static native boolean nativeIsValid(long nativeObject); nativeIsConsumerRunningBehind(long nativeObject)82 private static native boolean nativeIsConsumerRunningBehind(long nativeObject); nativeReadFromParcel(long nativeObject, Parcel source)83 private static native long nativeReadFromParcel(long nativeObject, Parcel source); nativeWriteToParcel(long nativeObject, Parcel dest)84 private static native void nativeWriteToParcel(long nativeObject, Parcel dest); 85 nativeAllocateBuffers(long nativeObject)86 private static native void nativeAllocateBuffers(long nativeObject); 87 nativeGetWidth(long nativeObject)88 private static native int nativeGetWidth(long nativeObject); nativeGetHeight(long nativeObject)89 private static native int nativeGetHeight(long nativeObject); 90 nativeGetNextFrameNumber(long nativeObject)91 private static native long nativeGetNextFrameNumber(long nativeObject); nativeSetScalingMode(long nativeObject, int scalingMode)92 private static native int nativeSetScalingMode(long nativeObject, int scalingMode); nativeForceScopedDisconnect(long nativeObject)93 private static native int nativeForceScopedDisconnect(long nativeObject); nativeAttachAndQueueBufferWithColorSpace(long nativeObject, HardwareBuffer buffer, int colorSpaceId)94 private static native int nativeAttachAndQueueBufferWithColorSpace(long nativeObject, 95 HardwareBuffer buffer, int colorSpaceId); 96 nativeSetSharedBufferModeEnabled(long nativeObject, boolean enabled)97 private static native int nativeSetSharedBufferModeEnabled(long nativeObject, boolean enabled); nativeSetAutoRefreshEnabled(long nativeObject, boolean enabled)98 private static native int nativeSetAutoRefreshEnabled(long nativeObject, boolean enabled); 99 nativeSetFrameRate( long nativeObject, float frameRate, int compatibility, int changeFrameRateStrategy)100 private static native int nativeSetFrameRate( 101 long nativeObject, float frameRate, int compatibility, int changeFrameRateStrategy); nativeDestroy(long nativeObject)102 private static native void nativeDestroy(long nativeObject); 103 104 public static final @android.annotation.NonNull Parcelable.Creator<Surface> CREATOR = 105 new Parcelable.Creator<Surface>() { 106 @Override 107 public Surface createFromParcel(Parcel source) { 108 try { 109 Surface s = new Surface(); 110 s.readFromParcel(source); 111 return s; 112 } catch (Exception e) { 113 Log.e(TAG, "Exception creating surface from parcel", e); 114 return null; 115 } 116 } 117 118 @Override 119 public Surface[] newArray(int size) { 120 return new Surface[size]; 121 } 122 }; 123 124 private final CloseGuard mCloseGuard = CloseGuard.get(); 125 126 // Guarded state. 127 @UnsupportedAppUsage 128 final Object mLock = new Object(); // protects the native state 129 @UnsupportedAppUsage 130 private String mName; 131 @UnsupportedAppUsage 132 long mNativeObject; // package scope only for SurfaceControl access 133 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 134 private long mLockedObject; 135 private int mGenerationId; // incremented each time mNativeObject changes 136 private final Canvas mCanvas = new CompatibleCanvas(); 137 138 // A matrix to scale the matrix set by application. This is set to null for 139 // non compatibility mode. 140 private Matrix mCompatibleMatrix; 141 142 private HwuiContext mHwuiContext; 143 144 private boolean mIsSingleBuffered; 145 private boolean mIsSharedBufferModeEnabled; 146 private boolean mIsAutoRefreshEnabled; 147 148 /** @hide */ 149 @Retention(RetentionPolicy.SOURCE) 150 @IntDef(prefix = { "SCALING_MODE_" }, value = { 151 SCALING_MODE_FREEZE, 152 SCALING_MODE_SCALE_TO_WINDOW, 153 SCALING_MODE_SCALE_CROP, 154 SCALING_MODE_NO_SCALE_CROP 155 }) 156 public @interface ScalingMode {} 157 // From system/window.h 158 /** @hide */ 159 public static final int SCALING_MODE_FREEZE = 0; 160 /** @hide */ 161 public static final int SCALING_MODE_SCALE_TO_WINDOW = 1; 162 /** @hide */ 163 public static final int SCALING_MODE_SCALE_CROP = 2; 164 /** @hide */ 165 public static final int SCALING_MODE_NO_SCALE_CROP = 3; 166 167 /** @hide */ 168 @IntDef(prefix = { "ROTATION_" }, value = { 169 ROTATION_0, 170 ROTATION_90, 171 ROTATION_180, 172 ROTATION_270 173 }) 174 @Retention(RetentionPolicy.SOURCE) 175 public @interface Rotation {} 176 177 /** 178 * Rotation constant: 0 degree rotation (natural orientation) 179 */ 180 public static final int ROTATION_0 = 0; 181 182 /** 183 * Rotation constant: 90 degree rotation. 184 */ 185 public static final int ROTATION_90 = 1; 186 187 /** 188 * Rotation constant: 180 degree rotation. 189 */ 190 public static final int ROTATION_180 = 2; 191 192 /** 193 * Rotation constant: 270 degree rotation. 194 */ 195 public static final int ROTATION_270 = 3; 196 197 /** @hide */ 198 @Retention(RetentionPolicy.SOURCE) 199 @IntDef(prefix = {"FRAME_RATE_COMPATIBILITY_"}, 200 value = {FRAME_RATE_COMPATIBILITY_DEFAULT, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE}) 201 public @interface FrameRateCompatibility {} 202 203 // From native_window.h. Keep these in sync. 204 /** 205 * There are no inherent restrictions on the frame rate of this surface. When the 206 * system selects a frame rate other than what the app requested, the app will be able 207 * to run at the system frame rate without requiring pull down. This value should be 208 * used when displaying game content, UIs, and anything that isn't video. 209 */ 210 public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0; 211 212 /** 213 * This surface is being used to display content with an inherently fixed frame rate, 214 * e.g. a video that has a specific frame rate. When the system selects a frame rate 215 * other than what the app requested, the app will need to do pull down or use some 216 * other technique to adapt to the system's frame rate. The user experience is likely 217 * to be worse (e.g. more frame stuttering) than it would be if the system had chosen 218 * the app's requested frame rate. This value should be used for video content. 219 */ 220 public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; 221 222 /** 223 * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display 224 * to operate at the exact frame rate. 225 * 226 * This is used internally by the platform and should not be used by apps. 227 * @hide 228 */ 229 public static final int FRAME_RATE_COMPATIBILITY_EXACT = 100; 230 231 232 /** @hide */ 233 @Retention(RetentionPolicy.SOURCE) 234 @IntDef(prefix = {"CHANGE_FRAME_RATE_"}, 235 value = {CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, CHANGE_FRAME_RATE_ALWAYS}) 236 public @interface ChangeFrameRateStrategy {} 237 238 /** 239 * Change the frame rate only if the transition is going to be seamless. 240 */ 241 public static final int CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS = 0; 242 243 /** 244 * Change the frame rate even if the transition is going to be non-seamless, i.e. with visual 245 * interruptions for the user. Non-seamless switches might be used when the benefit of matching 246 * the content's frame rate outweighs the cost of the transition, for example when 247 * displaying long-running video content. 248 */ 249 public static final int CHANGE_FRAME_RATE_ALWAYS = 1; 250 251 /** 252 * Create an empty surface, which will later be filled in by readFromParcel(). 253 * @hide 254 */ 255 @UnsupportedAppUsage Surface()256 public Surface() { 257 } 258 259 /** 260 * Create a Surface associated with a given {@link SurfaceControl}. Buffers submitted to this 261 * surface will be displayed by the system compositor according to the parameters 262 * specified by the control. Multiple surfaces may be constructed from one SurfaceControl, 263 * but only one can be connected (e.g. have an active EGL context) at a time. 264 * 265 * @param from The SurfaceControl to associate this Surface with 266 */ Surface(@onNull SurfaceControl from)267 public Surface(@NonNull SurfaceControl from) { 268 copyFrom(from); 269 } 270 271 /** 272 * Create Surface from a {@link SurfaceTexture}. 273 * 274 * Images drawn to the Surface will be made available to the {@link 275 * SurfaceTexture}, which can attach them to an OpenGL ES texture via {@link 276 * SurfaceTexture#updateTexImage}. 277 * 278 * Please note that holding onto the Surface created here is not enough to 279 * keep the provided SurfaceTexture from being reclaimed. In that sense, 280 * the Surface will act like a 281 * {@link java.lang.ref.WeakReference weak reference} to the SurfaceTexture. 282 * 283 * @param surfaceTexture The {@link SurfaceTexture} that is updated by this 284 * Surface. 285 * @throws OutOfResourcesException if the surface could not be created. 286 */ Surface(SurfaceTexture surfaceTexture)287 public Surface(SurfaceTexture surfaceTexture) { 288 if (surfaceTexture == null) { 289 throw new IllegalArgumentException("surfaceTexture must not be null"); 290 } 291 mIsSingleBuffered = surfaceTexture.isSingleBuffered(); 292 synchronized (mLock) { 293 mName = surfaceTexture.toString(); 294 setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture)); 295 } 296 } 297 298 /* called from android_view_Surface_createFromIGraphicBufferProducer() */ 299 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) Surface(long nativeObject)300 private Surface(long nativeObject) { 301 synchronized (mLock) { 302 setNativeObjectLocked(nativeObject); 303 } 304 } 305 306 @Override finalize()307 protected void finalize() throws Throwable { 308 try { 309 if (mCloseGuard != null) { 310 mCloseGuard.warnIfOpen(); 311 } 312 release(); 313 } finally { 314 super.finalize(); 315 } 316 } 317 318 /** 319 * Release the local reference to the server-side surface. 320 * Always call release() when you're done with a Surface. 321 * This will make the surface invalid. 322 */ release()323 public void release() { 324 synchronized (mLock) { 325 if (mHwuiContext != null) { 326 mHwuiContext.destroy(); 327 mHwuiContext = null; 328 } 329 if (mNativeObject != 0) { 330 nativeRelease(mNativeObject); 331 setNativeObjectLocked(0); 332 } 333 } 334 } 335 336 /** 337 * Free all server-side state associated with this surface and 338 * release this object's reference. This method can only be 339 * called from the process that created the service. 340 * @hide 341 */ 342 @UnsupportedAppUsage destroy()343 public void destroy() { 344 synchronized (mLock) { 345 if (mNativeObject != 0) { 346 nativeDestroy(mNativeObject); 347 } 348 release(); 349 } 350 } 351 352 /** 353 * Destroys the HwuiContext without completely 354 * releasing the Surface. 355 * @hide 356 */ hwuiDestroy()357 public void hwuiDestroy() { 358 if (mHwuiContext != null) { 359 mHwuiContext.destroy(); 360 mHwuiContext = null; 361 } 362 } 363 364 /** 365 * Returns true if this object holds a valid surface. 366 * 367 * @return True if it holds a physical surface, so lockCanvas() will succeed. 368 * Otherwise returns false. 369 */ isValid()370 public boolean isValid() { 371 synchronized (mLock) { 372 if (mNativeObject == 0) return false; 373 return nativeIsValid(mNativeObject); 374 } 375 } 376 377 /** 378 * Gets the generation number of this surface, incremented each time 379 * the native surface contained within this object changes. 380 * 381 * @return The current generation number. 382 * @hide 383 */ getGenerationId()384 public int getGenerationId() { 385 synchronized (mLock) { 386 return mGenerationId; 387 } 388 } 389 390 /** 391 * Returns the next frame number which will be dequeued for rendering. 392 * Intended for use with SurfaceFlinger's deferred transactions API. 393 * 394 * @hide 395 */ 396 @UnsupportedAppUsage getNextFrameNumber()397 public long getNextFrameNumber() { 398 synchronized (mLock) { 399 checkNotReleasedLocked(); 400 return nativeGetNextFrameNumber(mNativeObject); 401 } 402 } 403 404 /** 405 * Returns true if the consumer of this Surface is running behind the producer. 406 * 407 * @return True if the consumer is more than one buffer ahead of the producer. 408 * @hide 409 */ isConsumerRunningBehind()410 public boolean isConsumerRunningBehind() { 411 synchronized (mLock) { 412 checkNotReleasedLocked(); 413 return nativeIsConsumerRunningBehind(mNativeObject); 414 } 415 } 416 417 /** 418 * Returns the default size of this Surface provided by the consumer of the surface. 419 * Should only be used by the producer of the surface. 420 * 421 * @hide 422 */ 423 @NonNull getDefaultSize()424 public Point getDefaultSize() { 425 synchronized (mLock) { 426 checkNotReleasedLocked(); 427 return new Point(nativeGetWidth(mNativeObject), nativeGetHeight(mNativeObject)); 428 } 429 } 430 431 /** 432 * Gets a {@link Canvas} for drawing into this surface. 433 * 434 * After drawing into the provided {@link Canvas}, the caller must 435 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface. 436 * 437 * @param inOutDirty A rectangle that represents the dirty region that the caller wants 438 * to redraw. This function may choose to expand the dirty rectangle if for example 439 * the surface has been resized or if the previous contents of the surface were 440 * not available. The caller must redraw the entire dirty region as represented 441 * by the contents of the inOutDirty rectangle upon return from this function. 442 * The caller may also pass <code>null</code> instead, in the case where the 443 * entire surface should be redrawn. 444 * @return A canvas for drawing into the surface. 445 * 446 * @throws IllegalArgumentException If the inOutDirty rectangle is not valid. 447 * @throws OutOfResourcesException If the canvas cannot be locked. 448 */ lockCanvas(Rect inOutDirty)449 public Canvas lockCanvas(Rect inOutDirty) 450 throws Surface.OutOfResourcesException, IllegalArgumentException { 451 synchronized (mLock) { 452 checkNotReleasedLocked(); 453 if (mLockedObject != 0) { 454 // Ideally, nativeLockCanvas() would throw in this situation and prevent the 455 // double-lock, but that won't happen if mNativeObject was updated. We can't 456 // abandon the old mLockedObject because it might still be in use, so instead 457 // we just refuse to re-lock the Surface. 458 throw new IllegalArgumentException("Surface was already locked"); 459 } 460 mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty); 461 return mCanvas; 462 } 463 } 464 465 /** 466 * Posts the new contents of the {@link Canvas} to the surface and 467 * releases the {@link Canvas}. 468 * 469 * @param canvas The canvas previously obtained from {@link #lockCanvas}. 470 */ unlockCanvasAndPost(Canvas canvas)471 public void unlockCanvasAndPost(Canvas canvas) { 472 synchronized (mLock) { 473 checkNotReleasedLocked(); 474 475 if (mHwuiContext != null) { 476 mHwuiContext.unlockAndPost(canvas); 477 } else { 478 unlockSwCanvasAndPost(canvas); 479 } 480 } 481 } 482 unlockSwCanvasAndPost(Canvas canvas)483 private void unlockSwCanvasAndPost(Canvas canvas) { 484 if (canvas != mCanvas) { 485 throw new IllegalArgumentException("canvas object must be the same instance that " 486 + "was previously returned by lockCanvas"); 487 } 488 if (mNativeObject != mLockedObject) { 489 Log.w(TAG, "WARNING: Surface's mNativeObject (0x" + 490 Long.toHexString(mNativeObject) + ") != mLockedObject (0x" + 491 Long.toHexString(mLockedObject) +")"); 492 } 493 if (mLockedObject == 0) { 494 throw new IllegalStateException("Surface was not locked"); 495 } 496 try { 497 nativeUnlockCanvasAndPost(mLockedObject, canvas); 498 } finally { 499 nativeRelease(mLockedObject); 500 mLockedObject = 0; 501 } 502 } 503 504 /** 505 * Gets a {@link Canvas} for drawing into this surface. 506 * 507 * After drawing into the provided {@link Canvas}, the caller must 508 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface. 509 * 510 * Unlike {@link #lockCanvas(Rect)} this will return a hardware-accelerated 511 * canvas. See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported"> 512 * unsupported drawing operations</a> for a list of what is and isn't 513 * supported in a hardware-accelerated canvas. It is also required to 514 * fully cover the surface every time {@link #lockHardwareCanvas()} is 515 * called as the buffer is not preserved between frames. Partial updates 516 * are not supported. 517 * 518 * @return A canvas for drawing into the surface. 519 * 520 * @throws IllegalStateException If the canvas cannot be locked. 521 */ lockHardwareCanvas()522 public Canvas lockHardwareCanvas() { 523 synchronized (mLock) { 524 checkNotReleasedLocked(); 525 if (mHwuiContext == null) { 526 mHwuiContext = new HwuiContext(false); 527 } 528 return mHwuiContext.lockCanvas( 529 nativeGetWidth(mNativeObject), 530 nativeGetHeight(mNativeObject)); 531 } 532 } 533 534 /** 535 * Gets a {@link Canvas} for drawing into this surface that supports wide color gamut. 536 * 537 * After drawing into the provided {@link Canvas}, the caller must 538 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface. 539 * 540 * Unlike {@link #lockCanvas(Rect)} and {@link #lockHardwareCanvas()}, 541 * this will return a hardware-accelerated canvas that supports wide color gamut. 542 * See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported"> 543 * unsupported drawing operations</a> for a list of what is and isn't 544 * supported in a hardware-accelerated canvas. It is also required to 545 * fully cover the surface every time {@link #lockHardwareCanvas()} is 546 * called as the buffer is not preserved between frames. Partial updates 547 * are not supported. 548 * 549 * @return A canvas for drawing into the surface. 550 * 551 * @throws IllegalStateException If the canvas cannot be locked. 552 * 553 * @hide 554 */ lockHardwareWideColorGamutCanvas()555 public Canvas lockHardwareWideColorGamutCanvas() { 556 synchronized (mLock) { 557 checkNotReleasedLocked(); 558 if (mHwuiContext != null && !mHwuiContext.isWideColorGamut()) { 559 mHwuiContext.destroy(); 560 mHwuiContext = null; 561 } 562 if (mHwuiContext == null) { 563 mHwuiContext = new HwuiContext(true); 564 } 565 return mHwuiContext.lockCanvas( 566 nativeGetWidth(mNativeObject), 567 nativeGetHeight(mNativeObject)); 568 } 569 } 570 571 /** 572 * @deprecated This API has been removed and is not supported. Do not use. 573 */ 574 @Deprecated unlockCanvas(Canvas canvas)575 public void unlockCanvas(Canvas canvas) { 576 throw new UnsupportedOperationException(); 577 } 578 579 /** 580 * Sets the translator used to scale canvas's width/height in compatibility 581 * mode. 582 */ setCompatibilityTranslator(Translator translator)583 void setCompatibilityTranslator(Translator translator) { 584 if (translator != null) { 585 float appScale = translator.applicationScale; 586 mCompatibleMatrix = new Matrix(); 587 mCompatibleMatrix.setScale(appScale, appScale); 588 } 589 } 590 updateNativeObject(long newNativeObject)591 private void updateNativeObject(long newNativeObject) { 592 synchronized (mLock) { 593 if (newNativeObject == mNativeObject) { 594 return; 595 } 596 if (mNativeObject != 0) { 597 nativeRelease(mNativeObject); 598 } 599 setNativeObjectLocked(newNativeObject); 600 } 601 } 602 603 /** 604 * Copy another surface to this one. This surface now holds a reference 605 * to the same data as the original surface, and is -not- the owner. 606 * This is for use by the window manager when returning a window surface 607 * back from a client, converting it from the representation being managed 608 * by the window manager to the representation the client uses to draw 609 * in to it. 610 * 611 * @param other {@link SurfaceControl} to copy from. 612 * @hide 613 */ 614 @UnsupportedAppUsage copyFrom(SurfaceControl other)615 public void copyFrom(SurfaceControl other) { 616 if (other == null) { 617 throw new IllegalArgumentException("other must not be null"); 618 } 619 620 long surfaceControlPtr = other.mNativeObject; 621 if (surfaceControlPtr == 0) { 622 throw new NullPointerException( 623 "null SurfaceControl native object. Are you using a released SurfaceControl?"); 624 } 625 long newNativeObject = nativeGetFromSurfaceControl(mNativeObject, surfaceControlPtr); 626 updateNativeObject(newNativeObject); 627 } 628 629 /** 630 * Update the surface if the BLASTBufferQueue IGraphicBufferProducer is different from this 631 * surface's IGraphicBufferProducer. 632 * 633 * @param queue {@link BLASTBufferQueue} to copy from. 634 * @hide 635 */ copyFrom(BLASTBufferQueue queue)636 public void copyFrom(BLASTBufferQueue queue) { 637 if (queue == null) { 638 throw new IllegalArgumentException("queue must not be null"); 639 } 640 641 long blastBufferQueuePtr = queue.mNativeObject; 642 if (blastBufferQueuePtr == 0) { 643 throw new NullPointerException("Null BLASTBufferQueue native object"); 644 } 645 long newNativeObject = nativeGetFromBlastBufferQueue(mNativeObject, blastBufferQueuePtr); 646 updateNativeObject(newNativeObject); 647 } 648 649 /** 650 * Gets a reference a surface created from this one. This surface now holds a reference 651 * to the same data as the original surface, and is -not- the owner. 652 * This is for use by the window manager when returning a window surface 653 * back from a client, converting it from the representation being managed 654 * by the window manager to the representation the client uses to draw 655 * in to it. 656 * 657 * @param other {@link SurfaceControl} to create surface from. 658 * 659 * @hide 660 */ createFrom(SurfaceControl other)661 public void createFrom(SurfaceControl other) { 662 if (other == null) { 663 throw new IllegalArgumentException("other must not be null"); 664 } 665 666 long surfaceControlPtr = other.mNativeObject; 667 if (surfaceControlPtr == 0) { 668 throw new NullPointerException( 669 "null SurfaceControl native object. Are you using a released SurfaceControl?"); 670 } 671 long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr); 672 673 synchronized (mLock) { 674 if (mNativeObject != 0) { 675 nativeRelease(mNativeObject); 676 } 677 setNativeObjectLocked(newNativeObject); 678 } 679 } 680 681 /** 682 * This is intended to be used by {@link SurfaceView#updateWindow} only. 683 * @param other access is not thread safe 684 * @hide 685 * @deprecated 686 */ 687 @Deprecated 688 @UnsupportedAppUsage transferFrom(Surface other)689 public void transferFrom(Surface other) { 690 if (other == null) { 691 throw new IllegalArgumentException("other must not be null"); 692 } 693 if (other != this) { 694 final long newPtr; 695 synchronized (other.mLock) { 696 newPtr = other.mNativeObject; 697 other.setNativeObjectLocked(0); 698 } 699 700 synchronized (mLock) { 701 if (mNativeObject != 0) { 702 nativeRelease(mNativeObject); 703 } 704 setNativeObjectLocked(newPtr); 705 } 706 } 707 } 708 709 @Override describeContents()710 public int describeContents() { 711 return 0; 712 } 713 readFromParcel(Parcel source)714 public void readFromParcel(Parcel source) { 715 if (source == null) { 716 throw new IllegalArgumentException("source must not be null"); 717 } 718 719 synchronized (mLock) { 720 // nativeReadFromParcel() will either return mNativeObject, or 721 // create a new native Surface and return it after reducing 722 // the reference count on mNativeObject. Either way, it is 723 // not necessary to call nativeRelease() here. 724 // NOTE: This must be kept synchronized with the native parceling code 725 // in frameworks/native/libs/Surface.cpp 726 mName = source.readString(); 727 mIsSingleBuffered = source.readInt() != 0; 728 setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source)); 729 } 730 } 731 732 @Override writeToParcel(Parcel dest, int flags)733 public void writeToParcel(Parcel dest, int flags) { 734 if (dest == null) { 735 throw new IllegalArgumentException("dest must not be null"); 736 } 737 synchronized (mLock) { 738 // NOTE: This must be kept synchronized with the native parceling code 739 // in frameworks/native/libs/Surface.cpp 740 dest.writeString(mName); 741 dest.writeInt(mIsSingleBuffered ? 1 : 0); 742 nativeWriteToParcel(mNativeObject, dest); 743 } 744 if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) { 745 release(); 746 } 747 } 748 749 @Override toString()750 public String toString() { 751 synchronized (mLock) { 752 return "Surface(name=" + mName + ")/@0x" + 753 Integer.toHexString(System.identityHashCode(this)); 754 } 755 } 756 setNativeObjectLocked(long ptr)757 private void setNativeObjectLocked(long ptr) { 758 if (mNativeObject != ptr) { 759 if (mNativeObject == 0 && ptr != 0) { 760 mCloseGuard.open("Surface.release"); 761 } else if (mNativeObject != 0 && ptr == 0) { 762 mCloseGuard.close(); 763 } 764 mNativeObject = ptr; 765 mGenerationId += 1; 766 if (mHwuiContext != null) { 767 mHwuiContext.updateSurface(); 768 } 769 } 770 } 771 checkNotReleasedLocked()772 private void checkNotReleasedLocked() { 773 if (mNativeObject == 0) { 774 throw new IllegalStateException("Surface has already been released."); 775 } 776 } 777 778 /** 779 * Allocate buffers ahead of time to avoid allocation delays during rendering 780 * @hide 781 */ allocateBuffers()782 public void allocateBuffers() { 783 synchronized (mLock) { 784 checkNotReleasedLocked(); 785 nativeAllocateBuffers(mNativeObject); 786 } 787 } 788 789 /** 790 * Set the scaling mode to be used for this surfaces buffers 791 * @hide 792 */ setScalingMode(@calingMode int scalingMode)793 public void setScalingMode(@ScalingMode int scalingMode) { 794 synchronized (mLock) { 795 checkNotReleasedLocked(); 796 int err = nativeSetScalingMode(mNativeObject, scalingMode); 797 if (err != 0) { 798 throw new IllegalArgumentException("Invalid scaling mode: " + scalingMode); 799 } 800 } 801 } 802 forceScopedDisconnect()803 void forceScopedDisconnect() { 804 synchronized (mLock) { 805 checkNotReleasedLocked(); 806 int err = nativeForceScopedDisconnect(mNativeObject); 807 if (err != 0) { 808 throw new RuntimeException("Failed to disconnect Surface instance (bad object?)"); 809 } 810 } 811 } 812 813 /** 814 * Transfer ownership of buffer with a color space and present it on the Surface. 815 * The supported color spaces are SRGB and Display P3, other color spaces will be 816 * treated as SRGB. 817 * @hide 818 */ attachAndQueueBufferWithColorSpace(HardwareBuffer buffer, ColorSpace colorSpace)819 public void attachAndQueueBufferWithColorSpace(HardwareBuffer buffer, ColorSpace colorSpace) { 820 synchronized (mLock) { 821 checkNotReleasedLocked(); 822 if (colorSpace == null) { 823 colorSpace = ColorSpace.get(ColorSpace.Named.SRGB); 824 } 825 int err = nativeAttachAndQueueBufferWithColorSpace(mNativeObject, buffer, 826 colorSpace.getId()); 827 if (err != 0) { 828 throw new RuntimeException( 829 "Failed to attach and queue buffer to Surface (bad object?), " 830 + "native error: " + err); 831 } 832 } 833 } 834 835 /** 836 * Returns whether or not this Surface is backed by a single-buffered SurfaceTexture 837 * @hide 838 */ isSingleBuffered()839 public boolean isSingleBuffered() { 840 return mIsSingleBuffered; 841 } 842 843 /** 844 * <p>The shared buffer mode allows both the application and the surface compositor 845 * (SurfaceFlinger) to concurrently access this surface's buffer. While the 846 * application is still required to issue a present request 847 * (see {@link #unlockCanvasAndPost(Canvas)}) to the compositor when an update is required, 848 * the compositor may trigger an update at any time. Since the surface's buffer is shared 849 * between the application and the compositor, updates triggered by the compositor may 850 * cause visible tearing.</p> 851 * 852 * <p>The shared buffer mode can be used with 853 * {@link #setAutoRefreshEnabled(boolean) auto-refresh} to avoid the overhead of 854 * issuing present requests.</p> 855 * 856 * <p>If the application uses the shared buffer mode to reduce latency, it is 857 * recommended to use software rendering (see {@link #lockCanvas(Rect)} to ensure 858 * the graphics workloads are not affected by other applications and/or the system 859 * using the GPU. When using software rendering, the application should update the 860 * smallest possible region of the surface required.</p> 861 * 862 * <p class="note">The shared buffer mode might not be supported by the underlying 863 * hardware. Enabling shared buffer mode on hardware that does not support it will 864 * not yield an error but the application will not benefit from lower latency (and 865 * tearing will not be visible).</p> 866 * 867 * <p class="note">Depending on how many and what kind of surfaces are visible, the 868 * surface compositor may need to copy the shared buffer before it is displayed. When 869 * this happens, the latency benefits of shared buffer mode will be reduced.</p> 870 * 871 * @param enabled True to enable the shared buffer mode on this surface, false otherwise 872 * 873 * @see #isSharedBufferModeEnabled() 874 * @see #setAutoRefreshEnabled(boolean) 875 * 876 * @hide 877 */ setSharedBufferModeEnabled(boolean enabled)878 public void setSharedBufferModeEnabled(boolean enabled) { 879 if (mIsSharedBufferModeEnabled != enabled) { 880 int error = nativeSetSharedBufferModeEnabled(mNativeObject, enabled); 881 if (error != 0) { 882 throw new RuntimeException( 883 "Failed to set shared buffer mode on Surface (bad object?)"); 884 } else { 885 mIsSharedBufferModeEnabled = enabled; 886 } 887 } 888 } 889 890 /** 891 * @return True if shared buffer mode is enabled on this surface, false otherwise 892 * 893 * @see #setSharedBufferModeEnabled(boolean) 894 * 895 * @hide 896 */ isSharedBufferModeEnabled()897 public boolean isSharedBufferModeEnabled() { 898 return mIsSharedBufferModeEnabled; 899 } 900 901 /** 902 * <p>When auto-refresh is enabled, the surface compositor (SurfaceFlinger) 903 * automatically updates the display on a regular refresh cycle. The application 904 * can continue to issue present requests but it is not required. Enabling 905 * auto-refresh may result in visible tearing.</p> 906 * 907 * <p>Auto-refresh has no effect if the {@link #setSharedBufferModeEnabled(boolean) 908 * shared buffer mode} is not enabled.</p> 909 * 910 * <p>Because auto-refresh will trigger continuous updates of the display, it is 911 * recommended to turn it on only when necessary. For example, in a drawing/painting 912 * application auto-refresh should be enabled on finger/pen down and disabled on 913 * finger/pen up.</p> 914 * 915 * @param enabled True to enable auto-refresh on this surface, false otherwise 916 * 917 * @see #isAutoRefreshEnabled() 918 * @see #setSharedBufferModeEnabled(boolean) 919 * 920 * @hide 921 */ setAutoRefreshEnabled(boolean enabled)922 public void setAutoRefreshEnabled(boolean enabled) { 923 if (mIsAutoRefreshEnabled != enabled) { 924 int error = nativeSetAutoRefreshEnabled(mNativeObject, enabled); 925 if (error != 0) { 926 throw new RuntimeException("Failed to set auto refresh on Surface (bad object?)"); 927 } else { 928 mIsAutoRefreshEnabled = enabled; 929 } 930 } 931 } 932 933 /** 934 * @return True if auto-refresh is enabled on this surface, false otherwise 935 * 936 * @hide 937 */ isAutoRefreshEnabled()938 public boolean isAutoRefreshEnabled() { 939 return mIsAutoRefreshEnabled; 940 } 941 942 /** 943 * Sets the intended frame rate for this surface. 944 * 945 * <p>On devices that are capable of running the display at different refresh rates, 946 * the system may choose a display refresh rate to better match this surface's frame 947 * rate. Usage of this API won't introduce frame rate throttling, or affect other 948 * aspects of the application's frame production pipeline. However, because the system 949 * may change the display refresh rate, calls to this function may result in changes 950 * to Choreographer callback timings, and changes to the time interval at which the 951 * system releases buffers back to the application.</p> 952 * 953 * <p>Note that this only has an effect for surfaces presented on the display. If this 954 * surface is consumed by something other than the system compositor, e.g. a media 955 * codec, this call has no effect.</p> 956 * 957 * @param frameRate The intended frame rate of this surface, in frames per second. 0 958 * is a special value that indicates the app will accept the system's choice for the 959 * display frame rate, which is the default behavior if this function isn't 960 * called. The <code>frameRate</code> parameter does <em>not</em> need to be a valid refresh 961 * rate for this device's display - e.g., it's fine to pass 30fps to a device that can only run 962 * the display at 60fps. 963 * 964 * @param compatibility The frame rate compatibility of this surface. The 965 * compatibility value may influence the system's choice of display frame rate. 966 * This parameter is ignored when <code>frameRate</code> is 0. 967 * 968 * @param changeFrameRateStrategy Whether display refresh rate transitions caused by this 969 * surface should be seamless. A seamless transition is one that doesn't have any visual 970 * interruptions, such as a black screen for a second or two. This parameter is ignored when 971 * <code>frameRate</code> is 0. 972 * 973 * @throws IllegalArgumentException If <code>frameRate</code>, <code>compatibility</code> or 974 * <code>changeFrameRateStrategy</code> are invalid. 975 */ setFrameRate(@loatRangefrom = 0.0) float frameRate, @FrameRateCompatibility int compatibility, @ChangeFrameRateStrategy int changeFrameRateStrategy)976 public void setFrameRate(@FloatRange(from = 0.0) float frameRate, 977 @FrameRateCompatibility int compatibility, 978 @ChangeFrameRateStrategy int changeFrameRateStrategy) { 979 synchronized (mLock) { 980 checkNotReleasedLocked(); 981 int error = nativeSetFrameRate(mNativeObject, frameRate, compatibility, 982 changeFrameRateStrategy); 983 if (error == -EINVAL) { 984 throw new IllegalArgumentException("Invalid argument to Surface.setFrameRate()"); 985 } else if (error != 0) { 986 throw new RuntimeException("Failed to set frame rate on Surface"); 987 } 988 } 989 } 990 991 /** 992 * Sets the intended frame rate for this surface. Any switching of refresh rates is 993 * most probably going to be seamless. 994 * 995 * @see #setFrameRate(float, int, int) 996 */ setFrameRate( @loatRangefrom = 0.0) float frameRate, @FrameRateCompatibility int compatibility)997 public void setFrameRate( 998 @FloatRange(from = 0.0) float frameRate, @FrameRateCompatibility int compatibility) { 999 setFrameRate(frameRate, compatibility, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); 1000 } 1001 1002 /** 1003 * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or 1004 * when a SurfaceTexture could not successfully be allocated. 1005 */ 1006 @SuppressWarnings("serial") 1007 public static class OutOfResourcesException extends RuntimeException { OutOfResourcesException()1008 public OutOfResourcesException() { 1009 } OutOfResourcesException(String name)1010 public OutOfResourcesException(String name) { 1011 super(name); 1012 } 1013 } 1014 1015 /** 1016 * Returns a human readable representation of a rotation. 1017 * 1018 * @param rotation The rotation. 1019 * @return The rotation symbolic name. 1020 * 1021 * @hide 1022 */ rotationToString(int rotation)1023 public static String rotationToString(int rotation) { 1024 switch (rotation) { 1025 case Surface.ROTATION_0: { 1026 return "ROTATION_0"; 1027 } 1028 case Surface.ROTATION_90: { 1029 return "ROTATION_90"; 1030 } 1031 case Surface.ROTATION_180: { 1032 return "ROTATION_180"; 1033 } 1034 case Surface.ROTATION_270: { 1035 return "ROTATION_270"; 1036 } 1037 default: { 1038 return Integer.toString(rotation); 1039 } 1040 } 1041 } 1042 1043 /** 1044 * A Canvas class that can handle the compatibility mode. 1045 * This does two things differently. 1046 * <ul> 1047 * <li>Returns the width and height of the target metrics, rather than 1048 * native. For example, the canvas returns 320x480 even if an app is running 1049 * in WVGA high density. 1050 * <li>Scales the matrix in setMatrix by the application scale, except if 1051 * the matrix looks like obtained from getMatrix. This is a hack to handle 1052 * the case that an application uses getMatrix to keep the original matrix, 1053 * set matrix of its own, then set the original matrix back. There is no 1054 * perfect solution that works for all cases, and there are a lot of cases 1055 * that this model does not work, but we hope this works for many apps. 1056 * </ul> 1057 */ 1058 private final class CompatibleCanvas extends Canvas { 1059 // A temp matrix to remember what an application obtained via {@link getMatrix} 1060 private Matrix mOrigMatrix = null; 1061 1062 @Override setMatrix(Matrix matrix)1063 public void setMatrix(Matrix matrix) { 1064 if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) { 1065 // don't scale the matrix if it's not compatibility mode, or 1066 // the matrix was obtained from getMatrix. 1067 super.setMatrix(matrix); 1068 } else { 1069 Matrix m = new Matrix(mCompatibleMatrix); 1070 m.preConcat(matrix); 1071 super.setMatrix(m); 1072 } 1073 } 1074 1075 @SuppressWarnings("deprecation") 1076 @Override getMatrix(Matrix m)1077 public void getMatrix(Matrix m) { 1078 super.getMatrix(m); 1079 if (mOrigMatrix == null) { 1080 mOrigMatrix = new Matrix(); 1081 } 1082 mOrigMatrix.set(m); 1083 } 1084 } 1085 1086 private final class HwuiContext { 1087 private final RenderNode mRenderNode; 1088 private HardwareRenderer mHardwareRenderer; 1089 private RecordingCanvas mCanvas; 1090 private final boolean mIsWideColorGamut; 1091 HwuiContext(boolean isWideColorGamut)1092 HwuiContext(boolean isWideColorGamut) { 1093 mRenderNode = RenderNode.create("HwuiCanvas", null); 1094 mRenderNode.setClipToBounds(false); 1095 mRenderNode.setForceDarkAllowed(false); 1096 mIsWideColorGamut = isWideColorGamut; 1097 1098 mHardwareRenderer = new HardwareRenderer(); 1099 mHardwareRenderer.setContentRoot(mRenderNode); 1100 mHardwareRenderer.setSurface(Surface.this, true); 1101 mHardwareRenderer.setColorMode( 1102 isWideColorGamut 1103 ? ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT 1104 : ActivityInfo.COLOR_MODE_DEFAULT); 1105 mHardwareRenderer.setLightSourceAlpha(0.0f, 0.0f); 1106 mHardwareRenderer.setLightSourceGeometry(0.0f, 0.0f, 0.0f, 0.0f); 1107 } 1108 lockCanvas(int width, int height)1109 Canvas lockCanvas(int width, int height) { 1110 if (mCanvas != null) { 1111 throw new IllegalStateException("Surface was already locked!"); 1112 } 1113 mCanvas = mRenderNode.beginRecording(width, height); 1114 return mCanvas; 1115 } 1116 unlockAndPost(Canvas canvas)1117 void unlockAndPost(Canvas canvas) { 1118 if (canvas != mCanvas) { 1119 throw new IllegalArgumentException("canvas object must be the same instance that " 1120 + "was previously returned by lockCanvas"); 1121 } 1122 mRenderNode.endRecording(); 1123 mCanvas = null; 1124 mHardwareRenderer.createRenderRequest() 1125 .setVsyncTime(System.nanoTime()) 1126 .syncAndDraw(); 1127 } 1128 updateSurface()1129 void updateSurface() { 1130 mHardwareRenderer.setSurface(Surface.this, true); 1131 } 1132 destroy()1133 void destroy() { 1134 mHardwareRenderer.destroy(); 1135 } 1136 isWideColorGamut()1137 boolean isWideColorGamut() { 1138 return mIsWideColorGamut; 1139 } 1140 } 1141 } 1142