2

We want Android to automatically connect to our custom made BLE peripheral.

Our peripheral should regularly (but infrequently) advertise and attempt to Indicate some time-sensitive sensor data to the phone. Thus we want the phone to be ready to connect at any time.

Generally, you can pair a smart watch with an Android, and Android will then automatically connect to the smart watch whenever it is in range. So we believe our use case should be feasible.

I read a lot of answers that advise to set the "autoconnect" parameter to true when connecting. I have tried that and the reconnections don't persist through a reboot or even after disabling and re-enabling Bluetooth on Android. This answer by Brian says I should scan in the background, but Android made this unrealistic. If I use a foreground service, my users will hate the app. If I use a background service, I may miss the peripheral's attempts to connect during Android's Doze and the code becomes error prone.

Ideally, I want to do something like what Emil said in his answer here. Please read the follow up question and response.

However, we can't see our app through Android's Bluetooth settings. We can only connect to the peripheral and pair with it using our app (or nrf Connect). In desperation, I tried modifying the peripheral's advertising flags. Then I could see it in Android's Bluetooth settings. But when I try to pair using Android's settings, the attempt fails because the peripheral is not in "pairing mode".

We are building both the app and the peripheral, so we can change both. I want to know if our use case is possible and what we need to do to get it working. We are using the STM32WB for our peripheral.

2 Answers2

6

Use a combination of these techniques:

  1. Bond the device. This might be needed due to the crappy Android Bluetooth LE API design that doesn't take the "address type" as an extra parameter when connecting to a device. When you connect using the Bluetooth device address, it looks up a device with this address in the bonding info, and uses the corresponding address type (random or public).

  2. Use connectGatt with autoConnect set to true. This means no timeout, as well as auto-reconnect if the connection drops. Even if it takes days or weeks until the peripheral starts advertising, it will still work.

  3. Listen to https://developer.android.com/reference/android/bluetooth/BluetoothAdapter#ACTION_STATE_CHANGED and restart your connections when Bluetooth is re-started.

  4. Use a Foreground Service in your application's process to prevent the OS from killing the process. Users can nowadays hide the annoying notification in Android settings if they want to.

  5. Listen to https://developer.android.com/reference/android/content/Intent#ACTION_BOOT_COMPLETED to start your app after boot, including your Foreground Service.

  6. Listen to https://developer.android.com/reference/android/content/Intent#ACTION_PACKAGE_REPLACED to automatically restart your app after an app update. See https://stackoverflow.com/a/2134443/556495 for some instructions.

Emil
  • 16,784
  • 2
  • 41
  • 52
  • I'm working on this. It seems promising. But is it really impossible for the device to automatically connect with the device without our app's intervention? – Youssef Beltagy Apr 28 '21 at 21:47
  • Android will never connect by itself to a device. It must either be an app wanting a connection, or a standard profile device like HID that has been bonded through the system settings. – Emil Apr 29 '21 at 07:25
  • I just finished implementing your suggestion. It works. Thank you. Going forward, it seems implementing a standard profile like HID for the peripheral is closer to what we want. Can you please direct me to more information on what Android expects/needs exactly to connect to a device through the system settings? How does the system settings decide what it can connect to and what it can't connect to? For example, will something like a heart rate profile as defined by Bluetooth SIG connect through Android's system settings? Why would it work? – Youssef Beltagy May 03 '21 at 05:35
2

The best approach is to make sure your peripheral can be bonded. Once you have bonded with it you can ALWAYS use autoconnect because Android stores info about bonded devices and you don't have to scan for it anymore. Hence you avoid the issues with scanning in the background.

Although that resolves the need for scanning, you still need to deal with your app being killed once it is in the background. Using a Foreground Service is still the best solution to my knowledge. I don't think you users will hate your app for it...

  • Are you saying that after establishing a bond, I can start my app on Android boot and attempt to gatt.connect with autoconnect equal to true? And this should allow my app to connect to the peripheral as soon as the peripheral advertises. But wouldn't there be a timeout? If this works, it should hopefully resolve scanning. If the foreground service is up only while the peripheral is connected, that should be okay. But I will have to show a foreground service as long as Android is up to attempt to connect. – Youssef Beltagy Apr 19 '21 at 18:21
  • Indeed, when issuing an autoconnect there won't be a timeout and you can do it directly after startup of the app. Sometime it takes a bit long for sone phones to connect but you can fix that by keeping the advertisement interval below 1000ms. Try 500ms – Martijn van Welie Apr 20 '21 at 04:43