I'm experiencing an issue, where I can connect to bluetooth device once, but after I disconnect, I no longer see that device when scanning for bluetooth devices. If I completely close the app, device is still undiscoverable, but if I turn off the phone, device becomes discoverable again.
I also noticed that this issue is happending on pixel, huawei and xiomi devices, but seems to work on samsung running android 12.
My assumption is, that there's some strange functionality in android 12 that somehow keeps connection alive separately from the app. In my app I call this code to disconnect:
gatt.close()
Are there any other ways I could make sure device is completely disconnected?
EDIT: Calling
bluetoothManager.getConnectedDevices(BluetoothProfile.GATT)
after disconnect and close still returns my connected device.
EDIT2: I'm able to reproduce this issue with following code:
private var gatt: BluetoothGatt? = null
@SuppressLint("MissingPermission")
fun onDeviceClick(macAddress: String) {
logger.i(TAG, "onDeviceClick(macAddress=$macAddress)")
val bluetoothManager: BluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
if (gatt != null) {
logger.i(TAG, "Disconnecting")
gatt?.close()
gatt = null
printConnectedDevices(bluetoothManager)
return
}
printConnectedDevices(bluetoothManager)
val btDevice = bluetoothManager.adapter.getRemoteDevice(macAddress)
logger.d(TAG, "Device to connect: $btDevice")
gatt = btDevice.connectGatt(context, false, object : BluetoothGattCallback() {
override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
super.onConnectionStateChange(gatt, status, newState)
logger.d(TAG, "Connection state changed to status: $status, sate: $newState")
when (newState) {
BluetoothProfile.STATE_CONNECTED -> {
logger.d(TAG, "Connected")
printConnectedDevices(bluetoothManager)
}
BluetoothProfile.STATE_DISCONNECTED -> {
logger.d(TAG, "Disconnected")
printConnectedDevices(bluetoothManager)
}
}
}
})
}
@SuppressLint("MissingPermission")
private fun printConnectedDevices(bluetoothManager: BluetoothManager) {
val btDevices = bluetoothManager.getConnectedDevices(BluetoothProfile.GATT)
logger.d(TAG, "Currently connected devices: $btDevices")
}
Just call onDeviceClick once to connect to device and click again to disconnect. After disconnect I can see in my logs, that for pixel phone, my bluetooth dongle is still shown as connected:
I/SelectDeviceViewModel: onDeviceClick(macAddress=00:1E:42:35:F0:4D)
D/SelectDeviceViewModel: Currently connected devices: []
D/SelectDeviceViewModel: Device to connect: 00:1E:42:35:F0:4D
D/BluetoothGatt: connect() - device: 00:1E:42:35:F0:4D, auto: false
D/BluetoothGatt: registerApp()
D/BluetoothGatt: registerApp() - UUID=ae98a387-cfca-43db-82f0-45fd141979ee
D/BluetoothGatt: onClientRegistered() - status=0 clientIf=12
D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=12 device=00:1E:42:35:F0:4D
D/SelectDeviceViewModel: Connection state changed to status: 0, sate: 2
D/SelectDeviceViewModel: Connected
D/SelectDeviceViewModel: Currently connected devices: [00:1E:42:35:F0:4D]
D/BluetoothGatt: onConnectionUpdated() - Device=00:1E:42:35:F0:4D interval=6 latency=0 timeout=500 status=0
D/BluetoothGatt: onConnectionUpdated() - Device=00:1E:42:35:F0:4D interval=36 latency=0 timeout=500 status=0
D/BluetoothGatt: onConnectionUpdated() - Device=00:1E:42:35:F0:4D interval=9 latency=0 timeout=600 status=0
I/SelectDeviceViewModel: onDeviceClick(macAddress=00:1E:42:35:F0:4D)
I/SelectDeviceViewModel: Disconnecting
D/BluetoothGatt: close()
D/BluetoothGatt: unregisterApp() - mClientIf=12
D/SelectDeviceViewModel: Currently connected devices: [00:1E:42:35:F0:4D]
EDIT3 Log on samsung where everything works:
I/SelectDeviceViewModel: onDeviceClick(macAddress=00:1E:42:35:F0:4D)
D/SelectDeviceViewModel: Currently connected devices: []
D/SelectDeviceViewModel: Device to connect: 00:1E:42:35:F0:4D
I/BluetoothAdapter: STATE_ON
D/BluetoothGatt: connect() - device: 00:1E:42:35:F0:4D, auto: false
I/BluetoothAdapter: isSecureModeEnabled
D/BluetoothGatt: registerApp()
D/BluetoothGatt: registerApp() - UUID=931b9526-ffae-402a-a4b4-3f01edc76e46
D/BluetoothGatt: onClientRegistered() - status=0 clientIf=17
D/BluetoothGatt: onTimeSync() - eventCount=0 offset=346
D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=17 device=00:1E:42:35:F0:4D
D/SelectDeviceViewModel: Connection state changed to status: 0, sate: 2
D/SelectDeviceViewModel: Connected
D/SelectDeviceViewModel: Currently connected devices: [00:1E:42:35:F0:4D]
D/BluetoothGatt: onConnectionUpdated() - Device=00:1E:42:35:F0:4D interval=6 latency=0 timeout=500 status=0
D/BluetoothGatt: onConnectionUpdated() - Device=00:1E:42:35:F0:4D interval=38 latency=0 timeout=500 status=0
D/BluetoothGatt: onConnectionUpdated() - Device=00:1E:42:35:F0:4D interval=9 latency=0 timeout=600 status=0
I/SelectDeviceViewModel: onDeviceClick(macAddress=00:1E:42:35:F0:4D)
I/SelectDeviceViewModel: Disconnecting
D/BluetoothGatt: close()
D/BluetoothGatt: unregisterApp() - mClientIf=17
D/SelectDeviceViewModel: Currently connected devices: []
EDIT4 I've tried modifying above code to first call disconnect() and only call close() when bluetooth connection state changes to disconnected, but it still had the same issue.