BLE: HID input device together with ancs service - android

I'm working with ANCS compatible android BLE app. The ANCS content consumer is nRF52-based thingie that listens for ANCS notifications and (should) also be able to adjust phone volume.
I've got the ANCS as solicitated UUID in the advertisement package and the HID device UUID in the advertisement response package.
All is well with iOS. All works and no problems. However with android the ANCS part of my system works ok, but I cannot get the volume part working. After bonding the android shows the device as input device and it's also selected for input. If I try to send volume up/down key, I get no indication from the android side.
My assumption was that I do not need to connect to nrf board as periperal (bluetoothdevice.connectGatt()), I've only got gatt server running and providing the nrf board the ANCS service. That part works just fine. I've also tried connecting it via connectGatt, and checking the services and enabling the notifications for it. However I cannot see any indication when I send the key. If I request read for characteristic or descriptor, that works OK.
Is there some fundamental flaw in my thinking? Shouldn't the android framework handle the keyboard part? Also why I cannot get any notification about the input_report change?

Ok, the keyboard now works also with Android. I'll listen to keyboard volume in the gatt callback. Problem with previous trial was that I just enabled & read the characteristics and descriptors in a loop. After I serialized the operations it works fine.

Related

Android: Using HID over GATT directly in Application (Gadget=HID → control Application)

