As our team was designing and implementing an open API for COVID-19 contact-tracing, we also created a smartphone app to demonstrate how fully-anonymised automated contact-tracing can be done with a smartphone app. In this post, we’ll discuss how the app works and how it was developed.
The requirements were to develop an app (initially for Android and later for iOS) which could use bluetooth low-energy to register close contacts (<2m) with other people. The contacts are stored in a central database (via the API) and if one of those contacts tests positive for COVID-19 up to 14 days after contact has been made, alerts are sent to all participants who have had contact during that period.
The app should record both the proximity of the contact (only contacts of <2m are likely result in infection) and the duration of the contact (the longer the contact, the greater the risk).
The app should not require any personal details of the participants.
Android introduced and API for detecting Bluetooth Low Energy devices as early as in Android 4.3 Jelly Bean. Since this version was later marked deprecated and replaced by a more powerful API with android Version 5.0, we decided to use the new API to strike a balance between supporting as many Android devices as possible (Up to 90% of Android Devices run Android 5.0 or higher) and creating a future-proof application with as much functionality as possible.
The general approach we use to detect nearby devices consists of two processes. In order to be able to detect other devices we enable scanning for bluetooth devices.
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); BluetoothLeScanner scanner = adapter.getBluetoothLeScanner(); scanner.startScan(Collections.singletonList( new ScanFilter.Builder().build()), new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_BALANCED).build(), scannerCallback);
The second part of this is for a device to be able to be detected by other devices. This is done by sending out advertising packages, which can in return be detected by the bluetooth scanner we just enabled. A bluetooth low energy advertising package can have a payload of up to 39 bytes, which includes a header of 2 bytes and the MAC-address of 6 bytes. That leaves us with 31 bytes worth of data. The data itself consists of 1byte for length and 1 byte for the type of the following data. We use the remaining 29 bytes to include a service UUID of 16 bytes to be able to filter the packages from our application against others and a 13 byte id, which is the public broadcasting id used to identify the user.
BluetoothLeAdvertiser advertiser = adapter.getBluetoothLeAdvertiser(); AdvertiseSettings settings = new AdvertiseSettings.Builder() .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED) .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_LOW) .setConnectable(false) .setTimeout(0) .build(); AdvertiseData data = new AdvertiseData.Builder() .addServiceData(ParcelUuid.fromString(SERVICE_UUID), idService.getPublicId()) .setIncludeDeviceName(false).setIncludeTxPowerLevel(false) .build(); advertiser.startAdvertising(settings, data, advertCallback);
Distance approximation over BLE
Bluetooth low-energy provides no distance measurement, so we have to rely on translating signal strength (RSSI) into distance. Based on a limited test set, we came up with an approximation as follows (based on advertisement using Android’s lowest TX power level: ADVERTISE_TX_POWER_ULTRA_LOW):
distance (in meters) = 10^((-89 - RSSI)/(10*3))
This formula obviously needs to be treated with extreme caution since it’s based on a sample of two similar phones.
How to get in touch
Armstrong Consulting Services GmbH