BluetoothPairingStateProvider: getUuids() returns null for device - android

Context:
I am working on a FIDO-U2F bluetooth authenticator with a nRF52 BLE SoC. and want it to test with google example.
So far I have implemented the FIDO Bluetooth specification and I have a device that advertises as a FIDO-compatible device.
Thanks to nRF Connect I have ensured that all the services and characteristics are correctly exposed and that I can interact with it only when my device is securely paired (with LTK):
Problem:
When the app scans for eligible FIDO device, it does not find mine.
I am stuck on the screen that ask to press a button for 5s, which I don't need to since my device responds to pairing request without user interaction and is already paired with my SAMSUNG A8.
I/BluetoothDevicePreference: onDeviceAttributesChanged :: Device = (N) D8BE86, isBonded = 12 , mIsOnProgressAddVI = false
I/Fido: [BleScanner] startScan()
E/Fido: [BluetoothPairingStateProvider] getUuids() returns null for device: D8:BE:86:4A:E5:65
I/Fido: [PreferredTransportProvider] BLE enabled but no device is paired
I/Fido: [AuthenticateBaseChimeraActivity] User selected transport ble
I/Fido: [ViewController] Accepting proposed view {"viewName":"ble_instructions","anyU2fDevicesPaired":false}: outranks current (2 > 0)
I/Fido: [ViewPresenter] viewSelected(...) ble_instructions
I/Fido: [U2fRequestController] onResultReceived(null, ErrorResponseData{errorCode=5})
I/Fido: [BleScanner] stopScan()
I tried to remove pairing data and all I have is:
I/BluetoothDevicePreference: onDeviceAttributesChanged :: Device = (N) D8BE86, isBonded = 10 , mIsOnProgressAddVI = false
The advertising flags are currently set to "BR/EDR not supported", but I also tried "LE Limited Discoverable Mode" and "LE General Discoverable Mode" without success.
I looked into android-fido sources but the BLE scan seems imported from elsewhere, I cannot debug it in this project.
Any pointer is welcome

Have you got to this screen?
We may need to add Service Data field (0x16) into advertising packet. This is mentioned in FIDO specification here
Android code snippet for advertising with Service Data field added:
AdvertiseData data = new AdvertiseData.Builder()
.addServiceUuid(new ParcelUuid(fido2GattService.getUuid()))
.setIncludeDeviceName(true)
.addServiceData(new ParcelUuid(fido2GattService.getUuid()), new byte[] {(byte)192, (byte)192, (byte)192})
.build();
If you want to capture bluetooth packets to see what is your advertising packet, you can use PacketLogger (for MacOS)
Here is the screenshot of the advertising packet
The red box is Service Data

Related

how to make BLE autoconnect to Bluetooth of android phone without pairing

I am having a Arduino with BLE which has to send some data to any/all android phones over Bluetooth in it's range. My android phone should have a app which i intend to make will notify about data received.
How can i make such android app which auto-connects to any nearby BLE , if found without pairing even for first time and exchange data. I mean how in any application i can implement auto-connect without key pairing.I found that setting autoconnect=true will do this task , but i am not sure.
Any help, even some resource i will refer and clear my doubts.
The pre-requisites and steps are (code snippets in Java):
HC-XX module or similar BLE-device on the Arduino-side set to security mode 1 and security level 1 (no security AND no pairing)
Android 4.3 (API level 18) with built-in platform support for Bluetooth Low Energy (BLE)
Check on the device (mobile) that BLE is enabled
// Ensures Bluetooth is available on the device and it is enabled. If not,
// displays a dialog requesting user permission to enable Bluetooth.
if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
Find the BLE device(s). You use the startLeScan() method. This method takes a BluetoothAdapter.LeScanCallback as a parameter. You must implement this callback, because that is how scan results are returned. Because scanning is battery-intensive, you should observe the following guidelines:
As soon as you find the desired device, stop scanning.
Never scan on a loop, and set a time limit on your scan. A device that was previously available may have moved out of range, and continuing to scan drains the battery.
If you want to scan for only specific types of peripherals, you can instead call startLeScan(UUID[], BluetoothAdapter.LeScanCallback), providing an array of UUID objects that specify the GATT services your app supports.
The first step in interacting with a BLE device is connecting to it— more specifically, connecting to the GATT server on the device. To connect to a GATT server on a BLE device, you use the connectGatt() method. This method takes three parameters: a Context object, autoConnect (boolean indicating whether to automatically connect to the BLE device as soon as it becomes available), and a reference to a BluetoothGattCallback.
// Here we set autoconnect to true
bluetoothGatt = device.connectGatt(this, true, gattCallback);
To sum up auto connect alone will not do the job as you want no pairing. So security mode 1 and security level 1 (no security at all) has to be set. So make sure by using software sided encryption/auto sign-in that no unauthorized persons use your device
Read more about BLE in Android in detail here
Read more about BLE security in detail here

BLE peripheral pairing pin on android

