Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Android disconnect() and close() do not disconnect

I have problems with disconnecting my Android devices from my BLE peripheral. I don't think this is Nordic-specific, but perhaps someone has an idea?

Disconnecting using the nRF Connect app is 100% successful. The BLE peripheral sees the remote disconnect as soon as I click the "DISCONNECT" button.

However my own app based on Android BLE Library does not work: when I call mBleManager.disconnect().enqueue(); my app thinks it has disconnected, but my device does not see the disconnection. (It times out and does its own disconnect later).

I wrote a simple non-Nordic app with buttons for mBluetoothGatt.disconnect(); and mBluetoothGatt.close(); In this case the peripheral sees the remote disconnect only about 10% of the time.

I get the same results with an tablet running Android 7 and a Samsung phone running Android 8. I was involved in a thread on the same topic last year (not sure if it was resolved): github.com/.../450

Any ideas? In particular, what is the nRF Connect connect/disconnect code (which works) and how does it differ from the BleManager code, which does not?

  • Hello !

    On Android (and iOS as well), it is the OS that manages the physical Bluetooth connections. Many apps may be (almost) independently connected to the same device. Only when the last of them disconnects, the OS closes the physical connection. There is no way* for an app to know if there is any other app that is using this connection, or not. In fact, a single app may open virtual connection to the same device multiple times, just by calling `device.connectGatt(...)` with different callbacks. From the BluetoothGatt object's perspective, calling disconnect() closes the connection and good bye. But it does not mean that the peripheral was in fact disconnected.

    A second after calling disconnect() the OS checks if there are any other virtual connections open. If so, it just keeps the connection open, as if nothing happened. If no more apps, it disconnects from the peripheral.

    When you are using nRF Connect you don't have nRF Connect running in background :) nRF Connect, when the Settings -> Connectivity -> Show incoming connections switch is enabled (default) will connect to the device in background and, until Android 8.0.0 will keep a strong reference to the connection, that means that even if your app has disconnected, it will still be connected. Just exit nRF Connect with Back button, instead of switching to another task, to avoid this problem. From Android 8.1.0 nRF Connect tries to use hidden connectGatt method with opportunistic parameter set to true, so the connection is weak. Weak connection, from OS perspective, is no connection, so physical link may be closed when another app disconnects.

    To make sure that your device disconnects, you have to send some kind of Reset command that will send the disconnect command from the peripheral. Android will honor this and will notify all BluetoothGattCallbacks that the device has disconnected. This is for example what we do in DFU when we switch to Bootloader mode.

    Try disconnection without nRF Connect runnign in background, this should work.

    BR, Aleksander

  • Thanks so much for this, Aleksander. It is a simple explanation when you know it, but not at all obvious!!!

    Can I suggest you document in as many places as you can! Including various places in the source code.

Related