Slide 1

Slide 1 text

Talking to your bike and other devices Walmyr Carvalho Senior Android Engineer @ VanMoof Google Developer Expert for Android @walmyrcarvalho (wait, what?)

Slide 2

Slide 2 text

(seriously, it's getting out of hand at this point) There are connected devices everywhere!

Slide 3

Slide 3 text

Pixel Watch Mi Smart Scale Nothing ear (1) Wahoo TICKR X

Slide 4

Slide 4 text

I'm also a beginner cyclist, and cyclists love these devices!

Slide 5

Slide 5 text

Beeline Velo 2 SRAM Rival eTap AXS

Slide 6

Slide 6 text

This is my commuter bike, a VanMoof S3!

Slide 7

Slide 7 text

Main features ● Touch Unlock: tap a button to unlock your bike; ● Assistance level: change how much the motor helps you; ● Gear shifting moments: adjust how the bike shift gears according to your needs; ● Firmware updates: get the latest software updates for your bike; ● Lights and Sounds: set the lights behavior and change the bell sound of your bike; ● Many more! (let me demonstrate!) VanMoof App VanMoof (Google Play)

Slide 8

Slide 8 text

Like most of these devices, it connects to your phone through Bluetooth, but…

Slide 9

Slide 9 text

… how does it work, exactly?

Slide 10

Slide 10 text

Connection overview User

Slide 11

Slide 11 text

Connection overview Bike User

Slide 12

Slide 12 text

Connection overview Auth server Bike User

Slide 13

Slide 13 text

Connection overview Auth server Bike User

Slide 14

Slide 14 text

Connection overview Auth server Bike User

Slide 15

Slide 15 text

Connection overview Auth server Bike User

Slide 16

Slide 16 text

Connection overview Auth server Bike User BLE connectivity

Slide 17

Slide 17 text

Some of these concepts are applicable to other devices, so we're good!

Slide 18

Slide 18 text

OK, but how can I actually do it?

Slide 19

Slide 19 text

Slide 20

Slide 20 text

... ...

Slide 21

Slide 21 text

Android 12 Permission Source: Google I/O

Slide 22

Slide 22 text

// First, you need a BluetoothAdapter: val bluetoothManager: BluetoothManager = getSystemService(BluetoothManager::class.java) val bluetoothAdapter: BluetoothAdapter? = bluetoothManager.getAdapter() if (bluetoothAdapter == null) { // Device doesn't support Bluetooth } // Then, you can enable Bluetooth if it's not the case: if (bluetoothAdapter?.isEnabled == false) { val enableBluetoothIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) startActivityForResult(enableBluetoothIntent, REQUEST_ENABLE_BT) }

Slide 23

Slide 23 text

Bluetooth toggle pop-up Source: Android Developers

Slide 24

Slide 24 text

// Once we have the adapter and BLE connection, we can scan for devices: private val bluetoothLeScanner = bluetoothAdapter.bluetoothLeScanner private var scanning = false private val handler = Handler() // Stops scanning after 10 seconds. private val SCAN_PERIOD: Long = 10000 private fun scanLeDevice() { if (!scanning) { // Stops scanning after a pre-defined scan period. handler.postDelayed({ scanning = false bluetoothLeScanner.stopScan(leScanCallback) }, SCAN_PERIOD) scanning = true bluetoothLeScanner.startScan(leScanCallback) } else { scanning = false bluetoothLeScanner.stopScan(leScanCallback) } }

Slide 25

Slide 25 text

private val leDeviceListAdapter = LeDeviceListAdapter() // Device scan callback, including a ScanResult // which can contain one or more devices private val leScanCallback: ScanCallback = object : ScanCallback() { override fun onScanResult(callbackType: Int, result: ScanResult) { super.onScanResult(callbackType, result) leDeviceListAdapter.addDevice(result.device) leDeviceListAdapter.notifyDataSetChanged() } } // With the device, you can have the BluetoothGatt, which has the // characteristics read/write commands to interact with your device var bluetoothGatt: BluetoothGatt? = null bluetoothGatt = device.connectGatt(this, false, gattCallback) bluetoothGatt.readCharacteristic(characteristic) bluetoothGatt.writeCharacteristic(characteristic, value, writeType)

Slide 26

Slide 26 text

Sending commands Bike User Light Command Characteristic (through Gatt)

Slide 27

Slide 27 text

Yay, that's it? So now it works 100%?

Slide 28

Slide 28 text

● So many concepts to understand (Service, GATT, Characteristics, Advertising, etc) ● Differences across devices OEMs and OS versions can affect how your implementation behaves on different devices; ● You can experience a lot of false positives/negatives when developing for BLE; ● Queueing and handling of GATT messages can be also tricky/prone to errors; ● Connectivity issues is a constant ghost flying around; ● Most team/companies are shipping custom solutions to address different issues; ● Many small things… :') Well… Bluetooth is tricky :(

Slide 29

Slide 29 text

Whoa, that's a lot. Is there a library to help with this?

Slide 30

Slide 30 text

RxAndroidBle ● A RxJava-first approach for the whole BLE process; ● Observables and handy classes for device scanning, adapter state and device connectivity; ● Singles for read/write operations, to improve chaining in general; ● Helper tools to improve logging using Timber; ● We're using it in production! https://github.com/dariuszseweryn/RxAndroidBle

Slide 31

Slide 31 text

Kable ● A Kotlin Coroutines-first approach for the whole BLE process; ● Proper DSLs for scanning, filtering and connecting with BLE devices; ● KMM ready + JS support; ● Custom DataProcessor for HEX intercepting and manipulation; ● Many more features! https://github.com/JuulLabs/kable

Slide 32

Slide 32 text

Looks hard, buuuut… Google is listening!

Slide 33

Slide 33 text

Companion device pairing ● A better proposed approach to reach BLE and WiFi devices and setup a proper bonding to them; ● Improves discoverability of the devices while keeping the privacy of the user; ● Available for Android 8.0 and up; ● Recommended if Nearby Fast Pair implementations are being planned; ● The main point is that it can find devices close by without asking for the user location permission.

Slide 34

Slide 34 text

// First you need to define how you want to filter the devices // PS: BluetoothLeDeviceFilter and WifiDeviceFilter are also available val deviceFilter: BluetoothDeviceFilter = BluetoothDeviceFilter.Builder() // Match only Bluetooth devices whose name matches the pattern. .setNamePattern(Pattern.compile("My device")) // Match only Bluetooth devices whose service UUID matches this pattern. .addServiceUuid(ParcelUuid(UUID(0x123abcL, -1L)), null) .build() // Once you have this filter done, you can prepare an AssociationRequest val pairingRequest: AssociationRequest = AssociationRequest.Builder() // Find only devices that match this request filter. .addDeviceFilter(deviceFilter) // Stop scanning as soon as one device matching the filter is found. .setSingleDevice(true) .build()

Slide 35

Slide 35 text

val deviceManager = requireContext().getSystemService(Context.COMPANION_DEVICE_SERVICE) // The AssociationRequest also provides a callback function deviceManager.associate(pairingRequest, object : CompanionDeviceManager.Callback() { // Called when a device is found. Launch the IntentSender so the user // can select the device they want to pair with. override fun onDeviceFound(chooserLauncher: IntentSender) { startIntentSenderForResult(chooserLauncher, SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0) } override fun onFailure(error: CharSequence?) { // Handle the failure. } }, null)

Slide 36

Slide 36 text

// When you select a device on the system popup, it's returned as result of the intent override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { when (requestCode) { SELECT_DEVICE_REQUEST_CODE -> when(resultCode) { Activity.RESULT_OK -> { // The user chose to pair the app with a Bluetooth device. val deviceToPair: BluetoothDevice? = data?.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE) deviceToPair?.let { device -> device.createBond() // Continue to interact with the paired device. } } } else -> super.onActivityResult(requestCode, resultCode, data) } }

Slide 37

Slide 37 text

CDM is the recommended approach for more private BLE connections.

Slide 38

Slide 38 text

Bluetooth is now inside androix! Source: GitHub (androidx)

Slide 39

Slide 39 text

Emulated Bluetooth ● Supports two emulated Bluetooth devices with Virtual Bluetooth; ● Available on Android Emulator 31.3.8 and system images with API 33 (T); ● Planned to improve Bluetooth integration test with emulated devices; ● There're some plans to add different devices in the future, such as heart rate monitors and beacons! Source: Android Developers Blog

Slide 40

Slide 40 text

Besides BLE, how can we connect to Android devices in different ways?

Slide 41

Slide 41 text

Google Nearby / Fast Pair ● Improving out of box experience for devices ("AirPods"-like); ● Relies on CDM to improve BLE pairing; ● Documentation and implementation reference available both for Android and device manufacturers; ● Currently most used for headphones, but some manufacturers are already using it for different boards. https://developers.google.com/nearby Source: Google

Slide 42

Slide 42 text

Google Nearby / Fast Pair Source: Pocket-lint

Slide 43

Slide 43 text

Ultra-wide band (early) support ● Some initial API support already in Jetpack (androidx.core.uwb, version 1.0.0-alpha3) ● Some companies are already selling some developer devices with UWB support, like Estimote. ● Some Android devices are already supporting them, but not many (Pixel 6 Pro, Galaxy Note 20 and Galaxy S22 Plus/Ultra) ● Widely adopted by Apple with Find My / AirTags; ● Ideal for contextual connections, like vehicle unlocking, object finding, etc; ● Seems like the future of connectivity, but still yet to come on Android platform. Source: Estimote

Slide 44

Slide 44 text

So, to summarise…

Slide 45

Slide 45 text

Go with BLE, but watch the future! ● Connected devices are cool to work with it, but tricky sometimes (which is fine); ● BLE is the industry standard for connected devices, (at least for now); ● Google is definitely aware of the challenges around it, and things are getting better! <3 ● Fast Pair is already a reality for plenty of products, so definitely check it out; ● UWB is promising to be a good replacement for BLE in the future, but it's still yet to come!

Slide 46

Slide 46 text

Thank you and have a nice conference! ❤ Walmyr Carvalho Senior Android Engineer @ VanMoof Google Developer Expert for Android @walmyrcarvalho

Slide 47

Slide 47 text

BLE Content Recommendation Bluetooth LE for Modern Android Development, by Erik Hellman Droidcon Berlin 2021 State of BLE on Android in 2022, by Erik Hellman Droidcon London 2022 (aka tomorrow)

Slide 48

Slide 48 text

Reference Links ● Talk - Bluetooth LE for Modern Android Development - droidcon Berlin 2021 ● Slides - Bluetooth LE for Modern Android Development - droidcon Berlin 202 ● GitHub - Android X (Bluetooth) ● Ultra-wideband (UWB) communication | Android Developers ● Core Ultra Wideband (UWB) | Android Developers ● Google Fast Pair Service ● Google I/O 2022: What’s new in Android Development Tools Slides available here: tinyurl.com/dcldn22-talk-walmyr Soon available on SpeakerDeck as well!