16 July, 2014

BLE: Bluetooth Low Energy New APIs On Android L Preview


This document describes the results of an investigation into new BLE APIs provided by Android L Preview.

BluetoothLeScanner

This class provides methods to perform scan related operations for Bluetooth LE devices.

startScan(List filters, ScanSettings settings, ScanCallback callback)

ScanFilter class


Q: Currently we only care about the RSSI filter and UUID filter,  will these filters work?
A: Yes. RSSI filter and UUID filter work well for a single filter.

ScanFilter uuidFilter = new ScanFilter.Builder().setRssiRange(-75, 0).setServiceUuid(new ParcelUuid(UUID.fromString("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"))).build();

Q: If we have more than one filter, what logic strategy will the scanner apply? AND or OR ?
A: The scanner will apply OR logic, once one filter matches, then we get the advertisement data.


ScanSettings class


Q: How many callback types?
A: Currently only one: ScanSettings.CALLBACK_TYPE_ON_UPDATE
which means to callback each time when a bluetooth advertisement is found.

Q: What’s differences of scan mode?
A: There are three scan modes: Balanced, low latency, and low power.
Different modes mean different scan frequency.

Here is the test result:
Balanced: 0.03s - 0.1s
Low Latency: ~0.03s
Low Power: 0.1s (Default)

Q: What’s usage of API setReportDelayNanos?
A: Not clear.

ScanCallback class


Q: Does the scan result contain device info, rssi, and scan data?
A: Yes.

Q: How to parse scan data?
A: Android provides a new class ScanRecord, we can call a class method: ScanRecord.parseFromBytes(byte[] scanRecord).
Here is the example of scan data:
02011a1106xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx09084c69676874426c7514ff4c00010000000000000000000000000000100000000000000000000000

Advertise Flags  => scanRecord.getAdvertiseFlags();  => 02011a
Local Name => scanRecord.getLocalName();  => 09084c69676874426c75
Manufacturer Id => scanRecord.getManufacturerId();  => 0x4c00 (Low endian)  == 76
Manufacturer data => scanRecord.ManufacturerSpecificData(); => 4c000100000000000000000000000000001000
Service data => scanRecord.getServiceData ();  =>  Null
Service UUID => scanRecord.getServiceDataUuid(); =>  Null
Service UUID list =>  scanRecord.getServiceUuids(); => [xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx]
Tx Power Level => scanRecord.getTxPowerLevel() => Integer.MIN_VALUE for iOS advertisement data.

Summary


Android L provides scan filters and scan parser for BLE scanning, which allow us to filter by RSSI, Service UUID, and also provide an easy way to parse advertisement data.

Note, UUID filter only works when iOS app is in the foreground, but should work when android BLE App is in the background. Since when the app in the background, it will still advertise UUID or other data.

BluetoothLeAdvertiser

This class provides a way to perform Bluetooth LE advertise operations, such as start and stop advertising. An advertiser can broadcast up to 31 bytes of advertisement data represented by AdvertisementData.

startAdvertising(AdvertiseSettings settings, AdvertisementData advertiseData, AdvertiseCallback callback)

startAdvertising(AdvertiseSettings settings, AdvertisementData advertiseData, AdvertisementData scanResponse, AdvertiseCallback callback)

AdvertiseSettings Class


  • Advertise Mode
Different Mode means different advertise frequency:

Advertise Mode
Frequency
ADVERTISE_MODE_LOW_LATENCY
approx 1 Hz
ADVERTISE_MODE_BALANCED
approx 3 Hz
ADVERTISE_MODE_LOW_POWER
approx 10 Hz  

After test, we can confirm that there is a bug in Android document:
BUG: ADVERTISE_MODE_LOW_POWER actually is the high power mode.

  • Tx Power Level

Different Tx Power Level means different visibility range.

  • Advertise Type

ADVERTISE_TYPE_SCANNABLE, ADVERTISE_TYPE_NON_CONNECTABLE, ADVERTISE_TYPE_CONNECTABLE.

For detailed info, please refer to Bluetooth Specification V4.1 vol6, part B, section 4.4.2 - Advertising state.

BUG: Even set Advertise type as ADVERTISE_TYPE_NON_CONNECTABLE, we can still see the scan data.

AdvertisementData Class


  • setIncludeTxPowerLevel
Whether the transmission power level should be included in the advertising packet.
We can see the adv data like [02 0a 00].

  • setManufacturerData
Set manufacturer id and data.
E.g. setManufacturerData(1,new byte[]{0x4c,0x00,0x01,0x02});
We can see the adv data like [ff 4c 00 01 02].

  • setServiceData
We can set 128-bit UUID also, not only 16-bit UUID.
We can see the adv data like [16 01 02]

  • setServiceUuids
Set the service uuids.
Actually we can only set one 128 bit UUID, since two 128-bit UUIDs will use 32 bytes, which will not be allowed.

Summary

For advertiser, we cannot set Local Name, which should consider as a BIG defect.
It will advertise the same package when the app is in the background.  There is no FG/BG difference.
Android supports multiple apps to advertise packages concurrently. We can see Android uses different Mac address for different advertiser.
We only see the scan data if we set ADV and SCAN data both.  In short, SCAN data always response to other BLE scanner like Android 4.4.2 or BT tool.