Development record of developer who study hard everyday.

, ,

How to check bluetooth headset(A2DP) connection

 How to check bluetooth headset(A2DP) connection


android develop blog

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.
}


Share:
Location: 대한민국 서울특별시

댓글 없음:

댓글 쓰기