I implemented a GATT Server and Client App on Android. The connection is working and I forced pairing by adding PERMISSION_READ/WRITE_ENCRYPTED_MITM to all of the GattCharacteristics.
But the pairing behavior differs on different clients:
1) Pin is shown on the client/central (Android 5 on Samsung Galaxy S3) and should be insert on the server/peripheral (Android 7 on Nexus 5).
2) Passkey is shown on both devices client/central (Android 5 on Samsung Galaxy S3) and server/peripheral (Android 6 on Nexus 7)
3) Pairing with Windows or iOS fails with server/peripheral expecing a pin for input.
What I expected and want to happen is:
Pin is shown on the server/peripheral and has to be insert on client/central
Is there any way to configure that behavior?
Thanks in advance!
EDIT
Here is my setup:
BluetoothGattService gattService = new BluetoothGattService(
serviceUUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
gattService.addCharacteristic(new BluetoothGattCharacteristic(
charReadUUID,
BluetoothGattCharacteristic.PROPERTY_READ,
BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED_MITM
));
gattService.addCharacteristic(new BluetoothGattCharacteristic(
charWriteUUID,
BluetoothGattCharacteristic.PROPERTY_WRITE,
BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED_MITM
));
gattServer.addService(gattService);
...
AdvertiseSettings settings = new AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
.setConnectable(true)
.build();
AdvertiseData data = new AdvertiseData.Builder()
.setIncludeTxPowerLevel(false)
.addServiceUuid(serviceUUID)
.build();
BluetoothLeAdvertiser advertiser = adaper.getBluetoothLeAdvertiser()
advertiser.startAdvertising(settings, data, callback);
Summary: Set the I/O Capabilites of your client to "Keyboard Only".
Explanation:
I am not fully sure what happens "under the hood" of your system. But I can tell you what should be happening according to the BLE CoreSpec. First see CoreSpec V4.2, Vol. 3, Part H, chap. 2.3.5.1, table 2.7 & 2.8. There it is defined which pairing is used, depending on the authentication requirements and the I/O capabilities of the devices.
What you want is described as "Passkey Entry: responder displays, initiator inputs". This is the case if legacy pairing (pairing according to Bluetooth V4.0) is used, and if:
the server (responder) has a display AND
the client (initiator) has a keyboard AND
server and client do NOT both have display AND keyboard.
(And if OOB data is not used and MITM is enforced, but I assume this as given.) Note that if both client and server have display and keyboard, the default case is that the client displays and the server inputs. It would seem that if your protocol automatically handles pairing, it will also automatically chose the pairing method as defined in the CoreSpec.
So what you see is corresponding to different I/O capabilities of different servers. It seems that your client has display and keyboard, so if you use a server with display and keyboard, the client will display the passkey and the responder will wait for input (which fits to your case 1). For case 2, we have Numeric Comparison; this is only possible if LE Secure Connections (pairing according to Bluetooth V4.2) is supported by both client and server.
For case 3, I don't know what is going on, but it may be a problem between an Android system and an iOS system not operating well together (but I have no idea why).
Since pairing seems to be fully automized here, the only possibility to change things is to change the I/O capabilities. There should be a function to change these capabilities, check your manual. If you do not want to use a display on the client, set its I/O capabilities to "Keyboard Only" and it will exhibit the behavior you expect.(*)
(*) This holds only if you use legacy pairing. If both devices support LE Secure Connections, it is recommended that you use this newer pairing protocol, since it removes security issues with the old protocol. (I would however assume that in this case, the newer protocol is used automatically anyway.)

BLE with Android 5.0 : How to get a device to act as Central AND Server?

I'm using two Android 5.0 devices to communicate through Bluetooth Low Energy and I wan't :
Device 1 to act as Central and Server.
Device 2 to act as Peripheral and Client.
This is the behavior I'd like to achieve :
1) Device 2 starts advertising (peripheral role).
2) Device 1 starts scanning (central role), and gets the advertising device (BluetoothDevice object) through the ScanCallback's onScanResult method.
3) I now want the advertising device (Device 2) to be notified that it has been scanned and be able to get the BluetoothDevice associated with Device 1.
4) Device 1 has an instance of BluetoothGattServer. Device 2 would now call connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback) on Device 1 to get an instance of BluetoothGatt.
5) In the end, Device 1 is Server and Device 2 is Client.
So far I've found that in step 2, once Device 1 holds the BluetoothDevice for Device 2, it can only connect as client like in step 4 using connectGatt.
I might be able to use the BluetoothGattServer defined in Device 1, and call : gattServer.connect(BluetoothDevice device, boolean autoConnect) with device being Device 2.
But how will Device 2 be notified it's been connected to ?
And how will I get an instance of BluetoothGatt in Device 2 if I can't call connectGatt(Context, boolean, BluetoothGattCallback) on a BluetoothDevice?
Thank you in advance for your help !
Some documentation :
BluetoothGattServer
BluetoothDevice
1) Device 2 starts advertising (peripheral role).
Peripheral role will advertise, make sure to add CONNECTABLE
AdvertiseSettings.Builder settingBuilder = new AdvertiseSettings.Builder();
settingBuilder.setConnectable(true);
And start advertisement accordingly.
2) Device 1 starts scanning (central role), and gets the advertising device (BluetoothDevice object) through the ScanCallback's onScanResult method.
Perfect, now call connectGatt on this device(peripheral), make sure you stops the advertisement after you gets required device, otherwise you will end up sending multiple connect commands.
3) I now want the advertising device (Device 2) to be notified that it has been scanned and be able to get the BluetoothDevice associated with Device 1.
When you calls connectGatt from Central/client role, your peripheral will get a notification in its BluetoothGattServerCallback'onConnectionStateChange.
there you will know that connection has been made. though you have to register gatt Service with characteristics at peripheral side.
4) Device 1 has an instance of BluetoothGattServer. Device 2 would now call connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback) on Device 1 to get an instance of BluetoothGatt.
Wrong, Device 1 will initiate connection as I have stated in point 3. both device's onConnectionStateChange will be called to know that connection has been made.
5) In the end, Device 1 is Server and Device 2 is Client.
Wrong, Device 2 is peripheral(Server), Device 1 is Monitor(Client)
You must turn it around a bit.
The scanner is the one connecting to the advertiser.
Dev1 scans dev2 adv and scan response. then dev1 should connect. Dev2 will get callback on connect.
There is no callback when someone hear your adv or request scan response on android.
Check instead 0x14 «List of 16-bit Service Solicitation UUIDs» from btsig if You want to advertise request for servers with a certain service to connect to You. It is a bit unusual ti see this used.

