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