How to check bluetooth headset(A2DP) connection
I am developing karaoke app. In this app, I need to check whether bluetooth headset is connected.
In case of bluetooth headset connection, users can hear their voice.
It is a little bit annoying to implement checking out bluetooth headset connection. Becasue there are so many Intent.action which we choose.
In short, I use BluetoothDevice.ACTIONACL_DISCONNECTED and BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.
class SoundDeviceConnectManager @Inject constructor(val mApplicationContext: Context) {
val TAG = SoundDeviceConnectManager::class.java.simpleName
private val _a2dpProfileState = MutableStateFlow(false) //1
val a2dpProfileState : StateFlow<Boolean> = _a2dpProfileState
private val _bluetoothHeadsetStateFlow = MutableStateFlow<Boolean>(false) //2
val bluetoothHeadsetStateFlow: StateFlow<Boolean> = _bluetoothHeadsetStateFlow
private val _wiredHeadsetStateFlow = MutableStateFlow<Boolean>(false) //3
val wiredHeadsetStateFlow: StateFlow<Boolean> = _wiredHeadsetStateFlow
private val wireHeadsetConnectionBroadcastReceiver by lazy { WireHeadsetConnectionBroadcastReceiver() } //4
private val bluetoothConnectionBroadcastReceiver by lazy { BluetoothConnectionBroadcastReceiver() } //5
private val bluetoothManager by lazy { mApplicationContext.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager }
fun onCreate() {
Log.d(TAG, "onCreate")
monitorBluetoothHeadsetConnection()
monitorBluetoothHeadsetConnection2()
monitorWiredHeadsetConnection()
}
private fun monitorBluetoothHeadsetConnection() { //6
val callback = object : BluetoothProfile.ServiceListener {
override fun onServiceConnected(profile: Int, proxy: BluetoothProfile?) {
Log.d(TAG, "BluetoothProfile Connected, profile: $profile, proxy: ${proxy ?: "null"}")
proxy?.connectedDevices?.size?.let {
Log.d(TAG, "onServiceConnected, connectedDevices: $it")
if(it > 0) _a2dpProfileState.value = true
}
}
override fun onServiceDisconnected(proxy: Int) {
Log.d(TAG, "BluetoothProfile Disconnected, proxy: $proxy")
_a2dpProfileState.value = false
}
}
bluetoothManager.adapter.getProfileProxy(
mApplicationContext,
callback,
BluetoothProfile.A2DP
)
}
private fun monitorBluetoothHeadsetConnection2() { //7
val intentFilter = IntentFilter().apply {
// addAction(BluetoothDevice.ACTION_ACL_CONNECTED)
addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED)
// addAction(BluetoothAdapter.ACTION_STATE_CHANGED)
addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)
}
mApplicationContext.registerReceiver(bluetoothConnectionBroadcastReceiver, intentFilter)
}
private fun monitorWiredHeadsetConnection() { //8
val intentFilter = IntentFilter().apply { addAction(Intent.ACTION_HEADSET_PLUG) }
mApplicationContext.registerReceiver(wireHeadsetConnectionBroadcastReceiver, intentFilter)
}
fun onDestroy() {
mApplicationContext.unregisterReceiver(wireHeadsetConnectionBroadcastReceiver)
mApplicationContext.unregisterReceiver(bluetoothConnectionBroadcastReceiver)
bluetoothManager.adapter.getProfileProxy(mApplicationContext, null, -1)
}
private inner class WireHeadsetConnectionBroadcastReceiver : BroadcastReceiver() { //9
override fun onReceive(context: Context?, intent: Intent?) {
val action = intent?.action
Log.d(TAG, "WireHeadsetConnectionBroadcastReceiver onReceive, action: $action")
action?.let {
if (it == Intent.ACTION_HEADSET_PLUG) {
val state = intent.getIntExtra("state", -1)
_wiredHeadsetStateFlow.value = state == 1
}
}
}
}
private inner class BluetoothConnectionBroadcastReceiver : BroadcastReceiver() { //10
override fun onReceive(context: Context?, intent: Intent?) {
val action = intent?.action
Log.d(TAG, "action: $action")
if(action == BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED || action == BluetoothDevice.ACTION_ACL_DISCONNECTED) {
val device = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
val method = device?.javaClass?.getMethod("isConnected")
val isConnected = method?.invoke(device)
Log.d(TAG, "BluetoothConnectionBroadcastReceiver onReceive, isConnected: $isConnected")
_bluetoothHeadsetStateFlow.value = isConnected as Boolean
}
}
}
}
1 => MutableStateFlow to save connection state of a2dp Profile.
2 => MutableStateFlow to save connection state of BluetoothHeadset
3 => MutableStateFlow to save connection state of wired headset.
4 => BroadcastReceiver which receive connection state of wired headset.
5 => BroadcastReceiver which receive connection state of Bluetooth
6 => Register BluetoothProfile.ServiceListener on BluetoothManager's Profile proxy
When BluetoothHeadset is registered at your device, you can get connectedDevices which is larger than 0.
7 => Register broadcastReceiver to receive bluetoothConnection state.
I didn't add BluetoothDevice.ACTION_ACL_CONNECTED and BluetoothAdapter.ACTION_STATE_CHANGED.
Because it is adequate to check bluetooth connected event by BluetoothProfile.ServiceListener.
8 => Register broadcastReceiver to receive wired headset connection state.
9 => Define BroadcastReceiver to check connection of wired headset.
10 => Define BroadcastReceiver to check connection of bluetooth headset connection.
Then, you can be sure that device is connected with bluetooth headset if isConnectedBluetoothHeadset or isConnectedA2dpProfile is true.
val isConnectedBluetoothHeadset = soundDeviceConnectManager.bluetoothHeadsetStateFlow.value
val isConnectedA2dpProfile = soundDeviceConnectManager.a2dpProfileState.value
Log.d(TAG, "isConnectedBluetoothHeadset: $isConnectedBluetoothHeadset, isConnectedA2dpProfile: $isConnectedA2dpProfile")
if(isConnectedBluetoothHeadset || isConnectedA2dpProfile) {
// device is connected with bluetoothHeadset.
}
댓글 없음:
댓글 쓰기