Android Lollipop BLE scan - getting peripherals without duplications - android

Android Lollipop introduced a new way to scan for BLE peripherals, via BluetoothLeScanner.
From what I read, the new scanning API solved an issue that happened with the old scanning API (BluetoothAdapter.startLeScan(UUID[],LeScanCallback)) where on some devices the callback (onLeScan) was called only once per peripheral, even if the peripheral keeps advertising.
This issue is handled on iOS with the CBCentralManagerScanOptionAllowDuplicatesKey option, that allows you to choose whether you want to detect only new peripherals or keep getting advertisements from previously-found peripherals.
Is there a similar option in the new Android Lollipop API? i.e. decide that you want the callback to be called only for new peripherals (new MAC addresses) and not called twice for the same peripheral.
I know that it could easily be implemented by saving a list\set of all the MAC addresses that were previously received - but this way does not take advantage of hardware optimizations.

Related

Android - What API can I use to see if a device supports BLE central mode?

https://developer.android.com/guide/topics/connectivity/bluetooth-le#roles
Central vs. peripheral. This applies to the BLE connection itself. The
device in the central role scans, looking for advertisement, and the
device in the peripheral role makes the advertisement.
To check if a device supports "peripheral"/advertisement mode it looks as though I can use getBluetoothLeAdvertiser()
getBluetoothLeAdvertiser
added in API level 21 public
BluetoothLeAdvertiser getBluetoothLeAdvertiser () Returns a
BluetoothLeAdvertiser object for Bluetooth LE Advertising operations.
Will return null if Bluetooth is turned off or if Bluetooth LE
Advertising is not supported on this device.
Use isMultipleAdvertisementSupported() to check whether LE Advertising
is supported on this device before calling this method.
Now I've heard some rumors that some devices can actually give you a BluetoothLeAdvertiser, but return false on isMultipleAdvertisementSupported() which is another issue in itself, but on the central side of things, the docs don't say anything!
Am I missing something? https://developer.android.com/reference/android/bluetooth/BluetoothAdapter doesn't say anything about central mode. Am I missing something basic here? Thanks for any help. I have heard bluetooth is a pain on Android and it is my first day exploring these APIs.
Short Answer
As DigitalNinja pointed out, an Android phone will always support Central role functionality by default, so if your phone supports BLE, then it can definitely operate in the central Role
Long Answer
You're right, the API might not be straight-forward but this is down to how Bluetooth Low Energy (BLE) API was added to Android and even down to the history of BLE technology itself.
When BLE was first introduced, it was aimed to be for sensors only (e.g. thermometer, heart rate, proximity, etc) and devices that talk to these sensors. The sensors were the peripherals in this case, and the devices that talk to these sensors are the centrals. The peripherals were the true Low Energy (LE) devices, as they would just advertise and send data once in a while. Centrals on the other hand would not be very power efficient as they would have to continuously scan for devices, connect to these devices, and remain in charge of maintaining and monitoring that connection, meaning the radio would be on for a much longer time when compared to the peripheral.
When Bluetooth Low Energy (BLE) API was added to Android, it supported Central role only. In other words, you could write an Android app to scan and connect to peripherals (sensors), but the Android device itself could not act as a peripheral (Because the assumption was that you wouldn't need an Android device to act as a sensor). This was done in Android 4.3 (API 18).
As people started to use BLE more often and the technology matured, it started being used for all sorts of different applications (e.g. virtual serial port, data transfer, beacons, etc). Moreover, standalone central devices started appearing in the market and there was a need to use them with phones or at least test them out against phones/tablets during the development stages. As such, the distinction between central and peripheral started becoming fuzzier and fuzzier, and there was a demand for Android to start supporting peripheral role. This is when the BLE API was updated to introduce peripheral role functionality, which happened in Android 5.0 (API 21).
So to answer your question, if BLE is supported on an Android device then it is safe to state that it will by default support central role as this is the foundation of the BLE functionality for Android. However, API was introduced later to support the peripheral role, which is why not all Android devices that support BLE will support peripheral role.
Finally, please note that isMultipleAdvertisementSupported is a different feature which indicates if your device supports sending out multiple adverts at the same time. Some devices support sending out different adverts simultaneously, while others don't. However, this does not mean that they do not support advertising at all. A device that supports isMultipleAdvertisementSupported will definitely support BluetoothLeAdvertiser, but the other way around is not guaranteed.
To conclude, the safest way to check if your device supports central and/or peripheral role is through the Android version and the API level used, as indicated by the two links above. On Android 5 (API 21) onwards, you can write applications that support both central and peripheral roles, whereas before that you can only write applications for the central role.
I hope this helps.

Android discovering same app UUID devices

I am using bluetooth adapter to discover bluetooth devices. The search displays all devices (iOS , Android, Speakers etc) which are available in surrounding with Bluetooth turned ON.
My App sends and receive data, so installed on two different Android Devices, app can perform a chat functionality, provided both apps are using same App UUID.
Is it possible that when I perform the device discovery/search, I only limit discovery to those devices which are Android and are using my App i.e. my App UUID and not to show all other bluetooth devices.
I know this happens in iOS using characteristic UUID.
Appreciate Response.
1) First you're doing an Inquiry (search) of all nearby devices
2) for each device enumerated, do a Discovery (SDP) on it to gather all its services/profiles; If you found the one you're searchnign for, display it, otherwise forget it...
PS: I have no idea about selecting Android devices only... You can use the CoD (Class Of Device) but not sure that you can separate Android from other "smartphones"...

