'Android 12 BLE always returning status 0 on disconnect

When testing with an Android 12 device whenever my Bluetooth device disconnects I receive a status 0 regardless if I disconnect programmatically or the device went out of range. From my understanding in previous Android versions status 0 is programmatically disconnected and status 8 was for device went out of range.

 return object : BluetoothGattCallback() {

            override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
                val name = gatt.device.name
                Log.i("onConnectionStateChange", name + "\t" + status + "\t" + newState)

                when (newState) {
                    BluetoothGatt.STATE_CONNECTED -> {
                        gatt.discoverServices()
                    }
                    BluetoothGatt.STATE_CONNECTING -> {

                    }
                    BluetoothGatt.STATE_DISCONNECTED -> {
                    }
                    BluetoothGatt.STATE_DISCONNECTING ->  {
                        // status 0 (Programmatically disconnected)
                        if (status == BluetoothGatt.GATT_SUCCESS) {
                            // Always going in here
                          ...
                        }
                        // Deivce went out of range
                        else if(status == 8){
                           // Never in here
                          ...
                        }
                    }

                }


            }

          override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
                    super.onServicesDiscovered(gatt, status)
            }
}

Has anyone face this same problem and figured out how to get the status to show correctly or found another way to determine if it was device out of range or a disconnect programmatically?



Solution 1:[1]

Unfortunately I have the same behaviour on my Pixel 3, after the Android 12 update, which is a bit sad. Either they changed this intentionally or unintentionally. In any case, what the status code should contain is not documented anywhere except that GATT_SUCCESS (0) shall be used if "the operation succeeds", with no definition of what "succeeds" means. I think you should file a bug report to AOSP.

Solution 2:[2]

I confirm what you say with Android 12: on BLE disconnection, the value of the status param passed in onConnectionStateChange() is 0 (i.e. BluetoothGatt.GATT_SUCCESS) wether the disconnection was done programmatically or because the device went out of range, or shut down electrically.

This is a drawback compared to previous version of android, which would pass status 8 (0x08 = GATT CONN TIMEOUT) when the device went out of range (or was shut down electrically) and status 0 when the connection was successfully closed programmatically.

Solution 3:[3]

This is a general problem/change on Android 12, 12L and 13 DP :( I have filed a bugreport to AOSP regarding this, but there is not really any feedback from Google. https://issuetracker.google.com/issues/207323675

If you look in the HCI logs you can still see the disconnect reason, but as you have also found out it is no longer passed on to apps. Except for status=133 when a direct connect times out.

So maybe Google has started cleaning up the mess of mixing internal status codes (like 133) with BLE disconnect reasons? The question is of course then: Where can then get the disconnect reasons?

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Emil
Solution 2 matdev
Solution 3 Lars Klint