Android 5.0 peripheral mode, how to add data to a scan response

When advertising from an android device (supports BLE Peripheral mode)
Is there a way to add advert data elements to a scan response?
I think it is sending empty scan responses when a central role device is doing an active scan as we are recieving two RSSI values in our own hardware
Use the start advertising method with that has two arguments of type AdvertiseData. One will be the Advertisement packet and the other is the scan response. See this constructor from Android developer site:
startAdvertising(AdvertiseSettings settings, AdvertiseData advertiseData, AdvertiseData scanResponse, AdvertiseCallback callback)

Android Bluetooth Low Energy Motorola API pairing

I am working on using the BT 4.0 API that Motorola has provided with the RAZR. In one of their documents it states to use the Android API to pair before connecting and using their framework. Per their instructions I have been pairing with OS Bluetooth settings application, but it never prompts me for a key. It will pair but doesn't appear to bond, and this is critical for me.
My question is, when they say "using the Android API" is this referring to simply using the OS Bluetooth utility to pair before hand (like I have been doing), or is there some way to do it with code in my application. They reference the "createBond()" function which, to my knowledge, is not an accessible function (at least not without some squirrely libraries or reflection).
Any advice is greatly appreciated, especially anyone who has used the API successfully, if they could give an account of their process. I'm just looking for some clarity at this point :)
Lloyd,
You are correct, follow the instructions in the link you posted.
Outside of coding, when they say use the standard android api for "non-le" operations, they mean go ahead and pair the ble device the same way you would any bluetooth classic devices inside android settings -> wireless & network -> bluetooth -> scan for devices.
If the device you are using is a motorola le compatible device the ble device will be paired but not connected.
Now, in the code, you can detect this paired device through the same method of
BluetoothAdapter.getDefaultAdapter().getBondedDevices()
To double check if your Android Phone is LE compatible, run this code:
public static boolean checkBLESupport() {
boolean deviceSupportsLE;
try {
#SuppressWarnings({ "unused", "rawtypes" })
Class object = Class.forName("android.server.BluetoothGattService");
deviceSupportsLE = true;
} catch (Exception e) {
deviceSupportsLE = false;
}
return deviceSupportsLE;
}
And to double check if the bluetooth device you paired is LE, when you are looping through the bonded devices.
Check the device with this code.
if (device.getBluetoothClass() == null) {
Log.i(TAG, "This device is BLE compatible");
b = true;
} else {
Log.i(TAG, "This device is not BLE");
b = false;
}
Now for establishing connection from your LE compatible phone to your LE compatible bluetooth device, follow the Gatt service instructions under the link you posted. http://developer.motorola.com/docs/bluetooth-low-energy-api/
Take note that under this example it is connecting to a bluetooth low energy heart rate monitor.
If you are not trying to connect to the heart rate monitor with LE heart rate profile, here is a link to another Motorola document that details creating your own LE Profile to use with the GATT framework. http://developer.motorola.com/docs/bluetooth-low-energy-gatt-framework-api/
If the instructions are not clear enough at any point in either of these documents, motorola offers sample android applications using the frameworks in those documents.
I guess motorola stack has BLE support. But what i feel is that it does not pair with the devices that require bonding though It does work some sensors. I have tried with a proximity sensor that require bonding. It never gets paired though the devices is discovered with Razr which even does not with S3.
There's a helpful video here.
Late to the game, but can confirm -
If your BLE Peripheral requires bonding, Moto X - and some other older Motorola devices - MUST be paired via Bluetooth Settings prior to programmatic connection via the Android GATT interface.
If you bond via the createBond method, or reading of an encrypted characteristic, your connection will be dropped typically in under 60 seconds, despite DDMS logs that show a good bond may be established.

Categories

Resources