BluetoothAdapter.startScan() vs BluetoothAdapter.startLeScan()

my goal is to find nearby Bluetooth devices(LE devices and "Classic"), in order to associate between current visible nearby devices to some functionality my app doing with it. (not a specific device/devices, but all of them!!!)
what I know:
startLeScan() would callback only with BLE devices
the two methods working in different way - while startBLeScan() managed by my code with callbacks while classic scan is managed by the system process, and returns the BluetoothDevice found via broadcasts.
what I don't know for sure:
assuming current device API level is 18+ startScan() will find always both discoverable BLE and classic devices.
BluetoothDevice.connectGatt() added with the new BLE API's, but should work also with classic bluetooth(return GATT Services...).
what I would like to know:
if indeed startScan() returns both types (Classic and BLE), what would be better to use in terms of battery consumption, performances, good practices and other aspects?
my application will perform background scans periodically, so I would like to minimize the battery consumption impact as possible.
You have to start a scan for Classic Bluetooth devices with startDiscovery() and a scan for Bluetooth LE devices with startLeScan(). Caution: Performing device discovery is a heavy procedure for the Bluetooth adapter and will consume a lot of its resources.
Edit:
On LG Nexus 4 with Android 4.4.2 startDiscovery() finds Bluetooth LE devices.
On Samsung Galaxy S3 with Android 4.3 startDiscovery() doesn't find Bluetooth LE devices.
I have an off-market Chinese tablet that has BLE support, however, it always return a BLE equipped device with its name as "null" when I call startLeScan. The issue was resolved by calling startDiscovery. Remember that if your app targets 23 or above, you will need to have location permissions for startDiscovery to work correctly. Hope it helps.

Is it possible in Android to transmit broadcast mode in BLE?

Is it possible in Android to transmit broadcast mode in BLE ?
And to add my own data on the transmission.
I know that BLE has a mode of transmiting in broadcast (not to a certain UUID).
This way it has very short connection time, which is what I need.
I failed to find how to do it in Android.
Any relevant link to the API ?
Look like the answer for android 4.3 and 4.4 is no.
Android 4.3 and 4.4 does not support BLE peripheral/broadcaster role
see
https://code.google.com/p/android/issues/detail?id=59693
and
https://code.google.com/p/android/issues/detail?id=58582
allow see this stackoverflow thread about the same issue
Android 4.3 as a Bluetooth LE Peripheral
The Android 5.0.X will only allow you to use the new API for BLE. This new API comes with a new feature, which you mentioned in your question: The possibility of advertising, from your own Android device, using it in Peripheral mode. However, the disadvantaged of this new feature is that it is hardware dependent.

