Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Talking to your bike and other devices (wait, what?)

Talking to your bike and other devices (wait, what?)

When it comes to connectivity between Android apps and other devices, Bluetooth is usually the way to go, right? But, how does that work, exactly? And what does the future look like in that matter, by the way?

In this talk, we're going to learn how Android applications can talk with real, consumer devices (like a smart bike!), what kind of APIs and implementation options we have for making that communication happen and what's new in terms of technologies, sensors and possibilities when it comes to communicating with real devices through your Android application!

Walmyr Carvalho

October 28, 2022
Tweet

More Decks by Walmyr Carvalho

Other Decks in Technology

Transcript

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  5. Beeline Velo 2
    SRAM Rival eTap AXS

    View full-size slide

  6. This is my commuter bike, a VanMoof S3!

    View full-size slide

  7. 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)

    View full-size slide

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

    View full-size slide

  9. … how does it
    work, exactly?

    View full-size slide

  10. Connection overview
    User

    View full-size slide

  11. Connection overview
    Bike
    User

    View full-size slide

  12. Connection overview
    Auth server
    Bike
    User

    View full-size slide

  13. Connection overview
    Auth server
    Bike
    User

    View full-size slide

  14. Connection overview
    Auth server
    Bike
    User

    View full-size slide

  15. Connection overview
    Auth server
    Bike
    User

    View full-size slide

  16. Connection overview
    Auth server
    Bike
    User
    BLE connectivity

    View full-size slide

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

    View full-size slide

  18. OK, but how can I
    actually do it?

    View full-size slide



  19. android:maxSdkVersion="30" />
    android:maxSdkVersion="30" />

    android:name="android.permission.BLUETOOTH_SCAN"
    android:usesPermissionFlags="neverForLocation"/>


    View full-size slide

  20. Android 12 Permission
    Source: Google I/O

    View full-size slide

  21. // 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)
    }

    View full-size slide

  22. Bluetooth toggle pop-up
    Source: Android Developers

    View full-size slide

  23. // 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)
    }
    }

    View full-size slide

  24. 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)

    View full-size slide

  25. Sending commands
    Bike
    User
    Light Command
    Characteristic
    (through Gatt)

    View full-size slide

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

    View full-size slide

  27. ● 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 :(

    View full-size slide

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

    View full-size slide

  29. 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

    View full-size slide

  30. 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

    View full-size slide

  31. Looks hard, buuuut…
    Google is listening!

    View full-size slide

  32. 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.

    View full-size slide

  33. // 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()

    View full-size slide

  34. 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)

    View full-size slide

  35. // 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)
    }
    }

    View full-size slide

  36. CDM is the
    recommended
    approach for more
    private BLE
    connections.

    View full-size slide

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

    View full-size slide

  38. 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

    View full-size slide

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

    View full-size slide

  40. 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

    View full-size slide

  41. Google Nearby / Fast Pair
    Source: Pocket-lint

    View full-size slide

  42. 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

    View full-size slide

  43. So, to summarise…

    View full-size slide

  44. 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!

    View full-size slide

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

    View full-size slide

  46. 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)

    View full-size slide

  47. 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!

    View full-size slide