BLE is native supported on Android from v4.3. It has been continuously improved as Android evolving. It's getting more and more complex with additional features. It's important that a Bluetooth app should work smoothly on all Android versions, from 4.3 to the latest one. One may find it's tricky to keep track of all the issues from earlier Android versions and the changes in BLE APIs of different API levels.
To help you with this, our app developers have provided a note, discussing about most important changes and added features on newer Android version 5 and 6, including some testings we have done on different Android phones regarding BLE performance.
Some interesting topic:
Required permissions for BLE app.
Scanning: different scan mode, report delay, callback type, etc
Connection: autoConnect, connection parameter update, MTU, number packets per connection parameters.
GATT server, advertising, how to set it up.
This document is strongly recommended to whom developing Android apps:
Question and issue, please post as a separated case and post the link here.
Nice document! I have some corrections, additions, proposals as well as some warnings.
First the sub chapters are numbered incorrectly. (I'll refer to chapters using the Content table).
The link static.googleusercontent.com/.../Android-6.0-Bluetooth-HCI-Reqs.pdf does not work. static.googleusercontent.com/.../Android-6.0-Bluetooth-HCI-Reqs.pdf is the correct address.
In chapter 3, connecting to a BLE device using an address directly, as of Android Nougat it is no longer true that it will assume it is a public address. It varies between Android builds but it sometimes set the bit to random address. I wonder about the sentence "the logic being that random addresses can change any time, and if it is hardcoded, it must be a public one". Is that something someone at Google has confirmed or is that just an assumption? Actually I think this is an afterthought when they added BLE support since they didn't need to care about address type before. There are still other bugs where they mess up with the address type in their code...
I'd like to add to "The device has been scanned at least once before connection attempt." that Bluetooth must not have been restarted since it was latest discovered by a scan. Also, a third condition is that it also works without the need to scan before if the device is bonded (I've tested static random addresses and public addresses, not sure about random resolvable addresses).
In chapter 4, about the autoConnect parameter. I think the terminology is a bit misleading here: "If it's true, this method will not connect to the device, like it would with this parameter set to false, but rather adds its address to the whitelist. Whenever a device from the whitelist is discovered, the system will try to connect to it." It definitely attempts to connect to this device (with a HCI LE Create Connection). The only difference regarding that is that the address is provided by the white list instead of in the HCI LE Create Connection command. Also the standard configuration (which may be different between Android phone vendors) is to use more active scanning parameters when using autoConnect=false which leads to faster connection setups.
There are more differences: once the device disconnects with a reason other than the gatt object was disconnected/closed, a new connection attempt will be made automatically if either the autoConnect parameter was true or the connect() method was called on the gatt object, i.e. if you used autoConnect=false no further connection attempt will be made. With autoConnect=false the connection attempt will also get a timeout of 30 seconds. autoConnect=true has no timeout. Lastly, autoConnect=false will temporarily cancel all other pending connections to devices in the white list and autoConnect=false attempts are queued up. You should also be aware of code.google.com/.../detail and certainly of code.google.com/.../detail if you use autoConnect=true.
In chapter 4.3, you could add that a new restriction in Android is that connections interval lower than 11.25 ms are not possible anymore (which is important if you use the Connection Parameter Update Request from the slave side) due to audio streaming performance they had or something like that.
In chapter 4.2/4.5 (streaming data using Write Without Response). If the device loses the connection while the internal queue is full, no further GATT operations will work on that gatt object once it reconnects. See code.google.com/.../detail. Regarding older devices where overflow is not handled well, as well as on iOS, an easy workaround is to send each 15th packet or so as a Write With Response. Then you don't need to create any special acknowledgement logic on the peripheral side. It of course reduces speed a bit, but rather that than dropped packets.
In chapter 4.5. With Qualcomm Bluetooth chips, that is used in for example Nexus 5X, I've measured 12 packets per connection event.
When referring to particular lines in Android source code, link to a specific commit rather than master. Otherwise the links will soon not be valid anymore. If you link to a file as a whole I guess you may link to a file in the master branch however.
There are some race conditions in the Android SDK if you call methods too quickly after each other. See code.google.com/.../detail.
If you need to have stable long-running connectivity to Android devices you should avoid restarting advertising immediately after a connection loss but rather wait a small time in between to prevent that the Android stack hangs. See code.google.com/.../detail
If you have found bugs in Android (as I see in the pdf), be sure to tell Google about them or submit a pull request. Otherwise it is very likely that they will never be fixed.