1 /* 2 * Copyright 2021 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 androidx.graphics.surface 18 19 import android.graphics.Rect 20 import android.graphics.Region 21 import android.hardware.HardwareBuffer 22 import android.os.Build 23 import android.view.Surface 24 import android.view.SurfaceControl 25 import androidx.annotation.RequiresApi 26 import androidx.graphics.utils.JniVisible 27 import androidx.hardware.SyncFenceV19 28 import java.util.concurrent.Executor 29 30 @JniVisible 31 internal class JniBindings { 32 companion object { nCreatenull33 @JvmStatic @JniVisible external fun nCreate(surfaceControl: Long, debugName: String): Long 34 35 @JvmStatic 36 @JniVisible 37 external fun nCreateFromSurface(surface: Surface, debugName: String): Long 38 39 @JvmStatic @JniVisible external fun nRelease(surfaceControl: Long) 40 41 @JvmStatic @JniVisible external fun nTransactionCreate(): Long 42 43 @JvmStatic @JniVisible external fun nTransactionDelete(surfaceTransaction: Long) 44 45 @JvmStatic @JniVisible external fun nTransactionApply(surfaceTransaction: Long) 46 47 @JvmStatic 48 @JniVisible 49 external fun nTransactionReparent( 50 surfaceTransaction: Long, 51 surfaceControl: Long, 52 newParent: Long 53 ) 54 55 @JvmStatic 56 @JniVisible 57 external fun nTransactionSetOnComplete( 58 surfaceTransaction: Long, 59 listener: SurfaceControlCompat.TransactionCompletedListener 60 ) 61 62 @JvmStatic 63 @JniVisible 64 external fun nTransactionSetOnCommit( 65 surfaceTransaction: Long, 66 listener: SurfaceControlCompat.TransactionCommittedListener 67 ) 68 69 @JvmStatic @JniVisible external fun nDupFenceFd(syncFence: SyncFenceV19): Int 70 71 @JvmStatic 72 @JniVisible 73 external fun nSetBuffer( 74 surfaceTransaction: Long, 75 surfaceControl: Long, 76 hardwareBuffer: HardwareBuffer?, 77 acquireFieldFd: SyncFenceV19 78 ) 79 80 @JvmStatic 81 @JniVisible 82 external fun nSetGeometry( 83 surfaceTransaction: Long, 84 surfaceControl: Long, 85 bufferWidth: Int, 86 bufferHeight: Int, 87 dstWidth: Int, 88 dstHeight: Int, 89 transformation: Int 90 ) 91 92 @JvmStatic 93 @JniVisible 94 external fun nSetVisibility( 95 surfaceTransaction: Long, 96 surfaceControl: Long, 97 visibility: Byte 98 ) 99 100 @JvmStatic 101 @JniVisible 102 external fun nSetZOrder(surfaceTransaction: Long, surfaceControl: Long, zOrder: Int) 103 104 @JvmStatic 105 @JniVisible 106 external fun nSetDamageRegion(surfaceTransaction: Long, surfaceControl: Long, rect: Rect?) 107 108 @JvmStatic 109 @JniVisible 110 external fun nSetDesiredPresentTime(surfaceTransaction: Long, desiredPresentTime: Long) 111 112 @JvmStatic 113 @JniVisible 114 external fun nSetBufferTransparency( 115 surfaceTransaction: Long, 116 surfaceControl: Long, 117 transparency: Byte, 118 ) 119 120 @JvmStatic 121 @JniVisible 122 external fun nSetBufferAlpha(surfaceTransaction: Long, surfaceControl: Long, alpha: Float) 123 124 @JvmStatic 125 @JniVisible 126 external fun nSetCrop( 127 surfaceTransaction: Long, 128 surfaceControl: Long, 129 left: Int, 130 top: Int, 131 right: Int, 132 bottom: Int 133 ) 134 135 @JvmStatic 136 @JniVisible 137 external fun nSetPosition( 138 surfaceTransaction: Long, 139 surfaceControl: Long, 140 x: Float, 141 y: Float 142 ) 143 144 @JvmStatic 145 @JniVisible 146 external fun nSetScale( 147 surfaceTransaction: Long, 148 surfaceControl: Long, 149 scaleX: Float, 150 scaleY: Float 151 ) 152 153 @JvmStatic 154 @JniVisible 155 external fun nSetBufferTransform( 156 surfaceTransaction: Long, 157 surfaceControl: Long, 158 transformation: Int 159 ) 160 161 @JvmStatic 162 @JniVisible 163 external fun nSetDataSpace(surfaceTransaction: Long, surfaceControl: Long, dataSpace: Int) 164 165 @JvmStatic @JniVisible external fun nGetDisplayOrientation(): String 166 167 @JvmStatic @JniVisible external fun nIsHwuiUsingVulkanRenderer(): Boolean 168 169 @JvmStatic 170 @JniVisible 171 external fun nGetPreviousReleaseFenceFd(surfaceControl: Long, transactionStats: Long): Int 172 173 @JvmStatic 174 @JniVisible 175 external fun nSetFrameRate( 176 surfaceTransaction: Long, 177 surfaceControl: Long, 178 frameRate: Float, 179 compatibility: Int, 180 changeFrameRateStrategy: Int 181 ) 182 183 init { 184 System.loadLibrary("graphics-core") 185 } 186 } 187 } 188 189 /** 190 * Handle to an on-screen Surface managed by the system compositor. By constructing a [Surface] from 191 * this [SurfaceControlWrapper] you can submit buffers to be composited. Using 192 * [SurfaceControlWrapper.Transaction] you can manipulate various properties of how the buffer will 193 * be displayed on-screen. SurfaceControls are arranged into a scene-graph like hierarchy, and as 194 * such any SurfaceControl may have a parent. Geometric properties like transform, crop, and 195 * Z-ordering will be inherited from the parent, as if the child were content in the parents buffer 196 * stream. 197 * 198 * Compatibility class for [SurfaceControl]. This differs by being built upon the equivalent API 199 * within the Android NDK. It introduces some APIs into earlier platform releases than what was 200 * initially exposed for SurfaceControl. 201 */ 202 @RequiresApi(Build.VERSION_CODES.Q) 203 internal class SurfaceControlWrapper { 204 205 constructor(surfaceControl: SurfaceControlWrapper, debugName: String) { 206 mNativeSurfaceControl = JniBindings.nCreate(surfaceControl.mNativeSurfaceControl, debugName) 207 if (mNativeSurfaceControl == 0L) { 208 throw IllegalArgumentException() 209 } 210 } 211 212 constructor(surface: Surface, debugName: String) { 213 mNativeSurfaceControl = JniBindings.nCreateFromSurface(surface, debugName) 214 if (mNativeSurfaceControl == 0L) { 215 throw IllegalArgumentException() 216 } 217 } 218 219 internal var mNativeSurfaceControl: Long = 0 220 221 /** Compatibility class for ASurfaceTransaction. */ 222 class Transaction() { 223 private var mNativeSurfaceTransaction: Long 224 225 init { 226 mNativeSurfaceTransaction = JniBindings.nTransactionCreate() 227 if (mNativeSurfaceTransaction == 0L) { 228 throw java.lang.IllegalArgumentException() 229 } 230 } 231 232 /** 233 * Commits the updates accumulated in this transaction. 234 * 235 * This is the equivalent of ASurfaceTransaction_apply. 236 * 237 * Note that the transaction is guaranteed to be applied atomically. The transactions which 238 * are applied on the same thread are als guaranteed to be applied in order. 239 */ commitnull240 fun commit() { 241 JniBindings.nTransactionApply(mNativeSurfaceTransaction) 242 } 243 244 // Suppression of PairedRegistration below is in order to match existing 245 // framework implementation of no remove method for listeners 246 247 /** 248 * Sets the callback that is invoked once the updates from this transaction are presented. 249 * 250 * @param listener The callback that will be invoked when the transaction has been 251 * completed. This value cannot be null. 252 */ 253 @Suppress("PairedRegistration") addTransactionCompletedListenernull254 internal fun addTransactionCompletedListener( 255 listener: SurfaceControlCompat.TransactionCompletedListener 256 ): Transaction { 257 JniBindings.nTransactionSetOnComplete(mNativeSurfaceTransaction, listener) 258 return this 259 } 260 261 /** 262 * Sets the callback that is invoked once the updates from this transaction are applied and 263 * ready to be presented. This callback is invoked before the setOnCompleteListener 264 * callback. 265 * 266 * @param executor The executor that the callback should be invoked on. This value can be 267 * null, where it will run on the default thread. Callback and listener events are 268 * dispatched through this Executor, providing an easy way to control which thread is 269 * used. 270 * @param listener The callback that will be invoked when the transaction has been 271 * completed. This value cannot be null. 272 */ 273 @RequiresApi(Build.VERSION_CODES.S) 274 @Suppress("PairedRegistration") addTransactionCommittedListenernull275 fun addTransactionCommittedListener( 276 executor: Executor?, 277 listener: SurfaceControlCompat.TransactionCommittedListener 278 ): Transaction { 279 var listenerWrapper = listener 280 if (executor != null) { 281 listenerWrapper = 282 object : SurfaceControlCompat.TransactionCommittedListener { 283 override fun onTransactionCommitted() { 284 executor.execute { (listener::onTransactionCommitted)() } 285 } 286 } 287 } 288 JniBindings.nTransactionSetOnCommit(mNativeSurfaceTransaction, listenerWrapper) 289 return this 290 } 291 292 /** 293 * Updates the [HardwareBuffer] displayed for the provided surfaceControl. Takes an optional 294 * [SyncFenceV19] that is signalled when all pending work for the buffer is complete and the 295 * buffer can be safely read. 296 * 297 * The frameworks takes ownership of the syncFence passed and is responsible for closing it. 298 * 299 * Note that the buffer must be allocated with [HardwareBuffer.USAGE_COMPOSER_OVERLAY] and 300 * [HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE] as the surface control might be composited using 301 * an overlay or the GPU. 302 * 303 * @param surfaceControl The surfaceControl to update. Can not be null. 304 * @param hardwareBuffer The buffer to be displayed. This can not be null. 305 * @param syncFence The presentation fence. If null or invalid, this is equivalent to not 306 * including it. 307 */ 308 @JvmOverloads setBuffernull309 fun setBuffer( 310 surfaceControl: SurfaceControlWrapper, 311 hardwareBuffer: HardwareBuffer?, 312 syncFence: SyncFenceV19 = SyncFenceV19(-1) 313 ): Transaction { 314 JniBindings.nSetBuffer( 315 mNativeSurfaceTransaction, 316 surfaceControl.mNativeSurfaceControl, 317 hardwareBuffer, 318 syncFence 319 ) 320 return this 321 } 322 323 /** See [SurfaceControlCompat.Transaction.setDataSpace] */ setDataSpacenull324 fun setDataSpace(surfaceControl: SurfaceControlWrapper, dataSpace: Int): Transaction { 325 JniBindings.nSetDataSpace( 326 mNativeSurfaceTransaction, 327 surfaceControl.mNativeSurfaceControl, 328 dataSpace 329 ) 330 return this 331 } 332 333 /** 334 * Updates the visibility of the given [SurfaceControlWrapper]. If visibility is set to 335 * false, the [SurfaceControlWrapper] and all surfaces in the subtree will be hidden. By 336 * default SurfaceControls are visible. 337 * 338 * @param surfaceControl The SurfaceControl for which to set the visibility This value 339 * cannot be null. 340 * @param visibility the new visibility. A value of true means the surface and its children 341 * will be visible. 342 */ setVisibilitynull343 fun setVisibility(surfaceControl: SurfaceControlWrapper, visibility: Boolean): Transaction { 344 JniBindings.nSetVisibility( 345 mNativeSurfaceTransaction, 346 surfaceControl.mNativeSurfaceControl, 347 if (visibility) 1 else 0 348 ) 349 return this 350 } 351 352 /** 353 * Updates z order index for [SurfaceControlWrapper]. Note that the z order for a surface is 354 * relative to other surfaces that are siblings of this surface. Behavior of siblings with 355 * the same z order is undefined. 356 * 357 * Z orders can range from Integer.MIN_VALUE to Integer.MAX_VALUE. Default z order index 358 * is 0. [SurfaceControlWrapper] instances are positioned back-to-front. That is lower z 359 * order values are rendered below other [SurfaceControlWrapper] instances with higher z 360 * order values. 361 * 362 * @param surfaceControl surface control to set the z order of. 363 * @param zOrder desired layer z order to set the surfaceControl. 364 */ setLayernull365 fun setLayer(surfaceControl: SurfaceControlWrapper, zOrder: Int): Transaction { 366 JniBindings.nSetZOrder( 367 mNativeSurfaceTransaction, 368 surfaceControl.mNativeSurfaceControl, 369 zOrder 370 ) 371 return this 372 } 373 374 /** 375 * Updates the region for content on this surface updated in this transaction. If 376 * unspecified, the complete surface will be assumed to be damaged. The damage region is the 377 * area of the buffer that has changed since the previously sent buffer. This can be used to 378 * reduce the amount of recomposition that needs to happen when only a small region of the 379 * buffer is being updated, such as for a small blinking cursor or a loading indicator. 380 * 381 * @param surfaceControl The surface control for which we want to set the damage region of. 382 * @param region The region to set. If null, the entire buffer is assumed dirty. This is 383 * equivalent to not setting a damage region at all. 384 */ setDamageRegionnull385 fun setDamageRegion(surfaceControl: SurfaceControlWrapper, region: Region?): Transaction { 386 JniBindings.nSetDamageRegion( 387 mNativeSurfaceTransaction, 388 surfaceControl.mNativeSurfaceControl, 389 region?.bounds 390 ) 391 return this 392 } 393 394 /** 395 * Re-parents a given layer to a new parent. Children inherit transform (position, scaling) 396 * crop, visibility, and Z-ordering from their parents, as if the children were pixels 397 * within the parent Surface. 398 * 399 * Any children of the reparented surfaceControl will remain children of the surfaceControl. 400 * 401 * The newParent can be null. Surface controls with a null parent do not appear on the 402 * display. 403 * 404 * @param surfaceControl The surface control to reparent 405 * @param newParent the new parent we want to set the surface control to. Can be null. 406 */ reparentnull407 fun reparent( 408 surfaceControl: SurfaceControlWrapper, 409 newParent: SurfaceControlWrapper? 410 ): Transaction { 411 JniBindings.nTransactionReparent( 412 mNativeSurfaceTransaction, 413 surfaceControl.mNativeSurfaceControl, 414 newParent?.mNativeSurfaceControl ?: 0L 415 ) 416 return this 417 } 418 419 /** 420 * Specifies a desiredPresentTime for the transaction. The framework will try to present the 421 * transaction at or after the time specified. 422 * 423 * Transactions will not be presented until all acquire fences have signaled even if the app 424 * requests an earlier present time. 425 * 426 * If an earlier transaction has a desired present time of x, and a later transaction has a 427 * desired present time that is before x, the later transaction will not preempt the earlier 428 * transaction. 429 * 430 * @param desiredPresentTimeNano The present time in nanoseconds to try to present the 431 * Transaction at. 432 */ setDesiredPresentTimenull433 fun setDesiredPresentTime(desiredPresentTimeNano: Long): Transaction { 434 JniBindings.nSetDesiredPresentTime(mNativeSurfaceTransaction, desiredPresentTimeNano) 435 return this 436 } 437 438 /** 439 * Update whether the content in the buffer associated with this surface is completely 440 * opaque. If true, every pixel of content in the buffer must be opaque or visual errors can 441 * occur. 442 * 443 * @param surfaceControl surface control to set the transparency of. 444 * @param isOpaque true if buffers alpha should be ignored 445 */ setOpaquenull446 fun setOpaque(surfaceControl: SurfaceControlWrapper, isOpaque: Boolean): Transaction { 447 JniBindings.nSetBufferTransparency( 448 mNativeSurfaceTransaction, 449 surfaceControl.mNativeSurfaceControl, 450 if (isOpaque) 2 else 0 451 ) 452 return this 453 } 454 455 /** 456 * Sets the alpha for the buffer. It uses a premultiplied blending. 457 * 458 * The passsed in alpha must be inclusively between 0.0 and 1.0. 459 * 460 * @param alpha alpha value within the range [0, 1]. 461 * @throws IllegalArgumentException if alpha is out of range. 462 * @paaram surfaceControl The surface control that we want to set the alpha of. 463 */ setAlphanull464 fun setAlpha(surfaceControl: SurfaceControlWrapper, alpha: Float): Transaction { 465 if (alpha < 0.0f || alpha > 1.0f) { 466 throw IllegalArgumentException("Alpha value must be between 0.0 and 1.0.") 467 } else { 468 JniBindings.nSetBufferAlpha( 469 mNativeSurfaceTransaction, 470 surfaceControl.mNativeSurfaceControl, 471 alpha 472 ) 473 } 474 return this 475 } 476 477 /** 478 * Bounds the surface and its children to the bounds specified. Size of the surface will be 479 * ignored and only the crop and buffer size will be used to determine the bounds of the 480 * surface. If no crop is specified and the surface has no buffer, the surface bounds is 481 * only constrained by the size of its parent bounds. 482 * 483 * @param surfaceControl The [SurfaceControlWrapper] to apply the crop to. This value cannot 484 * be null. 485 * @param crop Bounds of the crop to apply. This value can be null. A null value will remove 486 * the crop and bounds are determined via bounds of the parent surface. 487 * @throws IllegalArgumentException if crop is not a valid rectangle. 488 */ 489 @RequiresApi(Build.VERSION_CODES.S) setCropnull490 fun setCrop(surfaceControl: SurfaceControlWrapper, crop: Rect?): Transaction { 491 require((crop == null) || (crop.width() >= 0 && crop.height() >= 0)) { 492 throw IllegalArgumentException("width and height must be non-negative") 493 } 494 if (crop == null) { 495 JniBindings.nSetCrop( 496 mNativeSurfaceTransaction, 497 surfaceControl.mNativeSurfaceControl, 498 0, 499 0, 500 0, 501 0 502 ) 503 } else { 504 JniBindings.nSetCrop( 505 mNativeSurfaceTransaction, 506 surfaceControl.mNativeSurfaceControl, 507 crop.left, 508 crop.top, 509 crop.right, 510 crop.bottom 511 ) 512 } 513 514 return this 515 } 516 517 /** 518 * Sets the SurfaceControl to the specified position relative to the parent SurfaceControl 519 * 520 * @param surfaceControl The [SurfaceControlWrapper] to change position. This value cannot 521 * be null 522 * @param x the X position 523 * @param y the Y position 524 */ 525 @RequiresApi(Build.VERSION_CODES.S) setPositionnull526 fun setPosition(surfaceControl: SurfaceControlWrapper, x: Float, y: Float): Transaction { 527 JniBindings.nSetPosition( 528 mNativeSurfaceTransaction, 529 surfaceControl.mNativeSurfaceControl, 530 x, 531 y 532 ) 533 return this 534 } 535 536 /** 537 * Sets the SurfaceControl to the specified scale with (0, 0) as the center point of the 538 * scale. 539 * 540 * @param surfaceControl The [SurfaceControlWrapper] to change scale. This value cannot be 541 * null. 542 * @param scaleX the X scale 543 * @param scaleY the Y scale 544 */ 545 @RequiresApi(Build.VERSION_CODES.S) setScalenull546 fun setScale( 547 surfaceControl: SurfaceControlWrapper, 548 scaleX: Float, 549 scaleY: Float 550 ): Transaction { 551 JniBindings.nSetScale( 552 mNativeSurfaceTransaction, 553 surfaceControl.mNativeSurfaceControl, 554 scaleX, 555 scaleY 556 ) 557 return this 558 } 559 560 /** 561 * Sets the buffer transform that should be applied to the current buffer 562 * 563 * @param surfaceControl the [SurfaceControlWrapper] to update. This value cannot be null. 564 * @param transformation The transform to apply to the buffer. Value is 565 * [SurfaceControlCompat.BUFFER_TRANSFORM_IDENTITY], 566 * [SurfaceControlCompat.BUFFER_TRANSFORM_MIRROR_HORIZONTAL], 567 * [SurfaceControlCompat.BUFFER_TRANSFORM_MIRROR_VERTICAL], 568 * [SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_90], 569 * [SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_180], 570 * [SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_270], 571 * [SurfaceControlCompat.BUFFER_TRANSFORM_MIRROR_HORIZONTAL] | 572 * [SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_90], or 573 * [SurfaceControlCompat.BUFFER_TRANSFORM_MIRROR_VERTICAL] | 574 * [SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_90] 575 */ 576 @RequiresApi(Build.VERSION_CODES.S) setBufferTransformnull577 fun setBufferTransform( 578 surfaceControl: SurfaceControlWrapper, 579 transformation: Int 580 ): Transaction { 581 JniBindings.nSetBufferTransform( 582 mNativeSurfaceTransaction, 583 surfaceControl.mNativeSurfaceControl, 584 transformation 585 ) 586 return this 587 } 588 setGeometrynull589 fun setGeometry( 590 surfaceControl: SurfaceControlWrapper, 591 width: Int, 592 height: Int, 593 dstWidth: Int, 594 dstHeight: Int, 595 transformation: Int 596 ): Transaction { 597 JniBindings.nSetGeometry( 598 mNativeSurfaceTransaction, 599 surfaceControl.mNativeSurfaceControl, 600 width, 601 height, 602 dstWidth, 603 dstHeight, 604 transformation 605 ) 606 return this 607 } 608 setFrameRatenull609 fun setFrameRate( 610 surfaceControl: SurfaceControlWrapper, 611 frameRate: Float, 612 compatibility: Int, 613 changeFrameRateStrategy: Int 614 ): Transaction { 615 JniBindings.nSetFrameRate( 616 mNativeSurfaceTransaction, 617 surfaceControl.mNativeSurfaceControl, 618 frameRate, 619 compatibility, 620 changeFrameRateStrategy 621 ) 622 return this 623 } 624 625 /** Destroys the transaction object. */ closenull626 fun close() { 627 if (mNativeSurfaceTransaction != 0L) { 628 JniBindings.nTransactionDelete(mNativeSurfaceTransaction) 629 mNativeSurfaceTransaction = 0L 630 } 631 } 632 finalizenull633 fun finalize() { 634 close() 635 } 636 } 637 638 /** Check whether this instance points to a valid layer with the system-compositor. */ isValidnull639 fun isValid(): Boolean = mNativeSurfaceControl != 0L 640 641 override fun equals(other: Any?): Boolean { 642 if (other == this) { 643 return true 644 } 645 if ((other == null) or (other?.javaClass != SurfaceControlWrapper::class.java)) { 646 return false 647 } 648 649 other as SurfaceControlWrapper 650 if (other.mNativeSurfaceControl == this.mNativeSurfaceControl) { 651 return true 652 } 653 654 return false 655 } 656 hashCodenull657 override fun hashCode(): Int { 658 return mNativeSurfaceControl.hashCode() 659 } 660 661 /** 662 * Release the local reference to the server-side surface. The surface may continue to exist 663 * on-screen as long as its parent continues to exist. To explicitly remove a surface from the 664 * screen use [Transaction.reparent] with a null-parent. After release, [isValid] will return 665 * false and other methods will throw an exception. Always call release() when you're done with 666 * a SurfaceControl. 667 */ releasenull668 fun release() { 669 if (mNativeSurfaceControl != 0L) { 670 JniBindings.nRelease(mNativeSurfaceControl) 671 mNativeSurfaceControl = 0 672 } 673 } 674 finalizenull675 protected fun finalize() { 676 release() 677 } 678 679 /** 680 * Builder class for [SurfaceControlWrapper]. 681 * 682 * Requires a debug name. 683 */ 684 class Builder { 685 private var mSurface: Surface? = null 686 private var mSurfaceControl: SurfaceControlWrapper? = null 687 private lateinit var mDebugName: String 688 setParentnull689 fun setParent(surface: Surface): Builder { 690 mSurface = surface 691 mSurfaceControl = null 692 return this 693 } 694 setParentnull695 fun setParent(surfaceControlWrapper: SurfaceControlWrapper): Builder { 696 mSurface = null 697 mSurfaceControl = surfaceControlWrapper 698 return this 699 } 700 701 @Suppress("MissingGetterMatchingBuilder") setDebugNamenull702 fun setDebugName(debugName: String): Builder { 703 mDebugName = debugName 704 return this 705 } 706 707 /** Builds the [SurfaceControlWrapper] object */ buildnull708 fun build(): SurfaceControlWrapper { 709 val surface = mSurface 710 val surfaceControl = mSurfaceControl 711 return if (surface != null) { 712 SurfaceControlWrapper(surface, mDebugName) 713 } else if (surfaceControl != null) { 714 SurfaceControlWrapper(surfaceControl, mDebugName) 715 } else { 716 throw IllegalStateException("") 717 } 718 } 719 } 720 } 721