Lessons for First-Time Android Bluetooth LE developers I Learned the Hard Way

Hamid Mukhtar
AndroidPub
Published in
4 min readAug 5, 2017

--

Background

Once there was a stable Android Bluetooth stack named BlueZ. Everyday developers built Android Bluetooth applications without major issues. Until one day, Google decided to replace it with Broadcom’s BlueDroid stack mainly because of licensing issues. Because of that, Bluetooth development on KitKat OS became a nightmare for Android Developers. Because of that, the workarounds in code made Android Bluetooth applications as fragmented as the OS itself. Until finally, the issues were fixed in Android L and the M OS. Ever since then, users of Android Bluetooth LE applications started getting an experience similar to the iOS Bluetooth LE applications.

Bluetooth Low Energy development in Android

To get an idea about what Bluetooth LE in general is, these videos are a nice start:
1. Google Developers: Bluetooth Low Energy
2. KitKat development : Google I/O 2013 Best Practices for Bluetooth Development
3. L OS improvements: Newcircle Bluetooth LE matures

Google provides these three samples for Android Applications:
1. Bluetooth Advertisements
2. Bluetooth Client : This sample is a simple Bluetooth LE Heart rate monitor client which can be extended to make other clients. (the github is not updated for a long time and the pull requests can come to the rescue)
3. Bluetooth Server: This sample is a simple Bluetooth LE Current time Service server. It is also not updated after the first few commits so make sure to check the pull request for the bugs.

Bluetooth SIG also provides a starter kit for Android developers. Trying the samples is good enough to get you started. (Google also supports Bluetooth LE on Android things now so you can now make your own Bluetooth LE device).

The Good, the Bad, and the Ugly

Like every other technology, Bluetooth LE on Android is awesome till you find your first connection error or when the demo Gods are not in the mood.

The Good
Android started supporting Bluetooth LE Central mode (Client mode — in which the phone can connect to a Heart rate monitor which acts as a Server) in KitKat OS and Peripheral Mode (Server mode) in L OS. This enabled the use of many low power Bluetooth LE devices e.g. Heart rate monitors, Weight scales, Blood pressure monitors, and Glucose Meters.

The bad
Central mode is very unstable in KitKat OS because BlueDroid’s initial implementation was unstable.

The ugly
Error status 133 (GATT_INTERNAL_ERROR). Whenever you see this, take a deep breath, meditate, call a friend, call your support network for an early meeting, and remember you are not alone. Here are solutions to some common issues which can take days to figure out:

  1. Servers with Dual BT stacks : If your BLE Server is a Dual BT device, on the Client side try using auto-connect as false in bluetoothDevice.connectGatt API. If auto connect is needed in your application, use the bluetoothDevice.connectGatt api with the TRANSPORT_LE parameter in OS greater than or equal to M. In KitKat OS, there is no option other than scanning before connecting to the device.
  2. Error status 133: when you see this status (or error 128), always try adding 60~100ms delay after the last successful operation. This may save you from days of agony.
  3. Bluetooth 4.2 privacy : Many developers are unaware that in Bluetooth 4.2, when LE privacy is in use, the mac addresses are randomized and they maybe different from the BD_ADDR. The assumption that the mac address would always be same is not correct anymore.
  4. Thread issues: Do all GATT operations in the same thread, preferably the MAIN thread if you are using KitKat OS.
  5. Calling disconnect right before close: calling bluetoothDevice.disconnect() right before bluetoothDevice.close() is redundant and can result in issues in some devices. Try using only close() instead.
  6. connectGatt API has low priority: most applications add scanning side by side to make the connection faster.
  7. Retry retry retry: When you get an error status in the logs, its always good add retry logic for that operation. Some operations work on a second try after a delay e.g. if writing Current Time on a Server fails, adding logic to retry writing again after 60~100ms may work and may make the app more reliable.

Test Tools

For debugging, in the Android logs, look for the “BluetoothGatt”, and “GattService” keywords for the Gatt related logs. Sometimes bt-btif logs are also helpful to understand whats happening at the Android framework layer.

Wireshark and Frontline are the packet analyzers you need for catching Bluetooth LE packets if you need low level analysis.

Conclusion

Bluetooth LE support is getting better in every version of Android. It is still not as stable as iOS but its getting there. Most vendors that make BLE peripherals (e.g. Weight scales, Blood Pressure monitors, Glucose Monitors etc) don’t follow the standard Bluetooth LE profiles and add their own specifications to their devices. If you are trying to add support for a real Bluetooth LE device, always ask the device vendor for a sample even if they claim that they follow the standard BLE specifications. The communication flow varies from vendor to vendor.

Thanks for reading. Let me know about your feedback in comments. If you have any questions related to Bluetooth in Android feel free to ask.

--

--

Hamid Mukhtar
AndroidPub

Senior Android Engineer @ Samsung Electronics S Health Team