I have a Bluetooth LE Joystick with a couple of buttons. I want to connect it directly to the app without using the Bluetooth Settings, but by connecting to it via BluetoothLeScanner.
I already can connect to a Heart Rate Monitor and get periodic notifications of the HR-values.
I also have created a little temperature/light/humidity sensor with an ESP32 to which I can also connnect and display the sensor values in the app.
My understanding of this HID device may be erroneous. With the help of the App BLE Scanner I can connect to this gadget via BLE and see the offered services.
One of them is 0x1812 HUMAN INTERFACE DEVICE, which contains a couple of characteristics of type REPORT, among others which are described HID OVER GATT PROFILE SPECIFICATION (HOGP_SPEC)
How can I find out which button got pressed, what position the joystick has been moved to? I guess that this has to occur via notifications to which I have to subscribe to.
Is there any Android library avaliable to handle HID input devices? What I do NOT want to do is to use the Bluetooth settings and connect to the device and have it become detected as a HID device and replace the keyboard with some odd mapping. I don't want the OS to get involved at all, just like when I connect and use the HRM and the ESP32.
I couldn't find any information on this.
I can connect to the device with my app, enumerate the services and characteristics. But from there on, I have no clue how to work with HID. Ideally I'd get notifications like "Button A has been pressed" "Joystick got moved to x=32" where x would range from -127 to 127, for example.
Accessing the HID characteristics requires the BLUETOOTH_PRIVILEGED permission since Android 5.0. The only way for an app to obtain that permission is to be signed with the same certificates as system apps.
This is a security feature, to prevent an app from receiving HID events from your keyboard and stealing your passwords.
Quoting from https://devzone.nordicsemi.com/cfs-file/__key/communityserver-discussions-components-files/4/BLE_5F00_on_5F00_Android_5F00_v1.0.1.pdf
4.6 Protected services
Android does not allow to read or write data to the following characteristics (and their descriptors):
HID Service (since Android 5):
a. HID Information
b. Report Map
c. HID Control Point
d. Report
FIDO (https://fidoalliance.org/) (since Android 6)
a. U2F (0000FFFD-0000-1000-8000-00805F9B34FB)
Only applications with BLUETOOTH_PRIVILEGED, that is, applications signed
with the same certificate as the system, are able to read and write
data to those characteristics.

Bluetooth packet capture on Android

I use the technic described here to capture the Bluetooth paquets exchanged between my Android phone and a device (a very simple device).
I can capture a lot of scanning and the pairing between the two devices, but I can't see any of the later exchanges, only the scanning.
Moreover, just after the pairing there is a huge gap in the time, and other gaps later when I think data are exchanged between the device.
For exemple, the timeline is in this form:
0-8s: scanning (LE Set Scan)
8-15s: pairing
80-120s: scanning
180-200s:scanning
I'm sure that the gaps correspond with data exchanges, but I don't know why I can't see the paquets.
I've tried simple file exchange between the phone and a computer, and I've been able to see the paquets containing the file.
I assume you are using the BLE and you are sniff the air log. According to your description, you can scan the advertisement(and scan) and the pair procedure(I assume after the pair you can see nothing).
Did you entered the LTK(long term key)? it is just something like the link key in the classic Bluetooth, with out this you can not decrypt the encrypted packages. The best method to observer the log would be check the btsnoop.log.
You said you can see the paquets between PC and your mobile phone, should be you are using classic Bluetooth actually? or you did not pairing?

How to use android as ANCS content provider?

I'm trying to demo android side service (content provider in ANCS lingo), that communicates with embedded device that supports Apple Notification Service (ANCS) notification consumer. Reason for this is, that the embedded device only supports ANCS. As the ANCS BLE side things are publiced by Apple, this should be possible and I've already added that service + associated characterics to android side gatt server. Embedded device is nordic nRF52 and SW is nordic ANCS demo. Demo works OK with iPhone and apparently with the desktop version of nRF control panel (if added with nordic supplied config and if you have windows machine, which I don't).
However I cannot seem to be able to bond the device with android, that's required before connection. The advertisement is in limited discovery mode (before bonding) so I cannot find it via regular scanning from settings. Also bonding from java code doesn't work. With mBluetoothDevice.createBond() I get ACTION_BOND_STATE_CHANGED callback with state 10 (BluetoothDevice.BOND_NONE) with old state 11(BluetoothDevice.BOND_BONDING). Apparently I would need to exchange keys here, but no idea how to do that.
Also dunno if anyone has done this same exercise before, but any other tips would also be appreciated! Thanks!
Problem was that the phone BLE stack was corrupted or in some invalid state. REboot and removing battery solved the issue with the bonding.

How to send Bluetooth data to an unknown device?

I'm asking because I've been facing that issue for weeks.
I need to develop an Android application that can be able to perform an Bluetooth Connection and send data to an Bluetooth Hardware.
Ok, so here's the point:
is it possible to perform a RFCOMM connection to an 'unknown' device?
I mean, is it possible to do this without having any information about the hardware code?
Because i'm only able to modify the AndroidDevice (cellphone) code, for SENDING purposes.
I want to send a byte and make sure it was received, but there's only a sending code.
Could we have some more details? Is the other device accessible by you, as in can the other device know information about the Android device? And what do you mean by a "sending code"?
The Android device can pick up any active Bluetooth device in its range, and know the name and address of those devices. So, if the Android device doesn't know anything about the Bluetooth device it wants to connect to, you can always sort through the list of devices in range, and get its hardware code through that.
See the documentation about Bluetooth, specifically the Finding Devices section:
http://developer.android.com/guide/topics/connectivity/bluetooth.html
I've done a fair amount of Bluetooth work with Android devices and Arduinos, and the Bluetooth library might be a bit of a pain to work with, but it is powerful.
With bluetooth the two devices have a UUID. If you a writing a program that runs on both devices you have them listen for that UUID. When they connect as a client or a server you have a dataInputStream and a dataOutputStream. Then you can push and pull bytes out of those.

Is there a way for automatic/programatic pairing of 2 bluetooth devices in android?

I am developing an application which connects devices over bluetooth and exchanges messages. It works fine for paired devices, but I would also like it to automatically pair devices that are not paired. Like for example it could store and use the same PIN for pairing requests, I just dont know how to manage this request programatically in my applciation, how to automatically set and send the PIN when you get a pairing request and how to initiate such a request with the predefined PIN code.
Any snippets or thoughts would be highly appreciated! :)
EDIT:
I know its risky, I am developing this app for emergency situations only where no other means but bluetooth is available. Also is there maybe a way of premature pairing with devices without even connecting to them? Like lets say there is a list of MAC Addresses of those devices and I can use them to generate a bond with that devices so that they appear paired on my device?
You can't do this. To do what you want to do would create a huge security risk. Think about it, my device just comes anywhere in bluetooth range of yours and now I can send you anything I want without you knowing? You can't really do this and I highly recommend not trying to subvert it.
Reflecting the setPin method allowed me to send the pin automatically to the other device. I had to implement it in a broadcast receiver that is listening for pairing requests. Although I cant get rid of the dialog it just stucks there on the screen and I dont know how to close it (programatically) and continue the bonding procedure since this dialog is called from inside connect() which is a blocking method. I am not giving up on it yet though :)
With Bluetooth version 2.1 and above there is a method of pairing called the 'just works' association model. This is the lowest security method of pairing and has no protection against man-in-the-middle attacks.
However, this will provide a secure, encrypted link without the need to exchange pin numbers or verify device ID.
The API on different platforms may differ but the underlying HCI messages require that you indicate that your device (or one of the devices) has the following IO capabilities:
No Keyboard, No Display.
As you might have guessed, this is a mode for very
simple devices that use Bluetooth, such as a speaker or headphones.
If you can find the API to configure that, then the 'just works' association mode of Secure Simple Pairing will be used for pairing.
The next step is to store the link keys e.g. bonding. Many devices e.g. mobile phones, will still create a dialogue box to the user to ask if they want to 'remember this device', as user authorisation is specified by the BT specifications... but that's another problem.

Categories

Resources