Share
Embed
Connecting the Bean: the bumpy road of BLE on Android
Slides from my talk at the Android Developer Days in Ankara
Hugo Visser
May 09, 2015
Transcript
53 slides
-
Connecting the bean: The bumpy road of BLE on Android
Hugo Visser Little Robots source: https://www.flickr.com/photos/klaasjan/6295632164 -
The bumpy road of BLE on Android LightBlue Bean 3
Prototyping Arduino + BLE Accelerometer, LED, temperature Coin cell battery punchthrough.com/bean -
The bumpy road of BLE on Android LightBlue Bean 3
Prototyping Arduino + BLE Accelerometer, LED, temperature Coin cell battery punchthrough.com/bean -
The bumpy road of BLE on Android LightBlue Bean 3
Prototyping Arduino + BLE Accelerometer, LED, temperature Coin cell battery punchthrough.com/bean -
The bumpy road of BLE on Android LightBlue Bean BLE
“serial” protocol Control LED & Arduino Read sensors & configuration 4 -
The bumpy road of BLE on Android LightBlue Bean BeanLoader
for OS X LightBlue for iOS BeanLoader of iOS BeanLoader for Windows (2015) SDK for OS X and iOS 5 -
The bumpy road of BLE on Android LightBlue Bean BeanLoader
for OS X LightBlue for iOS BeanLoader of iOS BeanLoader for Windows (2015) SDK for OS X and iOS 5 -
The bumpy road of BLE on Android LightBlue Bean Unofficial
Android SDK est. July 2014 bitbucket.org/littlerobots/beanlib MIT License 6 -
The bumpy road of BLE on Android LightBlue Bean Unofficial
Android SDK est. July 2014 bitbucket.org/littlerobots/beanlib MIT License 6 -
The bumpy road of BLE on Android Beanloader! Official Android
app by Punch Through Released end of April 2015 7 -
The bumpy road of BLE on Android 8 Next up:
What is Bluetooth LE Code -
The bumpy road of BLE on Android 9 Bluetooth Low
Energy Branded: Bluetooth Smart Low power, low transmission rate (1 Mbps) Sports & fitness, health care, keyboards and mice, beacons, wearables, … -
The bumpy road of BLE on Android 10 Generic Access
Profile Peripheral is advertising it’s presence Observer scans for peripherals -
The bumpy road of BLE on Android 11 Generic Attribute
Profile Profiles Services Characteristics -
The bumpy road of BLE on Android Profile Service Characteristic
Characteristic Service Characteristic 11 Profiles Services Characteristics GATT -
The bumpy road of BLE on Android 12 UUIDs Unique
identifier for services, characteristics (and descriptors) Profile a495ff10-c5b1-4b44-b512-1370f02d74de a495ff11-c5b1-4b44-b512-1370f02d74de 0000180F-0000-1000-8000-00805F9B34FB Reserved base UUID 00002A19-0000-1000-8000-00805F9B34FB -
The bumpy road of BLE on Android 12 UUIDs Unique
identifier for services, characteristics (and descriptors) Profile a495ff10-c5b1-4b44-b512-1370f02d74de a495ff11-c5b1-4b44-b512-1370f02d74de Reserved base UUID 0000180F-0000-1000-8000-00805F9B34FB 00002A19-0000-1000-8000-00805F9B34FB -
The bumpy road of BLE on Android 12 UUIDs Unique
identifier for services, characteristics (and descriptors) Profile a495ff10-c5b1-4b44-b512-1370f02d74de a495ff11-c5b1-4b44-b512-1370f02d74de Reserved base UUID 180F 2A19 -
The bumpy road of BLE on Android 13 What about
beacons? Formatted advertisement packets iBeacon, UriBeacon, proprietary Use rssi to determine distance -
The bumpy road of BLE on Android 14 Android BLE
Platform API since Android 4.3 (API 18) Part of bluedroid -
The bumpy road of BLE on Android 15 First steps
Declare permissions in AndroidManifest.xml <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/> Require Bluetooth BLE if essential to the app -
The bumpy road of BLE on Android 16 First steps
Check for BLE support if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { // awww snap :( No LE support } -
The bumpy road of BLE on Android 17 First steps
Get the Bluetooth Adapter BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); (but…this also works) mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); -
The bumpy road of BLE on Android 18 First steps
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } Check that bluetooth is enabled -
The bumpy road of BLE on Android Find me a
device BluetoothAdapter. startLeScan() and LeScanCallback 19 public boolean startLeScan (BluetoothAdapter.LeScanCallback callback) -
The bumpy road of BLE on Android Small bump #1
What does false mean? Most likely: Bluetooth is disabled (but you checked) Or…infamous bugs (check logcat) 20 -
The bumpy road of BLE on Android Small bump #2
How many callbacks per device? a) One b) Many c) It depends 21 -
The bumpy road of BLE on Android Small bump #2
How many callbacks per device? a) One b) Many c) It depends 22 -
The bumpy road of BLE on Android Find me type
of device public boolean startLeScan (UUID[] serviceUuids, BluetoothAdapter.LeScanCallback callback) 23 -
The bumpy road of BLE on Android Find me type
of device public boolean startLeScan (UUID[] serviceUuids, BluetoothAdapter.LeScanCallback callback) Does not work with 128 bit UUIDs Solution: DIY filtering stackoverflow.com/questions/18019161/startlescan-with-128-bit- uuids-doesnt-work-on-native-android-ble-implementation 24 -
The bumpy road of BLE on Android Now for some
good news 25 -
The bumpy road of BLE on Android Now for some
good news 25 -
The bumpy road of BLE on Android BluetoothLeScanner Filtering Batching
of results* Power modes* ParcelUuid uuid = ParcelUuid.fromString("a495ff10-c5b1-4b44-b512-1370f02d74de"); BluetoothManager bm = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); BluetoothAdapter adapter = bm.getAdapter(); ScanFilter scanFilter = new Builder().setServiceUuid(uuid).build(); ScanSettings settings = new ScanSettings.Builder().build(); * this asterix might spoil the party 26 -
The bumpy road of BLE on Android BluetoothLeScanner adapter.getBluetoothLeScanner().startScan(singletonList(scanFilter), settings,
new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { // process the result, there's currently only one callbackType defined } @Override public void onBatchScanResults(List<ScanResult> results) { // terms and conditions apply } @Override public void onScanFailed(int errorCode) { // handle error based on the errorCode! } }); 27 -
The bumpy road of BLE on Android *one more thing
Power modes & batching require hardware support 28 -
The bumpy road of BLE on Android BluetoothGatt Manages the
connection to the peripheral Don’t forget to close() when done, manage reference carefully! 30 -
The bumpy road of BLE on Android Auto connect? Advice
against using autoConnect = true Behaviour is unclear Disconnect to cancel does not work on 4.3 Recommendation: manage (re)connection in your app 31 -
The bumpy road of BLE on Android BluetoothGattCallback Typical sequence:
1. onConnectionStateChange() 2. call discoverServices() 3. onServicesDiscovered() 4. read / write characteristics and / or subscribe to updates 5. close() when done 32 -
The bumpy road of BLE on Android Connection & discovery
BluetoothDevice device = ... // obtained from scanning device.connectGatt(this, false, new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (status == BluetoothGatt.GATT_SUCCESS) { if (newState == BluetoothGatt.STATE_CONNECTED) { if (!gatt.discoverServices()) { // requesting service failed, make sure we clean up gatt.close(); } } } else { // connection failed, clean up gatt.close(); } } public void onServicesDiscovered(BluetoothGatt gatt, int status) { // find the service we like to use mSerialService = gatt.getService(BEAN_SERIAL_CHARACTERISTIC_UUID); if (mSerialService == null) { // service is not found, close the client gatt.close(); } } }); 33 -
The bumpy road of BLE on Android Not in the
docs Limited amount of LE connections (total!) 4 connections on 4.3 7 on 4.4+ 34 -
The bumpy road of BLE on Android Characteristics public void
onServicesDiscovered(BluetoothGatt gatt, int status) { BluetoothGattCharacteristic characteristic = service.getCharacteristic(BEAN_SERIAL_CHARACTERISTIC_UUID); if (!gatt.readCharacteristic(characteristic)) { gatt.close(); } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { byte[] value = characteristic.getValue(); String stringValue = characteristic.getStringValue(0); } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) { boolean bonding = gatt.getDevice().createBond(); // note: API 19 gatt.close(); } else { gatt.close(); } } 35 -
The bumpy road of BLE on Android Notifications public void
onServicesDiscovered(BluetoothGatt gatt, int status) { BluetoothGattService service = gatt.getService(UUID.fromString("a495ff10-c5b1-4b44-b512-1370f02d74de")); BluetoothGattCharacteristic characteristic = service.getCharacteristic(BEAN_SERIAL_CHARACTERISTIC_UUID); if (characteristic == null) { gatt.close(); return; } if (gatt.setCharacteristicNotification(characteristic, true)) { UUID descriptorUuid = UUID.fromString("2902-0000-1000-8000-00805f9b34fb"); // remember? BluetoothGattDescriptor descriptor = characteristic.getDescriptor(descriptorUuid); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); if (!gatt.writeDescriptor(descriptor)) { gatt.close(); } } } public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { if (status != BluetoothGatt.GATT_SUCCESS) { gatt.close(); } } 36 -
The bumpy road of BLE on Android Profit! @Override public
void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { // handle updated value } 37 -
The bumpy road of BLE on Android Notification limits There’s
a hard limit on the number of notifications you can have: 4 on Android 4.3 7 on Android 4.4 15 on Android 5 38 -
The bumpy road of BLE on Android Writing characteristics public
void write(byte[] data) { mCharacteristic.setValue(data); if (!mGatt.writeCharacteristic(mCharacteristic)) { mGatt.close(); } // important: wait for onCharacteristicWrite callback before attempting the next write! } 39 -
The bumpy road of BLE on Android Juggling writes By
design the Bean SDK does a lot of writing Split data in 20 byte packets, write to characteristic Assemble packets from notifications Single characteristic for read/write makes it harder 40 -
The bumpy road of BLE on Android Conclusions Android has
full support for BLE, maturing in Lollipop The BLE related API’s are is a really low level Error checking all over the place Documentation could use some work 41 -
The bumpy road of BLE on Android Observations Complexity managing
multiple characteristics in a single callback. Low level interface seems straightforward, but is difficult to get right. Bean SDK has GattClient to solve some of those problems 42 -
The bumpy road of BLE on Android Learn more bitbucket.org/littlerobots/beanlib
d.android.com/guide/topics/connectivity/bluetooth-le.html punchthrough.com/bean 43 -
The bumpy road of BLE on Android Thank you @botteaap
google.com/+hugovisser www.littlerobots.nl 44