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 if (mNativeObject != 0) { 345 nativeDestroy(mNativeObject); 346 } 347 release(); 348 } 349 350 /** 351 * Destroys the HwuiContext without completely 352 * releasing the Surface. 353 * @hide 354 */ hwuiDestroy()355 public void hwuiDestroy() { 356 if (mHwuiContext != null) { 357 mHwuiContext.destroy(); 358 mHwuiContext = null; 359 } 360 } 361 362 /** 363 * Returns true if this object holds a valid surface. 364 * 365 * @return True if it holds a physical surface, so lockCanvas() will succeed. 366 * Otherwise returns false. 367 */ isValid()368 public boolean isValid() { 369 synchronized (mLock) { 370 if (mNativeObject == 0) return false; 371 return nativeIsValid(mNativeObject); 372 } 373 } 374 375 /** 376 * Gets the generation number of this surface, incremented each time 377 * the native surface contained within this object changes. 378 * 379 * @return The current generation number. 380 * @hide 381 */ getGenerationId()382 public int getGenerationId() { 383 synchronized (mLock) { 384 return mGenerationId; 385 } 386 } 387 388 /** 389 * Returns the next frame number which will be dequeued for rendering. 390 * Intended for use with SurfaceFlinger's deferred transactions API. 391 * 392 * @hide 393 */ 394 @UnsupportedAppUsage getNextFrameNumber()395 public long getNextFrameNumber() { 396 synchronized (mLock) { 397 checkNotReleasedLocked(); 398 return nativeGetNextFrameNumber(mNativeObject); 399 } 400 } 401 402 /** 403 * Returns true if the consumer of this Surface is running behind the producer. 404 * 405 * @return True if the consumer is more than one buffer ahead of the producer. 406 * @hide 407 */ isConsumerRunningBehind()408 public boolean isConsumerRunningBehind() { 409 synchronized (mLock) { 410 checkNotReleasedLocked(); 411 return nativeIsConsumerRunningBehind(mNativeObject); 412 } 413 } 414 415 /** 416 * Returns the default size of this Surface provided by the consumer of the surface. 417 * Should only be used by the producer of the surface. 418 * 419 * @hide 420 */ 421 @NonNull getDefaultSize()422 public Point getDefaultSize() { 423 synchronized (mLock) { 424 checkNotReleasedLocked(); 425 return new Point(nativeGetWidth(mNativeObject), nativeGetHeight(mNativeObject)); 426 } 427 } 428 429 /** 430 * Gets a {@link Canvas} for drawing into this surface. 431 * 432 * After drawing into the provided {@link Canvas}, the caller must 433 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface. 434 * 435 * @param inOutDirty A rectangle that represents the dirty region that the caller wants 436 * to redraw. This function may choose to expand the dirty rectangle if for example 437 * the surface has been resized or if the previous contents of the surface were 438 * not available. The caller must redraw the entire dirty region as represented 439 * by the contents of the inOutDirty rectangle upon return from this function. 440 * The caller may also pass <code>null</code> instead, in the case where the 441 * entire surface should be redrawn. 442 * @return A canvas for drawing into the surface. 443 * 444 * @throws IllegalArgumentException If the inOutDirty rectangle is not valid. 445 * @throws OutOfResourcesException If the canvas cannot be locked. 446 */ lockCanvas(Rect inOutDirty)447 public Canvas lockCanvas(Rect inOutDirty) 448 throws Surface.OutOfResourcesException, IllegalArgumentException { 449 synchronized (mLock) { 450 checkNotReleasedLocked(); 451 if (mLockedObject != 0) { 452 // Ideally, nativeLockCanvas() would throw in this situation and prevent the 453 // double-lock, but that won't happen if mNativeObject was updated. We can't 454 // abandon the old mLockedObject because it might still be in use, so instead 455 // we just refuse to re-lock the Surface. 456 throw new IllegalArgumentException("Surface was already locked"); 457 } 458 mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty); 459 return mCanvas; 460 } 461 } 462 463 /** 464 * Posts the new contents of the {@link Canvas} to the surface and 465 * releases the {@link Canvas}. 466 * 467 * @param canvas The canvas previously obtained from {@link #lockCanvas}. 468 */ unlockCanvasAndPost(Canvas canvas)469 public void unlockCanvasAndPost(Canvas canvas) { 470 synchronized (mLock) { 471 checkNotReleasedLocked(); 472 473 if (mHwuiContext != null) { 474 mHwuiContext.unlockAndPost(canvas); 475 } else { 476 unlockSwCanvasAndPost(canvas); 477 } 478 } 479 } 480 unlockSwCanvasAndPost(Canvas canvas)481 private void unlockSwCanvasAndPost(Canvas canvas) { 482 if (canvas != mCanvas) { 483 throw new IllegalArgumentException("canvas object must be the same instance that " 484 + "was previously returned by lockCanvas"); 485 } 486 if (mNativeObject != mLockedObject) { 487 Log.w(TAG, "WARNING: Surface's mNativeObject (0x" + 488 Long.toHexString(mNativeObject) + ") != mLockedObject (0x" + 489 Long.toHexString(mLockedObject) +")"); 490 } 491 if (mLockedObject == 0) { 492 throw new IllegalStateException("Surface was not locked"); 493 } 494 try { 495 nativeUnlockCanvasAndPost(mLockedObject, canvas); 496 } finally { 497 nativeRelease(mLockedObject); 498 mLockedObject = 0; 499 } 500 } 501 502 /** 503 * Gets a {@link Canvas} for drawing into this surface. 504 * 505 * After drawing into the provided {@link Canvas}, the caller must 506 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface. 507 * 508 * Unlike {@link #lockCanvas(Rect)} this will return a hardware-accelerated 509 * canvas. See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported"> 510 * unsupported drawing operations</a> for a list of what is and isn't 511 * supported in a hardware-accelerated canvas. It is also required to 512 * fully cover the surface every time {@link #lockHardwareCanvas()} is 513 * called as the buffer is not preserved between frames. Partial updates 514 * are not supported. 515 * 516 * @return A canvas for drawing into the surface. 517 * 518 * @throws IllegalStateException If the canvas cannot be locked. 519 */ lockHardwareCanvas()520 public Canvas lockHardwareCanvas() { 521 synchronized (mLock) { 522 checkNotReleasedLocked(); 523 if (mHwuiContext == null) { 524 mHwuiContext = new HwuiContext(false); 525 } 526 return mHwuiContext.lockCanvas( 527 nativeGetWidth(mNativeObject), 528 nativeGetHeight(mNativeObject)); 529 } 530 } 531 532 /** 533 * Gets a {@link Canvas} for drawing into this surface that supports wide color gamut. 534 * 535 * After drawing into the provided {@link Canvas}, the caller must 536 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface. 537 * 538 * Unlike {@link #lockCanvas(Rect)} and {@link #lockHardwareCanvas()}, 539 * this will return a hardware-accelerated canvas that supports wide color gamut. 540 * See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported"> 541 * unsupported drawing operations</a> for a list of what is and isn't 542 * supported in a hardware-accelerated canvas. It is also required to 543 * fully cover the surface every time {@link #lockHardwareCanvas()} is 544 * called as the buffer is not preserved between frames. Partial updates 545 * are not supported. 546 * 547 * @return A canvas for drawing into the surface. 548 * 549 * @throws IllegalStateException If the canvas cannot be locked. 550 * 551 * @hide 552 */ lockHardwareWideColorGamutCanvas()553 public Canvas lockHardwareWideColorGamutCanvas() { 554 synchronized (mLock) { 555 checkNotReleasedLocked(); 556 if (mHwuiContext != null && !mHwuiContext.isWideColorGamut()) { 557 mHwuiContext.destroy(); 558 mHwuiContext = null; 559 } 560 if (mHwuiContext == null) { 561 mHwuiContext = new HwuiContext(true); 562 } 563 return mHwuiContext.lockCanvas( 564 nativeGetWidth(mNativeObject), 565 nativeGetHeight(mNativeObject)); 566 } 567 } 568 569 /** 570 * @deprecated This API has been removed and is not supported. Do not use. 571 */ 572 @Deprecated unlockCanvas(Canvas canvas)573 public void unlockCanvas(Canvas canvas) { 574 throw new UnsupportedOperationException(); 575 } 576 577 /** 578 * Sets the translator used to scale canvas's width/height in compatibility 579 * mode. 580 */ setCompatibilityTranslator(Translator translator)581 void setCompatibilityTranslator(Translator translator) { 582 if (translator != null) { 583 float appScale = translator.applicationScale; 584 mCompatibleMatrix = new Matrix(); 585 mCompatibleMatrix.setScale(appScale, appScale); 586 } 587 } 588 updateNativeObject(long newNativeObject)589 private void updateNativeObject(long newNativeObject) { 590 synchronized (mLock) { 591 if (newNativeObject == mNativeObject) { 592 return; 593 } 594 if (mNativeObject != 0) { 595 nativeRelease(mNativeObject); 596 } 597 setNativeObjectLocked(newNativeObject); 598 } 599 } 600 601 /** 602 * Copy another surface to this one. This surface now holds a reference 603 * to the same data as the original surface, and is -not- the owner. 604 * This is for use by the window manager when returning a window surface 605 * back from a client, converting it from the representation being managed 606 * by the window manager to the representation the client uses to draw 607 * in to it. 608 * 609 * @param other {@link SurfaceControl} to copy from. 610 * @hide 611 */ 612 @UnsupportedAppUsage copyFrom(SurfaceControl other)613 public void copyFrom(SurfaceControl other) { 614 if (other == null) { 615 throw new IllegalArgumentException("other must not be null"); 616 } 617 618 long surfaceControlPtr = other.mNativeObject; 619 if (surfaceControlPtr == 0) { 620 throw new NullPointerException( 621 "null SurfaceControl native object. Are you using a released SurfaceControl?"); 622 } 623 long newNativeObject = nativeGetFromSurfaceControl(mNativeObject, surfaceControlPtr); 624 updateNativeObject(newNativeObject); 625 } 626 627 /** 628 * Update the surface if the BLASTBufferQueue IGraphicBufferProducer is different from this 629 * surface's IGraphicBufferProducer. 630 * 631 * @param queue {@link BLASTBufferQueue} to copy from. 632 * @hide 633 */ copyFrom(BLASTBufferQueue queue)634 public void copyFrom(BLASTBufferQueue queue) { 635 if (queue == null) { 636 throw new IllegalArgumentException("queue must not be null"); 637 } 638 639 long blastBufferQueuePtr = queue.mNativeObject; 640 if (blastBufferQueuePtr == 0) { 641 throw new NullPointerException("Null BLASTBufferQueue native object"); 642 } 643 long newNativeObject = nativeGetFromBlastBufferQueue(mNativeObject, blastBufferQueuePtr); 644 updateNativeObject(newNativeObject); 645 } 646 647 /** 648 * Gets a reference a surface created from this one. This surface now holds a reference 649 * to the same data as the original surface, and is -not- the owner. 650 * This is for use by the window manager when returning a window surface 651 * back from a client, converting it from the representation being managed 652 * by the window manager to the representation the client uses to draw 653 * in to it. 654 * 655 * @param other {@link SurfaceControl} to create surface from. 656 * 657 * @hide 658 */ createFrom(SurfaceControl other)659 public void createFrom(SurfaceControl other) { 660 if (other == null) { 661 throw new IllegalArgumentException("other must not be null"); 662 } 663 664 long surfaceControlPtr = other.mNativeObject; 665 if (surfaceControlPtr == 0) { 666 throw new NullPointerException( 667 "null SurfaceControl native object. Are you using a released SurfaceControl?"); 668 } 669 long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr); 670 671 synchronized (mLock) { 672 if (mNativeObject != 0) { 673 nativeRelease(mNativeObject); 674 } 675 setNativeObjectLocked(newNativeObject); 676 } 677 } 678 679 /** 680 * This is intended to be used by {@link SurfaceView#updateWindow} only. 681 * @param other access is not thread safe 682 * @hide 683 * @deprecated 684 */ 685 @Deprecated 686 @UnsupportedAppUsage transferFrom(Surface other)687 public void transferFrom(Surface other) { 688 if (other == null) { 689 throw new IllegalArgumentException("other must not be null"); 690 } 691 if (other != this) { 692 final long newPtr; 693 synchronized (other.mLock) { 694 newPtr = other.mNativeObject; 695 other.setNativeObjectLocked(0); 696 } 697 698 synchronized (mLock) { 699 if (mNativeObject != 0) { 700 nativeRelease(mNativeObject); 701 } 702 setNativeObjectLocked(newPtr); 703 } 704 } 705 } 706 707 @Override describeContents()708 public int describeContents() { 709 return 0; 710 } 711 readFromParcel(Parcel source)712 public void readFromParcel(Parcel source) { 713 if (source == null) { 714 throw new IllegalArgumentException("source must not be null"); 715 } 716 717 synchronized (mLock) { 718 // nativeReadFromParcel() will either return mNativeObject, or 719 // create a new native Surface and return it after reducing 720 // the reference count on mNativeObject. Either way, it is 721 // not necessary to call nativeRelease() here. 722 // NOTE: This must be kept synchronized with the native parceling code 723 // in frameworks/native/libs/Surface.cpp 724 mName = source.readString(); 725 mIsSingleBuffered = source.readInt() != 0; 726 setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source)); 727 } 728 } 729 730 @Override writeToParcel(Parcel dest, int flags)731 public void writeToParcel(Parcel dest, int flags) { 732 if (dest == null) { 733 throw new IllegalArgumentException("dest must not be null"); 734 } 735 synchronized (mLock) { 736 // NOTE: This must be kept synchronized with the native parceling code 737 // in frameworks/native/libs/Surface.cpp 738 dest.writeString(mName); 739 dest.writeInt(mIsSingleBuffered ? 1 : 0); 740 nativeWriteToParcel(mNativeObject, dest); 741 } 742 if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) { 743 release(); 744 } 745 } 746 747 @Override toString()748 public String toString() { 749 synchronized (mLock) { 750 return "Surface(name=" + mName + ")/@0x" + 751 Integer.toHexString(System.identityHashCode(this)); 752 } 753 } 754 setNativeObjectLocked(long ptr)755 private void setNativeObjectLocked(long ptr) { 756 if (mNativeObject != ptr) { 757 if (mNativeObject == 0 && ptr != 0) { 758 mCloseGuard.open("release"); 759 } else if (mNativeObject != 0 && ptr == 0) { 760 mCloseGuard.close(); 761 } 762 mNativeObject = ptr; 763 mGenerationId += 1; 764 if (mHwuiContext != null) { 765 mHwuiContext.updateSurface(); 766 } 767 } 768 } 769 checkNotReleasedLocked()770 private void checkNotReleasedLocked() { 771 if (mNativeObject == 0) { 772 throw new IllegalStateException("Surface has already been released."); 773 } 774 } 775 776 /** 777 * Allocate buffers ahead of time to avoid allocation delays during rendering 778 * @hide 779 */ allocateBuffers()780 public void allocateBuffers() { 781 synchronized (mLock) { 782 checkNotReleasedLocked(); 783 nativeAllocateBuffers(mNativeObject); 784 } 785 } 786 787 /** 788 * Set the scaling mode to be used for this surfaces buffers 789 * @hide 790 */ setScalingMode(@calingMode int scalingMode)791 public void setScalingMode(@ScalingMode int scalingMode) { 792 synchronized (mLock) { 793 checkNotReleasedLocked(); 794 int err = nativeSetScalingMode(mNativeObject, scalingMode); 795 if (err != 0) { 796 throw new IllegalArgumentException("Invalid scaling mode: " + scalingMode); 797 } 798 } 799 } 800 forceScopedDisconnect()801 void forceScopedDisconnect() { 802 synchronized (mLock) { 803 checkNotReleasedLocked(); 804 int err = nativeForceScopedDisconnect(mNativeObject); 805 if (err != 0) { 806 throw new RuntimeException("Failed to disconnect Surface instance (bad object?)"); 807 } 808 } 809 } 810 811 /** 812 * Transfer ownership of buffer with a color space and present it on the Surface. 813 * The supported color spaces are SRGB and Display P3, other color spaces will be 814 * treated as SRGB. 815 * @hide 816 */ attachAndQueueBufferWithColorSpace(HardwareBuffer buffer, ColorSpace colorSpace)817 public void attachAndQueueBufferWithColorSpace(HardwareBuffer buffer, ColorSpace colorSpace) { 818 synchronized (mLock) { 819 checkNotReleasedLocked(); 820 if (colorSpace == null) { 821 colorSpace = ColorSpace.get(ColorSpace.Named.SRGB); 822 } 823 int err = nativeAttachAndQueueBufferWithColorSpace(mNativeObject, buffer, 824 colorSpace.getId()); 825 if (err != 0) { 826 throw new RuntimeException( 827 "Failed to attach and queue buffer to Surface (bad object?), " 828 + "native error: " + err); 829 } 830 } 831 } 832 833 /** 834 * Returns whether or not this Surface is backed by a single-buffered SurfaceTexture 835 * @hide 836 */ isSingleBuffered()837 public boolean isSingleBuffered() { 838 return mIsSingleBuffered; 839 } 840 841 /** 842 * <p>The shared buffer mode allows both the application and the surface compositor 843 * (SurfaceFlinger) to concurrently access this surface's buffer. While the 844 * application is still required to issue a present request 845 * (see {@link #unlockCanvasAndPost(Canvas)}) to the compositor when an update is required, 846 * the compositor may trigger an update at any time. Since the surface's buffer is shared 847 * between the application and the compositor, updates triggered by the compositor may 848 * cause visible tearing.</p> 849 * 850 * <p>The shared buffer mode can be used with 851 * {@link #setAutoRefreshEnabled(boolean) auto-refresh} to avoid the overhead of 852 * issuing present requests.</p> 853 * 854 * <p>If the application uses the shared buffer mode to reduce latency, it is 855 * recommended to use software rendering (see {@link #lockCanvas(Rect)} to ensure 856 * the graphics workloads are not affected by other applications and/or the system 857 * using the GPU. When using software rendering, the application should update the 858 * smallest possible region of the surface required.</p> 859 * 860 * <p class="note">The shared buffer mode might not be supported by the underlying 861 * hardware. Enabling shared buffer mode on hardware that does not support it will 862 * not yield an error but the application will not benefit from lower latency (and 863 * tearing will not be visible).</p> 864 * 865 * <p class="note">Depending on how many and what kind of surfaces are visible, the 866 * surface compositor may need to copy the shared buffer before it is displayed. When 867 * this happens, the latency benefits of shared buffer mode will be reduced.</p> 868 * 869 * @param enabled True to enable the shared buffer mode on this surface, false otherwise 870 * 871 * @see #isSharedBufferModeEnabled() 872 * @see #setAutoRefreshEnabled(boolean) 873 * 874 * @hide 875 */ setSharedBufferModeEnabled(boolean enabled)876 public void setSharedBufferModeEnabled(boolean enabled) { 877 if (mIsSharedBufferModeEnabled != enabled) { 878 int error = nativeSetSharedBufferModeEnabled(mNativeObject, enabled); 879 if (error != 0) { 880 throw new RuntimeException( 881 "Failed to set shared buffer mode on Surface (bad object?)"); 882 } else { 883 mIsSharedBufferModeEnabled = enabled; 884 } 885 } 886 } 887 888 /** 889 * @return True if shared buffer mode is enabled on this surface, false otherwise 890 * 891 * @see #setSharedBufferModeEnabled(boolean) 892 * 893 * @hide 894 */ isSharedBufferModeEnabled()895 public boolean isSharedBufferModeEnabled() { 896 return mIsSharedBufferModeEnabled; 897 } 898 899 /** 900 * <p>When auto-refresh is enabled, the surface compositor (SurfaceFlinger) 901 * automatically updates the display on a regular refresh cycle. The application 902 * can continue to issue present requests but it is not required. Enabling 903 * auto-refresh may result in visible tearing.</p> 904 * 905 * <p>Auto-refresh has no effect if the {@link #setSharedBufferModeEnabled(boolean) 906 * shared buffer mode} is not enabled.</p> 907 * 908 * <p>Because auto-refresh will trigger continuous updates of the display, it is 909 * recommended to turn it on only when necessary. For example, in a drawing/painting 910 * application auto-refresh should be enabled on finger/pen down and disabled on 911 * finger/pen up.</p> 912 * 913 * @param enabled True to enable auto-refresh on this surface, false otherwise 914 * 915 * @see #isAutoRefreshEnabled() 916 * @see #setSharedBufferModeEnabled(boolean) 917 * 918 * @hide 919 */ setAutoRefreshEnabled(boolean enabled)920 public void setAutoRefreshEnabled(boolean enabled) { 921 if (mIsAutoRefreshEnabled != enabled) { 922 int error = nativeSetAutoRefreshEnabled(mNativeObject, enabled); 923 if (error != 0) { 924 throw new RuntimeException("Failed to set auto refresh on Surface (bad object?)"); 925 } else { 926 mIsAutoRefreshEnabled = enabled; 927 } 928 } 929 } 930 931 /** 932 * @return True if auto-refresh is enabled on this surface, false otherwise 933 * 934 * @hide 935 */ isAutoRefreshEnabled()936 public boolean isAutoRefreshEnabled() { 937 return mIsAutoRefreshEnabled; 938 } 939 940 /** 941 * Sets the intended frame rate for this surface. 942 * 943 * <p>On devices that are capable of running the display at different refresh rates, 944 * the system may choose a display refresh rate to better match this surface's frame 945 * rate. Usage of this API won't introduce frame rate throttling, or affect other 946 * aspects of the application's frame production pipeline. However, because the system 947 * may change the display refresh rate, calls to this function may result in changes 948 * to Choreographer callback timings, and changes to the time interval at which the 949 * system releases buffers back to the application.</p> 950 * 951 * <p>Note that this only has an effect for surfaces presented on the display. If this 952 * surface is consumed by something other than the system compositor, e.g. a media 953 * codec, this call has no effect.</p> 954 * 955 * @param frameRate The intended frame rate of this surface, in frames per second. 0 956 * is a special value that indicates the app will accept the system's choice for the 957 * display frame rate, which is the default behavior if this function isn't 958 * called. The <code>frameRate</code> parameter does <em>not</em> need to be a valid refresh 959 * rate for this device's display - e.g., it's fine to pass 30fps to a device that can only run 960 * the display at 60fps. 961 * 962 * @param compatibility The frame rate compatibility of this surface. The 963 * compatibility value may influence the system's choice of display frame rate. 964 * This parameter is ignored when <code>frameRate</code> is 0. 965 * 966 * @param changeFrameRateStrategy Whether display refresh rate transitions caused by this 967 * surface should be seamless. A seamless transition is one that doesn't have any visual 968 * interruptions, such as a black screen for a second or two. This parameter is ignored when 969 * <code>frameRate</code> is 0. 970 * 971 * @throws IllegalArgumentException If <code>frameRate</code>, <code>compatibility</code> or 972 * <code>changeFrameRateStrategy</code> are invalid. 973 */ setFrameRate(@loatRangefrom = 0.0) float frameRate, @FrameRateCompatibility int compatibility, @ChangeFrameRateStrategy int changeFrameRateStrategy)974 public void setFrameRate(@FloatRange(from = 0.0) float frameRate, 975 @FrameRateCompatibility int compatibility, 976 @ChangeFrameRateStrategy int changeFrameRateStrategy) { 977 synchronized (mLock) { 978 checkNotReleasedLocked(); 979 int error = nativeSetFrameRate(mNativeObject, frameRate, compatibility, 980 changeFrameRateStrategy); 981 if (error == -EINVAL) { 982 throw new IllegalArgumentException("Invalid argument to Surface.setFrameRate()"); 983 } else if (error != 0) { 984 throw new RuntimeException("Failed to set frame rate on Surface"); 985 } 986 } 987 } 988 989 /** 990 * Sets the intended frame rate for this surface. Any switching of refresh rates is 991 * most probably going to be seamless. 992 * 993 * @see #setFrameRate(float, int, int) 994 */ setFrameRate( @loatRangefrom = 0.0) float frameRate, @FrameRateCompatibility int compatibility)995 public void setFrameRate( 996 @FloatRange(from = 0.0) float frameRate, @FrameRateCompatibility int compatibility) { 997 setFrameRate(frameRate, compatibility, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); 998 } 999 1000 /** 1001 * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or 1002 * when a SurfaceTexture could not successfully be allocated. 1003 */ 1004 @SuppressWarnings("serial") 1005 public static class OutOfResourcesException extends RuntimeException { OutOfResourcesException()1006 public OutOfResourcesException() { 1007 } OutOfResourcesException(String name)1008 public OutOfResourcesException(String name) { 1009 super(name); 1010 } 1011 } 1012 1013 /** 1014 * Returns a human readable representation of a rotation. 1015 * 1016 * @param rotation The rotation. 1017 * @return The rotation symbolic name. 1018 * 1019 * @hide 1020 */ rotationToString(int rotation)1021 public static String rotationToString(int rotation) { 1022 switch (rotation) { 1023 case Surface.ROTATION_0: { 1024 return "ROTATION_0"; 1025 } 1026 case Surface.ROTATION_90: { 1027 return "ROTATION_90"; 1028 } 1029 case Surface.ROTATION_180: { 1030 return "ROTATION_180"; 1031 } 1032 case Surface.ROTATION_270: { 1033 return "ROTATION_270"; 1034 } 1035 default: { 1036 return Integer.toString(rotation); 1037 } 1038 } 1039 } 1040 1041 /** 1042 * A Canvas class that can handle the compatibility mode. 1043 * This does two things differently. 1044 * <ul> 1045 * <li>Returns the width and height of the target metrics, rather than 1046 * native. For example, the canvas returns 320x480 even if an app is running 1047 * in WVGA high density. 1048 * <li>Scales the matrix in setMatrix by the application scale, except if 1049 * the matrix looks like obtained from getMatrix. This is a hack to handle 1050 * the case that an application uses getMatrix to keep the original matrix, 1051 * set matrix of its own, then set the original matrix back. There is no 1052 * perfect solution that works for all cases, and there are a lot of cases 1053 * that this model does not work, but we hope this works for many apps. 1054 * </ul> 1055 */ 1056 private final class CompatibleCanvas extends Canvas { 1057 // A temp matrix to remember what an application obtained via {@link getMatrix} 1058 private Matrix mOrigMatrix = null; 1059 1060 @Override setMatrix(Matrix matrix)1061 public void setMatrix(Matrix matrix) { 1062 if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) { 1063 // don't scale the matrix if it's not compatibility mode, or 1064 // the matrix was obtained from getMatrix. 1065 super.setMatrix(matrix); 1066 } else { 1067 Matrix m = new Matrix(mCompatibleMatrix); 1068 m.preConcat(matrix); 1069 super.setMatrix(m); 1070 } 1071 } 1072 1073 @SuppressWarnings("deprecation") 1074 @Override getMatrix(Matrix m)1075 public void getMatrix(Matrix m) { 1076 super.getMatrix(m); 1077 if (mOrigMatrix == null) { 1078 mOrigMatrix = new Matrix(); 1079 } 1080 mOrigMatrix.set(m); 1081 } 1082 } 1083 1084 private final class HwuiContext { 1085 private final RenderNode mRenderNode; 1086 private HardwareRenderer mHardwareRenderer; 1087 private RecordingCanvas mCanvas; 1088 private final boolean mIsWideColorGamut; 1089 HwuiContext(boolean isWideColorGamut)1090 HwuiContext(boolean isWideColorGamut) { 1091 mRenderNode = RenderNode.create("HwuiCanvas", null); 1092 mRenderNode.setClipToBounds(false); 1093 mRenderNode.setForceDarkAllowed(false); 1094 mIsWideColorGamut = isWideColorGamut; 1095 1096 mHardwareRenderer = new HardwareRenderer(); 1097 mHardwareRenderer.setContentRoot(mRenderNode); 1098 mHardwareRenderer.setSurface(Surface.this, true); 1099 mHardwareRenderer.setColorMode( 1100 isWideColorGamut 1101 ? ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT 1102 : ActivityInfo.COLOR_MODE_DEFAULT); 1103 mHardwareRenderer.setLightSourceAlpha(0.0f, 0.0f); 1104 mHardwareRenderer.setLightSourceGeometry(0.0f, 0.0f, 0.0f, 0.0f); 1105 } 1106 lockCanvas(int width, int height)1107 Canvas lockCanvas(int width, int height) { 1108 if (mCanvas != null) { 1109 throw new IllegalStateException("Surface was already locked!"); 1110 } 1111 mCanvas = mRenderNode.beginRecording(width, height); 1112 return mCanvas; 1113 } 1114 unlockAndPost(Canvas canvas)1115 void unlockAndPost(Canvas canvas) { 1116 if (canvas != mCanvas) { 1117 throw new IllegalArgumentException("canvas object must be the same instance that " 1118 + "was previously returned by lockCanvas"); 1119 } 1120 mRenderNode.endRecording(); 1121 mCanvas = null; 1122 mHardwareRenderer.createRenderRequest() 1123 .setVsyncTime(System.nanoTime()) 1124 .syncAndDraw(); 1125 } 1126 updateSurface()1127 void updateSurface() { 1128 mHardwareRenderer.setSurface(Surface.this, true); 1129 } 1130 destroy()1131 void destroy() { 1132 mHardwareRenderer.destroy(); 1133 } 1134 isWideColorGamut()1135 boolean isWideColorGamut() { 1136 return mIsWideColorGamut; 1137 } 1138 } 1139 } 1140