How to connect Android device to an iOS device over BLE (Bluetooth Low Energy)

I'm trying to make an application which uses the new Bluetooth Low Energy API of Android. For this, I started with the BLE sample coming with API level 18.
As I read that Android can not act as a Peripheral, I put the Android phone in central mode, scanning for BLE devices around it. For this purpose, I made some testing with a Nordic Platform simulating a Heart Sensor. Everything works in a perfect way!
After this, I try to pick an iPhone (iOS 7 beta 4) and put it in a Peripheral way and simulating a Heart Rate sensor as the previous testing. The Android app is able to see the device and connect to it. But after the connection is active, the 2 devices disconnect from each other in 3-4 seconds. In addition to that, when I call discoverServices() on Android side, no callback is triggered! In some cases the Android device receives the "Connected" event even if iOS Bluetooth chip is Off. This is very strange. To prove that, I put the Nordic Board in Central mode and I was correctly able to connect to the iOS device with no problems.
What could it be? There are some limitations on Android or iOS that don't permit to connect from an Android to an iOS or viceversa?
Thanks.
EDIT: After some hard testing, I raised an issue on the AOSP page. It can be checked here
Adding a summary for reference:
What could it be? There are some limitations on Android or iOS that don't permit to connect from an Android to an iOS or viceversa?
When connecting to a GATT server that is advertised as dualmode (BLE and BR/EDR) device by calling connectGatt(...), the TRANSPORT_AUTO flag that is internally added makes Android to default to the BR/EDR mode (link).
Following workarounds are possible:
Peripheral side: Stop advertising BR/EDR capabilities by adjusting
the appropriate flags (link)
Central side: Set the transport parameter explicitely to
TRANSPORT_LE by calling the hidden version of connectGatt() using
reflection
Example:
public void connectToGatt(BluetoothDevice device) {
...
Method m = device.getClass().getDeclaredMethod("connectGatt", Context.class, boolean.class, BluetoothGattCallback.class, int.class);
int transport = device.getClass().getDeclaredField("TRANSPORT_LE").getInt(null); // LE = 2, BREDR = 1, AUTO = 0
BluetoothGatt mGatt = (BluetoothGatt) m.invoke(device, this, false, gattCallback, transport);
...
}
Edit 4/2016
As Arbel Israeli pointed out in the comment, Google introduced an overloaded version of connectGatt(...) which allows to specify the transport in Android M.
I've written a simple working example, well relatively simple, and included it open-source on Github: https://github.com/GitGarage. So far it has only been tested with an Android Nexus 9 and an iPhone 5s, but I presume it would also work with a Nexus 6 and various iPhone types. So far it is set up explicitly to communicate between one Android and one iPhone, but I presume it is tweakable to do much more.
Maybe a bit delayed, but perhaps your pain can be relieved slightly ;)
We have been experimenting a lot with cross platform BLE connections (iOS<-> Android) and learned that there are still many incompatibilities and connection issues. Aside to the instability of Android you should also consider that still, as of today, not that many Android devices actually support the BLE Peripheral mode.
Therefore, if your use case is feature driven and you only need basic data exchange I would suggest to look at Frameworks and Libraries that can achieve cross platform communication for you, without you needing to build it up from scratch.
For example: http://p2pkit.io or google nearby
Disclaimer: I work for Uepaa, developing p2pkit.io for Android and iOS.
You can now pass in TRANSPORT_LE via BluetoothDevice.connectGatt as of API 23.
Please see Android Documentation references below:
TRANSPORT_LE
Bluetooth.connectGatt
iOS Devices always be a peripheral or central but Android devices cant be rarely.In this case your iOS device must be a peripheral and android must be a central.We can think peripheral is a server and central is a client.This is simple.

Categories

Resources