Requirement : I have a requirement where I have to scan for near by ble devices at continuous basis.If an attribute of ble device changes,the device emits the ble signal which my app captures.But these things should be done at continuous mode.
Problem : In some of the android device (such as one plus 1,samsung tab 3,Moto droid turbo) the scancall back wil get triggered only once and is not scanning at continuous basis as per my requirement.I have tested some of other devices (such as one plus 3,samsung tab 4,moto g2)where in the scan callback gets triggered every single time.Is there any solution where in even other devices to get scan callback everytime...I have checked with all the scan modes,but yet the same problem persists...
Unfortunately some of the Android devices do not return Scan results continuously as this is not mandatory according to BLE protocol (I witnessed it on LG devices). The workaround is to initiate Start and stop scan. See This useful thread
Related
I'm using BluetoothLeScanner to scan for BLE devices, which I start using:
startScan(null, settings.getScanSettings(), scanCallback);
Every once in a while, a call to startScan() does not discover any BLE device, even though some devices are actually advertizing (They are discovered using nRF Connect app).
When this happens, the next call to stopScan() and startScan() does discover devices.
I know that since Android 7, the number of start and stop scans is restricted to 5 times in a window of 30 seconds. However, I've noticed the problem sometimes also occurs if no stopScan()/startScan() has been called for more than 30 secs.
Has anyone experienced such issue ?
Could it be something else my app is doing while starting the scanner that could the scanning to fail ?
I have this problem using Android 10 and lower versions.
Android phone limited BLE scan duration to save energy. So you can not scan BLE advertising for a long time. It is system limitation so APP layer have no way to change that.
In older phone (maybe under 4.4) do not set the limitation, but it will make the phone getting hot.
If you want to scan BLE advertisement for a long time, change your design is a better way.
I have followed the ten steps outlined in the Hello Beacon app tutorial at https://codelabs.developers.google.com/codelabs/hello-beacons/.
when i turn on the app for a few seconds (maybe 10sec) it tries to find beacons and lists the beacons found but after that even if i turn off the beacon or turn on new beacons there is no response or no new messages are recieved in the app . Unless i exit to main screen(home screen) and turn on the activity again is when the changes to beacons are detected. Is there some issue with the code or is it hardware.. I use nexus 7 2013(android 6) for the app. And beacon simulator for virtual beacons on moto g4 (android 7)
If you look at the tutorial, it writes out the beacons in onCreate(). This only happens once when the app is run. You need to modify the app to either have a timer to repeatedly get the beacons or, better still, cause beacons detected by the BackgroundSubscribeIntentService to show in the UI. You can do this by binding the activity to the service and receiving callbacks into the activity whenever there are new beacons detected.
I am developing an android application that uses Bluetooth Low Energy to receive data from a peripheral device.
The device itself sends the data as part of it's advertising message and it could send the message at any time.
So the applications works by continuously scanning for BLE devices.
When the screen is ON the application receives scan results as intended.
When the screen is OFF it appears that it only receives scan results every 5 seconds.
I guess that the phone is trying to optimize for battery life but this app is mission-critical so we can not afford to lose messages.
The scanning is done by a Service which is set as a 'foreground service' so that the OS knows that it is important.
The service also acquires a PowerManager.PARTIAL_WAKE_LOCK but that does not seem to help.
The application is excluded from battery optimizations so that it does not enter Doze or deep sleep mode.
The application is using the following ScanSettings:
ScanSettings.SCAN_MODE_LOW_LATENCY
ScanSettings.CALLBACK_TYPE_ALL_MATCHES
ScanSettings.MATCH_MODE_AGGRESSIVE
ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT
I am working with a Galaxy S7 but I have been told the same behaviour happens with a Galaxy S7 Edge.
I have tested with other non-samsung devices and they work as intended (continuously receiving scan results when the screen is OFF).
The question: is there something that I, as a developer, can do to make the BT adapter deliver scan results continuously even when the screen is OFF?
Samsung automatically change scan mode to low_power if screen is turned off. It's their customisation on their Android OS, so unfortunately no way to change it.
My goal is to get the Android device to reconnect to a BLE device that it has previously connected to without user intervention in the same way it does for a classic BT paired device does (even works through power cycles).
One of the ideas of BTLE devices is that one saves service, bonding, and enabling states such that a reconnect is VERY fast and consumes very little power on the peripheral.
What I have done seems to work but it works poorly.
The first step is to connect or pair and connect to a new device setting the 'autoconnect' parameter to 'true'.
When the device disconnects, do not call gatt.close(). Everywhere I look I see that one should call gatt.close(). But if I do call gatt.close() the Android central app never reconnects. I have tested this many times.
If I have not called gatt.close() and have not power cycled the Android, the auto-connection usually happens. Sometimes it can take a long time, especially after version 5.0. It is, however, unreliable and it may be unreliable due to a very low-duty scan cycle and the device quitting advertising before a scan cycle actually detects the advertisement. I am not sure because there is no way to detect the scanning operation like there is advertisements! It is also possible the scanning stops after a certain amount of time but there is no documentation on that.
So what I think I need to do is to somehow set the background scan rate used by the Android to a higher duty cycle (only possible in 5.0 and up) when auto-connect has been set but I do not know how to do this. I do not want to start my own scan but somehow set the background scanning rate used by Android for the reconnect. Does anyone know how to do this? Does anyone really know how autoconnect and gatt.close() are to work?
Maybe the auto-connect was NOT meant to re-connect as I indicated above?
Well after many trials and tribulations this is how I best get the Android to auto connect with the only user action being to first select the device (if using the settings menu then first pairing).
You have to trap the paired event in a BroadcastReceiver and do a BluetoothDevice.connectGatt() setting the autoconnect to true. Then when the device disconnects, invoke a gatt.connect().
Update: While the above approach works in general, it is sometimes agonizingly slow probably because the pending connection uses extremely conservative scan rates. The other downside is that for each device you want to auto-reconnect to you have to keep a BluetoothGatt object performing a pending connection. In the embedded world this is insane. Instead what one does is continuously scan and connect to a desired device by inspecting its advertisement. One saves only the minimal amount of data about the device (the services, its paired state and keys, etc.). When an advertisement is captured you see if it is one of your known devices and connect to if it is.
I tried the equivalent on Android. Scan all the time (low power rate) and connect to advertisements of interest, and maintain a class representing a known device. There are some annoying details in this approach (like turning off scanning while connecting and restarting after connected) but it basically works without the overhead of maintaining connections. BUT there is one exception I do not understand. One pre-paired device's advertisements are never seen by the scanner. However, if I invoke a pending connection to this device, I re-connect. I do not understand this at all. On my embedded platforms it works as it should.
If anyone else has tried this approach for auto-reconnecting, please share your experiences!
I have discovered the reason the pre-paired device is not seen by Android. Android only reports scan results IF the device responds to a scan request. Once paired, this device only emits advertisements and ignores scan requests, so the Android system does not pass up its advertisements in the ScanCallback. Thus in order to work using the scan approach, I have to use the pending connect approach for those specific devices. It just seems like you can't win!
============= UPDATE 2020
Many years have passed and I have a lot more experience with the background scan approach. If one keeps the supported platforms 5 and up, one can use only the newest scanner APIs and use filters, eliminating the need to decode the raw advertisements yourself. I have also found that connection and re-connection is snappier if you DONT turn off scanning while connecting. I know it goes against all documentation, but it works and on some platforms allowed connections to happen that otherwise did not. Also, to date, I have found only one (health) device that needs pending connects. Disclaimer: All I have ever worked with is health devices.
This is how I was able to do it for my application.
I first stored the address of the device in a SharedPreference then in gattClientCallback funtion of my BluetoothLeService
else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
intentAction = ACTION_DISCONNECTED;
DeviceActivity.runOnUI(() -> {
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
String name_dev_1 = sharedPreferences.getString("Dev_1", null) ;
connectToDevice(name_dev_1);
disconnectGattServer();
});
}
}
What this does is if your device is disconnected it will keep on trying to connect to it until a connection is established.
I am currently developing an application that will use Bluetooth Low Energy (testing on the Nexus 4). After getting started with the official BLE APIs in Android 4.3, I have noticed that after I connect a device for the first time I am rarely able to successfully connect to / communicate with that device or any other device again.
Following the guide here, I can successfully connect to a device, scan services and characteristics, and read/write/receive notifications without any issues. However, after disconnecting and re-connecting, I am often unable to either scan services/characteristics or unable to complete a read/write. I can't find anything in the logs to indicate why this is happening.
Once this happens I have to uninstall the application, disable Bluetooth, and restart the phone before it will start working again.
Whenever a device is disconnected I make sure to call close() on the BluetoothGatt object and set it to null. Any insights?
EDIT:
Log dumps: For these logs I rooted my phone and upped the trace levels of related items in /etc/bluetooth/bt_stack.conf
Successful connection - First attempt after rebooting the phone and installing the app. I am able to connect, discover all services/characteristics, and read/write.
Failed Attempt 1 - This is the next attempt after disconnecting from the successful connection above. It seems I was able to discover characteristics, but the first attempt to read returned a null value and disconnected soon thereafter.
Failed Attempt 2 - An example where I am not even able to discover services/characteristics.
EDIT 2:
The device to which I am trying to connect is based on TI's CC2541 chip. I obtained a TI SensorTag (also based on the CC2541) to play around with and discovered that TI released an android app for the SensorTag yesterday. However, this app has the same problem. I tested this on two other Nexus 4s with the same result: Connection to the SensorTag is successful the first or second time, but (according to the logs) fails to discover services thereafter, causing all sorts of crashes. I'm starting to wonder if it's an issue with this specific chip?
Important implementation hints
(Perhaps some of those hints aren't necessary anymore due to Android OS updates.)
Some devices like Nexus 4 with Android 4.3 take 45+ seconds to connect using an existing gatt instance. Work around: Always close gatt instances on disconnect and create a fresh instance of gatt on each connect.
Don't forget to call android.bluetooth.BluetoothGatt#close()
Start a new thread inside onLeScan(..) and then connect. Reason: BluetoothDevice#connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback) always fails, if called inside LeScanCallback() {...}.onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) in the same thread on Samsung Galaxy S3 with Android 4.3 (at least for build JSS15J.I9300XXUGMK6)
Most devices filter advertising
Better not use android.bluetooth.BluetoothAdapter#startLeScan(UUID[] serviceUuids, LeScanCallback callback) with the parameter to filter for certain service UUIDs because this is broken completely in Samsung Galaxy S3 with Android 4.3 and doesn't work for 128bit UUIDs in general.
Gatt always can process one command at a time. If several commands get called short after another, the first one gets cancelled due to the synchronous nature of the gatt implementation.
I often see even on modern devices with Android 5, that Wifi interferes withs bluetooth and vice versa. As a last resort, turn off wifi to stabilize bluetooth.
Tutorial for beginners
A pretty OK entry point for newcomers could be this video tutorial: Developing Bluetooth Smart Applications for Android http://youtu.be/x1y4tEHDwk0
The issue and work around described below is probably fixed now by OS updates
Work around: I could "stabilize" my app doing that...
I provide the user a setting "Restart Bluetooth". If that setting is enabled, I restart Bluetooth at some points that indicate the begin of BLE stack becoming unstable. E.g. if startScan returns false. A good point may also be if serviceDiscovery failes. I just turn Bluetooth off and on.
I provide another setting "Turn off WiFi". If that setting is enabled, my app turns off Wifi when the app is running (and turns it back on afterwards)
This work around is based on follwoing experiences...
Restarting Bluetooth helps to fix problems with BLE in most cases
If you turn off Wifi, the BLE stack gets much more stable. However, it also works fine on most devices with wifi turned on.
If you turn off Wifi, restarting Bluetooth fully recovers the BLE stack without the need to reboot the device in most cases.
Turning WIFI OFF:
I can confirm too, that turning WIFI OFF makes Bluetooth 4.0 more stable especially on Google Nexus (I have a Nexus 7).
The problem
is that the application I am developing needs both WIFI and continous Bluetooth LE scanning. So turning WIFI OFF was no option for me.
Moreover I have realised is that continous Bluetooth LE scanning can actually kill WIFI connection and make the WIFI adapter unable to re-connect to any WIFI network until BLE scan is ON. (I'm not sure about mobile networks and mobile internet).
This definitely happened on the following devices:
Nexus 7
Motorola Moto G
However BLE scanning with WIFI on seemed pretty stable on:
Samsung S4
HTC One
My workaround
I scan BLE for a short period of time 3-4 seconds then I turn scan OFF for 3-4 seconds. Then ON again.
Obviously I always turn BLE scan OFF when I'm connecting to a BLE device.
When I disconnect from a device I restart BLE (turn adapter OFF and then ON) to reset the stack before starting scan again.
I also reset BLE when discovering services or characteristics fails.
When I get advertisement data from a device that the app should connect to (lets say 500 times without being able to connect - thats about 5-10 seconds of advertising) I reset BLE again.
Make sure your Nexus is paired to the device. I can't verify whether or not the communication works properly, but you will be able to connect more than once without a reboot. It seems the first connect is not requiring pairing but all subsequent attempts do.
I will update this answer in a couple of days when I test service discovery and gatt read and write requests without a reboot.
EDIT:
It turns out I was testing on a development firmware version (our sensor) that was causing issues if not paired. Our latest production firmware build works fine on the 2540s and 2541s.
EDIT:
I did notice that on the Nexus 7 2013, connections are more stable when WiFi is turned off. I'd like to know if this helps anyone else.
EDIT:
I seem to have had it backwards with pairing. Everything works fine when not paired. After pairing, I am experiencing the exact same symptoms as the OP. It's just not known yet if this is related to our firmware or the Android BLE API. Be careful if testing this because once paired, you may not be able to unpair due to a bug explained in 3b of this post.
In some models there is a defect:
https://code.google.com/p/android/issues/detail?id=180440
On the other hand in my case the problem was, that my connection was not properly closed in onDestroy method. After correct closing, problem for me is not existing, not matter that wifi is turned on or off.
btGatt.disconnect();
btGatt.close();
I was facing a similar issue. My fix was
if (Build.VERSION.SDK_INT >= 23) {
mBluetoothGatt = device.connectGatt(this, false, mGattCallback, BluetoothDevice.TRANSPORT_LE);
} else {
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
}
& calling close after disconnect.