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 17 package com.android.systemui.bluetooth.qsdialog 18 19 import androidx.annotation.StringRes 20 import com.android.settingslib.bluetooth.BluetoothUtils 21 import com.android.settingslib.bluetooth.LocalBluetoothManager 22 import com.android.systemui.dagger.SysUISingleton 23 import com.android.systemui.dagger.qualifiers.Application 24 import com.android.systemui.dagger.qualifiers.Background 25 import com.android.systemui.res.R 26 import javax.inject.Inject 27 import kotlinx.coroutines.CoroutineDispatcher 28 import kotlinx.coroutines.CoroutineScope 29 import kotlinx.coroutines.flow.Flow 30 import kotlinx.coroutines.flow.SharingStarted 31 import kotlinx.coroutines.flow.combine 32 import kotlinx.coroutines.flow.flowOn 33 import kotlinx.coroutines.flow.stateIn 34 35 internal sealed class AudioSharingButtonState { 36 object Gone : AudioSharingButtonState() 37 data class Visible(@StringRes val resId: Int) : AudioSharingButtonState() 38 } 39 40 /** Holds business logic for the audio sharing state. */ 41 @SysUISingleton 42 internal class AudioSharingInteractor 43 @Inject 44 constructor( 45 private val localBluetoothManager: LocalBluetoothManager?, 46 bluetoothStateInteractor: BluetoothStateInteractor, 47 deviceItemInteractor: DeviceItemInteractor, 48 @Application private val coroutineScope: CoroutineScope, 49 @Background private val backgroundDispatcher: CoroutineDispatcher, 50 ) { 51 /** Flow representing the update of AudioSharingButtonState. */ 52 internal val audioSharingButtonStateUpdate: Flow<AudioSharingButtonState> = 53 combine( 54 bluetoothStateInteractor.bluetoothStateUpdate, 55 deviceItemInteractor.deviceItemUpdate bluetoothStatenull56 ) { bluetoothState, deviceItem -> 57 getButtonState(bluetoothState, deviceItem) 58 } 59 .flowOn(backgroundDispatcher) 60 .stateIn( 61 coroutineScope, 62 SharingStarted.WhileSubscribed(replayExpirationMillis = 0), 63 initialValue = AudioSharingButtonState.Gone 64 ) 65 getButtonStatenull66 private fun getButtonState( 67 bluetoothState: Boolean, 68 deviceItem: List<DeviceItem> 69 ): AudioSharingButtonState { 70 return when { 71 // Don't show button when bluetooth is off 72 !bluetoothState -> AudioSharingButtonState.Gone 73 // Show sharing audio when broadcasting 74 BluetoothUtils.isBroadcasting(localBluetoothManager) -> 75 AudioSharingButtonState.Visible( 76 R.string.quick_settings_bluetooth_audio_sharing_button_sharing 77 ) 78 // When not broadcasting, don't show button if there's connected source in any device 79 deviceItem.any { 80 BluetoothUtils.hasConnectedBroadcastSource( 81 it.cachedBluetoothDevice, 82 localBluetoothManager 83 ) 84 } -> AudioSharingButtonState.Gone 85 // Show audio sharing when there's a connected LE audio device 86 deviceItem.any { BluetoothUtils.isActiveLeAudioDevice(it.cachedBluetoothDevice) } -> 87 AudioSharingButtonState.Visible( 88 R.string.quick_settings_bluetooth_audio_sharing_button 89 ) 90 else -> AudioSharingButtonState.Gone 91 } 92 } 93 } 94