1 /*
<lambda>null2  * Copyright (C) 2023 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 package com.android.cts.mockime
17 
18 import android.os.Bundle
19 import android.os.RemoteCallback
20 import java.util.function.Consumer
21 import kotlinx.atomicfu.atomic
22 
23 class SessionChannel(private var mEstablishedCallback: Runnable) : AutoCloseable {
24     private val listeners = mutableListOf<Consumer<Bundle>>()
25     private val remote = atomic<RemoteCallback?>(null)
26     private var local: RemoteCallback? = RemoteCallback { bundle ->
27         checkNotNull(bundle)
28         if (bundle.containsKey(ESTABLISH_KEY)) {
29             val remote = bundle.getParcelable(ESTABLISH_KEY, RemoteCallback::class.java)!!
30             check(this.remote.getAndSet(remote) == null) {
31                 "already initialized"
32             }
33             mEstablishedCallback.run()
34             mEstablishedCallback = Runnable {}
35         } else {
36             listeners.forEach { listener ->
37                 listener.accept(bundle)
38             }
39         }
40     }
41 
42     constructor(transport: RemoteCallback) : this({}) {
43         this.remote.value = transport
44         send(Bundle().apply {
45             putParcelable(ESTABLISH_KEY, takeTransport())
46         })
47     }
48 
49     fun takeTransport(): RemoteCallback {
50         val taken = checkNotNull(local) { "Can only take transport once" }
51         local = null
52         return taken
53     }
54 
55     fun send(bundle: Bundle): Boolean {
56         val remote = remote.value ?: run {
57             return false
58         }
59         remote.sendResult(bundle)
60         return true
61     }
62 
63     fun registerListener(listener: Consumer<Bundle>) {
64         listeners.add(listener)
65     }
66 
67     fun unregisterListener(listener: Consumer<Bundle>) {
68         listeners.remove(listener)
69     }
70 
71     override fun close() {
72         remote.value = null
73         listeners.clear()
74     }
75 
76     companion object {
77         val ESTABLISH_KEY = SessionChannel::class.qualifiedName
78     }
79 }
80