NordicSemiconductor / Android-BLE-Library

A library that makes working with Bluetooth LE on Android a pleasure. Seriously.
BSD 3-Clause "New" or "Revised" License
1.99k stars 414 forks source link

onDeviceDisconnected - inconsistent reason #504

Closed ghost closed 11 months ago

ghost commented 1 year ago

I'm getting different reasons inside the ConnectionObservers onDeviceDisconnected callback for different devices in case of disconnecting some BLE devices from the phone (disconnecting them from the power outlet).

The main issue with this is that if I disconnect from a device using the disconnect() from the BleManager, I also get a REASON_SUCCESS on the onDeviceDisconnected callback.

Maybe the different Android version is the issue, I'm not sure. Can you help me take a look at it, how to solve it?

Thanks, Tamas

krioru commented 11 months ago

I have the same issue.

I have a battery powered peripheral/server device and I use phone to connect to it and read its characteristics. If I remove device's battery, I get the SUCCESS reason on disconnection event.

If I try to connect to device which is not powered or out of reach, i get the UNKNOWN reason on disconnection event.

philips77 commented 11 months ago

I'll look into that, thanks.

philips77 commented 11 months ago

The intended reason should be TERMINATE_PEER_USER, I believe, when you kill the connected device. In worst case TIMEOUT.

krioru commented 11 months ago

Removing the battery and going out of reach both give SUCCESS reason on my Android 13 phone. In both cases the reason should be TIMEOUT, because it's not a 'graceful disconnection'.

philips77 commented 11 months ago

There is this method called at some point: https://github.com/NordicSemiconductor/Android-BLE-Library/blob/839cbb3ac11b6b03d0dbc57f5aa523e19805ef62/ble/src/main/java/no/nordicsemi/android/ble/BleManagerHandler.java#L2810-L2820 If the reported status is 0, then success is reported. I'll try to modify it so SUCCESS is only reported when the disconnection was triggered by the user.

philips77 commented 11 months ago

Btw, what messages do you get on WARNING level just before getting the event from the log(...) method?

krioru commented 11 months ago

I don't see any warning logs. I retrieve the reason from stateAsFlow() flow.

Here's the logs that I receive when I remove power from the peripheral device:

BluetoothGatt           D  onClientConnectionState() - status=0 clientIf=12 device=CC86EC_3
BluetoothC...Connection D  [Callback] Connection state changed with status: 0 and new state: 0 (DISCONNECTED)
BluetoothC...Connection I  Disconnected
BluetoothC...Connection D  gatt.close()
BluetoothGatt           D  close()
BluetoothGatt           D  unregisterApp() - mClientIf=12
BluetoothAdapter        I  STATE_ON
BluetoothAdapter        I  STATE_ON
BluetoothAdapter        I  STATE_ON
BluetoothC...Connection D  onServicesInvalidated()
BluetoothC...er:connect D  Disconnect reason: SUCCESS

The last log line is called whenever stateAsFlow() emits a new value.

Like this:

stateJob = bleConnectionManager?.stateAsFlow()?.onEach { managerState ->

  if (managerState is ConnectionState.Disconnected) {
    Log.d("$TAG:connect", "Disconnect reason: ${managerState.reason}")
  }

}?.cancellable()?.launchIn(scope)
krioru commented 11 months ago

Ok, I checked on two other devices running Android 10 and Android 8 and they do have that warning log and they report the correct reason:

D  [Callback] Connection state changed with status: 8 and new state: 0 (DISCONNECTED)
W  Error: (0x8): GATT CONN TIMEOUT
I  Disconnected
D  gatt.close()
D  onServicesInvalidated()
D  Disconnect reason: TIMEOUT

So it looks like it's an Android 12/13+ issue. Maybe also Android 11?