There are a couple of differences between "auto connect" and scanning + "direct connect". Ideally "auto connect" is what we want since that requires only one advertising packets to set up the connection instead of two.
Scan parameters
Auto connect, direct connect and scanning all use different scan parameters while listening for the advertisements. The mode you use and the advertising interval heavily affects connection setup time.
Auto connect uses a window of 48 ms every 1280 ms in all non-ancient Android versions and is used by all vendors as far as I know. This works very good when the advertising device has a short advertising interval, such as 20 ms. I imagine that your car can burst out this short advertising interval when the car is started, and maybe increase the interval if a connection isn't established for some time. When 20 ms advertising interval is used, the connection should be established within 1280 ms since at least one packet should be caught during the 48 ms the Android device has the radio on. If you advertise with an interval of 1 second however, it may take a really long time to connect since the advertisement must be sent exactly in that 48 ms time frame of 1280 ms.
Direct connect uses a window of something like 30 ms every 60 ms to get a fast connection set up. Direct connection however times out after 30 seconds and sends an error status in the onConnectionStateChange
callback. So this mode should only be used either in a GUI where the user presses a "connect" button or after some scan has run and you want to connect to a device found during scan.
A normal scan operation uses totally different scan window and scan intervals. Historically 1 second scan window and 5 seconds scan interval was used for "low power" and 5 seconds scan window and 5 seconds scan interval was used for "low latency". In later versions of Android this has become much worse, such as a scan interval of 15 or 45 seconds, while the window hasn't increased.
Dealing with unexpected stops
Over time background scanning has become more and more restrictive on Android and you need to be careful with your scan settings, scan filters, how often and when you scan, to be sure that the Android device actually scans for your BLE devices. Fortunately new APIs using Pending Intents have been added in Android 8 to let the system scan for your devices, even if your app has been killed by the system to save memory. You should read http://www.davidgyoungtech.com/2017/08/07/beacon-detection-with-android-8 which compares a bunch of scanning options. That article however doesn't seem to bring up the case when you have a Foreground Service (which requires an icon in the notification bar indicating to the user that your app is running), which lowers all restrictions quite a lot.
No restrictions on "auto connect" have been added at all however over the years. The only "restriction" I'm aware of there is that you should have a Foreground Service in your app process to avoid the app from being killed, and hence losing your connection attempts.
Stability
There are of course a bunch of bugs in Android's Bluetooth stack, which some of them have been fixed and some remain. There are also intended behaviour that will cause unstability - such as when Android stops your scans when it thinks you scan too much.
Regardless of which method you use, if you want connections to persist after the user turns off and on Bluetooth (or if the Bluetooth stack crashes and restarts), you need to have a BroadcastReceiver that listens for BluetoothAdapter.ACTION_STATE_CHANGED
that restarts all your pending connections/scans. You might also want to set up a BroadcastReceiver that listens to when the system boots or your app is updated, to start your app in those scenarios so you can start the pending connections.
Maybe it's not that revelant for your case, but regardless of which connection method you use, you should also be aware of that Android has limits on maximum connections, BlueoothGatt objects, L2CAP links and stuff that might cause your communication to fail in unexpected ways. Sometimes by errors in the onConnectionStateChange
callback and sometimes no callbacks that a limit is hit.
For "auto connect" you really really should implement something like https://github.com/Polidea/RxAndroidBle/blob/7663a1ab96605dc26eba378a9e51747ad254b229/rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/util/BleConnectionCompat.java if you know you have devices running Android 6 or lower, due to https://issuetracker.google.com/issues/36995652 which causes "direct connect" to be chosen instead of "auto connect".
For "auto connect" I wrote an important patch https://android.googlesource.com/platform/system/bt/+/8451ad010e26562d4a4c7d0d135c70c4325ee6b5 that was accepted in Android 8.1 which earlier caused the Bluetooth stack to hang until it was restarted if a device timed out and then restarted advertising before the Android device has timed out.
When your code runs on a device recent enough to support to pass the TRANSPORT_LE
to connectGatt
, please use that method since otherwise Android sometimes attempt to connect using Bluetooth Classic.
Bluetooth Device Addresses
Due to a terrible design flaw, it's not possible to tell the Bluetooth stack to connect by the full address (address type random/public + address). You can only give the 48-bit address when you want to get a BluetoothDevice
object (which you then use to connect). By digging through the source code of Android's Bluetooth stack, it's the same issue everywhere that a Bluetooth device is identified by the 48-bit address instead of the 49 bits. Their "quick fix" was to add a property to the device information which indicates if the device has a public or random address. This bit cannot be set by an app, but is only set during scanning. When connecting with connectGatt
and the address type is unknown, it will try to establish using public address type (a few sub-versions of Android 7 made some stupid guess of address type depending on some bits in the 48-bit address when using "auto connect"). If your BLE devices has a static random address, it therefore won't connect. By performing a scan and your device is detected, it will store the device's address and the address type in a table in RAM, so if you later connect to it using connectGatt
, it will succeed since the correct address type is now used. This table is cleared when Bluetooth is restarted. Note that if you perform a Bond, then the device info is written to disk, including the address type so connecting to bonded devices should always work even if Bluetooth is restarted.
Summary
Despite all the issues above, "auto connect" generally works flawlessly and is very stable, as long as you follow the guidelines above, which gives you a fast connection setup time assuming your peripheral has a short advertising interval. In Android 8.1 and above, most critical bugs have been fixed.
Your second choice is probably to use the Pending Intent scanning option, where you get a broadcast from the system when your device is detected (even if this may take quite some time before your device gets detected). You can of course use both methods also, to be on the safe side...