1 /*
<lambda>null2  * Copyright (C) 2024 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 com.android.settingslib.volume.data.repository
18 
19 import android.bluetooth.BluetoothLeBroadcast
20 import android.bluetooth.BluetoothLeBroadcastMetadata
21 import com.android.internal.util.ConcurrentUtils
22 import com.android.settingslib.bluetooth.LocalBluetoothManager
23 import com.android.settingslib.flags.Flags
24 import kotlin.coroutines.CoroutineContext
25 import kotlinx.coroutines.channels.awaitClose
26 import kotlinx.coroutines.flow.Flow
27 import kotlinx.coroutines.flow.callbackFlow
28 import kotlinx.coroutines.flow.flowOf
29 import kotlinx.coroutines.flow.flowOn
30 import kotlinx.coroutines.flow.onStart
31 import kotlinx.coroutines.launch
32 
33 /** Provides audio sharing functionality. */
34 interface AudioSharingRepository {
35     /** Whether the device is in audio sharing. */
36     val inAudioSharing: Flow<Boolean>
37 }
38 
39 class AudioSharingRepositoryImpl(
40     private val localBluetoothManager: LocalBluetoothManager?,
41     backgroundCoroutineContext: CoroutineContext,
42 ) : AudioSharingRepository {
43     override val inAudioSharing: Flow<Boolean> =
44         if (Flags.enableLeAudioSharing()) {
leBroadcastnull45             localBluetoothManager?.profileManager?.leAudioBroadcastProfile?.let { leBroadcast ->
46                 callbackFlow {
47                         val listener =
48                             object : BluetoothLeBroadcast.Callback {
49                                 override fun onBroadcastStarted(reason: Int, broadcastId: Int) {
50                                     launch { send(isBroadcasting()) }
51                                 }
52 
53                                 override fun onBroadcastStartFailed(reason: Int) {
54                                     launch { send(isBroadcasting()) }
55                                 }
56 
57                                 override fun onBroadcastStopped(reason: Int, broadcastId: Int) {
58                                     launch { send(isBroadcasting()) }
59                                 }
60 
61                                 override fun onBroadcastStopFailed(reason: Int) {
62                                     launch { send(isBroadcasting()) }
63                                 }
64 
65                                 override fun onPlaybackStarted(reason: Int, broadcastId: Int) {}
66 
67                                 override fun onPlaybackStopped(reason: Int, broadcastId: Int) {}
68 
69                                 override fun onBroadcastUpdated(reason: Int, broadcastId: Int) {}
70 
71                                 override fun onBroadcastUpdateFailed(
72                                     reason: Int,
73                                     broadcastId: Int
74                                 ) {}
75 
76                                 override fun onBroadcastMetadataChanged(
77                                     broadcastId: Int,
78                                     metadata: BluetoothLeBroadcastMetadata
79                                 ) {}
80                             }
81 
82                         leBroadcast.registerServiceCallBack(
83                             ConcurrentUtils.DIRECT_EXECUTOR,
84                             listener,
85                         )
86                         awaitClose { leBroadcast.unregisterServiceCallBack(listener) }
87                     }
88                     .onStart { emit(isBroadcasting()) }
89                     .flowOn(backgroundCoroutineContext)
90             } ?: flowOf(false)
91         } else {
92             flowOf(false)
93         }
94 
isBroadcastingnull95     private fun isBroadcasting(): Boolean {
96         return Flags.enableLeAudioSharing() &&
97             (localBluetoothManager?.profileManager?.leAudioBroadcastProfile?.isEnabled(null)
98                 ?: false)
99     }
100 }
101