I have an android app i am developing. It's a BTLE app, i have some BTLE tags i need to talk to.
I do all by the book, discover device, GATT connect (subsequent bonding), write/read characteristics... it works.
Now the weird is that it will stop working if i close and open the application two times.
Let's say i have already one tag correctly connected, bonded and working properly.
phone reboot.
Open app the first time -> everything works.
close app, open again -> everything works.
close app again, open -> unable to receive any readCharacteristic from the GATT callbacks.
In the logs, there is NOTHING DIFFERENT from each attempt. I log each call and print return statuses: no difference. Just the readChar callback is never called.
Android is 4.3, same issue on different phones (S3, S4, Note3)
(note: on app shutdown i properly disconnect all the GATT stuff)
Do you have any ideas on what to check? Or is this a known android bug? I have searched, but could not find anything....
The bluetooth stack on Android 4.3(at least) specially for BTLE definitely has quite some issues. I don't know if it's a specific vendor implementation, driver issues, or what else, but it's honestly a nightmare for developers.
This is what i found out does help to improve things:
- disable Wifi
- forcefully enable/disable bluetooth by code (BluetoothAdapter methods enable() and disable())
In fact, cyclying bluetooth on and off when things start getting "unstable" do fix it. This requires the BLUETOOTH_ADMIN capability and might clearly not be desired, since it will briefly shut down ALL you bluetooth conencted gadgets AND will popup some dialogs to the user where he/she can disable the ongoing restart.
Now i am getting more stable results.
Still, shame on Google (or whoever i don't know) for letting such poor software out in the wild.
Related
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.
Use a combination of these techniques:
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).
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.
Listen to https://developer.android.com/reference/android/bluetooth/BluetoothAdapter#ACTION_STATE_CHANGED and restart your connections when Bluetooth is re-started.
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.
Listen to https://developer.android.com/reference/android/content/Intent#ACTION_BOOT_COMPLETED to start your app after boot, including your Foreground Service.
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.
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...
I need to estabilish a brief communication between a BLE master and a BLE peripherical device.
Until I have to use the mobile phone I have no problems, since I select the bluetooth device from Android, I can connect to it and then I can receive data simply writing them to HM-10.
BUT, this approach is battery expensive, since the BLE scanning is more battery expensive than the BLE advertising (right?). So I want that the mobile becames an advertisor and the HM-10 takes the ROLE of Slave.
BUT, I still don't understand if it is possible to connect to other devices: I tried AT+CONN and it always fails (AT+CONF). Is there any way to send brief data from the HM-10 to the advertisor, even without connecting?
Even my firmware looks slightly different from the readme! For example,AT+LN is present in the documentation but it appears to not exist. Does a better version of the firmware for this device exist, or, are sources available somewhere? I installed the HM-Soft V705 (lastest).
Thanks
UPDATE 1:
#ChrisStratton Ok, I have some intresting news: I was already following your idea (phone advertise sometimes, while HM-10 always scan and tries to connect to the service if it sees it, then HM-10 send some data, phone answer). I managed to make the phone visible from HM-10 (don't ask me how!). I am using the BLE Tool Android app to test everything. Now, the central problem now is that HM-10 won't connect to the android service even if the advertisor is connectable (see attached images).
I am sospicious that the AT+CO (that I discovered is a kind a replacement of AT+LN, but I am not sure) can help, but i don't know how.
In my Android application, I am using the WifiP2pManager API to discover peers with Wifi Direct. It works, and it discovers them as expected after calling
wifiP2pManager.DiscoverPeers(myChannel, myActionListener);
But sometimes, if I turn off a device after it has already been discovered, it still appears in the WifiP2pDeviceList when I discover peers again. I actually have to turn the wifi off and on from the device (that's discovering peers) so that it doesn't show the device (that's off) anymore. Is there a chache that I can clear instead?
I'm developing this app in Xamarin.Android, but an answer in Java/Kotlin would be fine.
EDIT
Just realized that if I wait for a minute, the turned off device doesn't appear in the list of discovered peers anymore. Still would like to know if there's a way to clear the cache sooner.
The device does not go away until "discoverPeers()" is called again by the system, which is currently set (in android framework) to be called after 60 sec.
This is normal behavior, probably nothing much you can do about it.
An answer to explain the behaviour: https://stackoverflow.com/a/25154034/3260008
What I want to know:
I'm wondering how the android system (like Android smart phone) auto-connects to devices which is paired before.
For example, I pair my bluetooth headset with my android smartphone in the procedure of "turn on scanning/advertising -> click pairing" on day 1. And when I turn on advertising on my headset, it connects automatically on day 2, 3, 4, and so on. The point is, I don't have to make my smartphone scan again to find my (paired) headset.
I can't understand how android system finds that the paired device is turned on. Does the android system scan periodically in background? Even if I don't click "scan" button?
Why I ask:
I want to make my app autoconnect to customized BLE device, after make pairing. I succeed to make pairing(bonding) with createBond() method, but after that, I couldn't find how to make autoconnect. I know I can turn on autoconnect function like this way, connectGatt(XXX, true, XXX), but this autoconnect function doesn't work when the BLE device is disconnected a few days.
So I want to make my app works like android system and Bluetooth headset. But I couldn't find how android bluetooth system works even I dig AOSP codes.
I found many questions (here and here) about problems like mine but there were no answers.
Thanks in advance.
Update:
I found that bt_btif gets activated (with LG smartphone and Nexus 5) when the paired headset is turned on (start advertising). But bt_btif doesn't get activated with my custom BLE device... What can I do?
Executing connectGatt(XXX, true, XXX) is the correct way to go. gatt.connect() also starts an auto connect. Once you execute that, your phone will scan for the device and once it appears it connects to it. The only thing that interrupt this call is either if Bluetooth is turned off on the phone or if your app process is being killed. To avoid your process from being killed, let your app have a foreground service.
One gotcha however, there is a bug in Android which will sometimes make auto connect do a direct connect instead (and cancel after 30 seconds or so). See https://code.google.com/p/android/issues/detail?id=69834. You need to use reflection to avoid this bug.
I think I found a solution.
First, the solution for my question: Android smartphone seems to detect state changes of nearby bluetooth devices from the hardware sides. When the paired bluetooth headset starts to advertise, a callback in HAL (I think) is called.
So I made my app to connectGatt with autoConnection=True to the device that I want, by using MAC address, when the activity is started (in onResume() of MainActivity).
The connection would fail if my BLE peripheral device is not advertising. But the device auto-connects when it starts advertising, because the autoConnection parameter was set to true.
I've done a similar app and i didn't have problem with that. As a last resort for your problem, i would suggest writing the BLE Device Address in a simple DB table and manually connect to it. I've made something like this here
. It is no best practice code, but i hope you can find ideas for you solution.
I am creating an app that communicates through Bluetooth Low Energy with a device, mostly to have the phone display the data from the device. I need to implement functionality where if the device and phone are moved into range, they will automatically identify as a pair and will connect without user interaction. I have been looking into Bonding to accomplish this.
I am currently trying to take the currently connected device and create a bond with it when the user clicks a ListItem. I call BluetoothDevice.createBond() on a reference to the connected BluetoothDevice variable. The Android Developer site says that for BluetoothDevice.createBond(), false will be returned if there is an error, and that I should register for ACTION_BOND_STATE_CHANGED to be informed when Bonding has started and is completed.
I have a few problems with createBond(), which is where my questions lie:
Most of the time createBond() returns false, indicating that it has failed to start bonding. What are some possible reasons for this? (My phone runs Android 4.4.2, API19 which is where createBond() is introduced - so it isn't that.)
Sometimes, bonding apparently succeeds because the code inside the ACTION_BOND_STATE_CHANGED receiver will be called. I may misunderstand what is involved in maintaining and using a bond, but the BLE device does not automatically connect to the phone when it is in range, so I am probably missing some code. After establishing a bond, what else do I need to do?
In the event that createBond() is no good for whatever reason (e.g. I have to make the app work for API18 when createBond() is introduced in API19), what alternatives are there?
Examples would be incredibly helpful. Finding information about bonding with BLE has been frustrating. Self-teaching this stuff has been difficult, especially with no tutorials lying around. On top of that, some people say it's impossible due to being "Just Works" when others say it's certainly possible. BLE is still a big cloud of confusion for me, so for now, some clarity with createBond() would be much appreciated.