I have a bluetooth HID device that I need to get working with my app running on a Nexus 7 2013 tablet running custom build forked from android 5.0. so:
#hide is not a constraint
Changes to AOSP are permitted
Any Android version 5.0* - 5.1* is fine
Now my device has a keyboard, AND sends and accepts some vendor-specific HID reports. By working, I mean sending and receiving all HID reports
Based on the AOSP source-code exploration I have done, it seems that:
The HidService service broadcasts BluetoothInputDevice.ACTION_REPORT intents for all input HID reports [My app has a BroadcastReceiver to receive ACTION_REPORT intents]
BluetoothInputDevice provides other interfaces like setReport(), sendData(), connect() etc through HidService.
BluetoothInputDevice uses HidService to provide HID device interface.
HidService.java is a JNI wrapper over com_android_bluetooth_hid.cpp
com_android_bluetooth_hid.cpp, on initialization of HidService, will register its own callbacks to Bluedroid
I have added logs to AOSP to trace calls and seems all the above is correct.
BUT
The get_report_callback() in com_android_bluetooth_hid.cpp never gets called, and consequently, My app does not receive ACTION_REPORT intents.
If I send dummy ACTION_REPORT intents from my app, then my BroadcastReceiver receives those intents.
My HID device is connected and working, as I do see keys received in edittext field within my app.
Is there any way I could receive my device's HID reports in my app? through intents or through any other way?
If I could receive through Intents, is there any step that I missed? I basically just have BroadcastReceiver with intent filter and BLUETOOTH and BLUETOOTH_ADMIN permissions for receiving HID reports.
If any other method must be used, please suggest.
[Update 2]
I probably didn't mention it clearly, but devices I work with implement HID over GATT and are BLE devices.
On newer Android versions (7,8,9), I am able to receive HID reports by subscribing to HID report notifications, Adding BLUETOOTH_PRIVILEGGED permission, and installing as platform app.
No other Android code jugglery was necessary for these versions. I didn't (and won't) test with older versions of Android, but this solution might already work there.
[Previous Answer]
BluetoothInputDevice didn't work at all.
I used /dev/hidraw* from C code to access the bluetooth hidraw devices.
mac address is NOT reported by /dev/hidraw* nodes.
In Android 5.x they work and all set/send/recv report operations are working. get not tested.
On Android 6.x, only recv operation is working from /dev/hidraw. set/send are not working. get not tested.
I will post update when I have better answer.
Update
I modified bluedroid and added a small unix-socket server within it. Bluedroid delivers all incoming HID reports to this server, and accepts outgoing HID reports from it. My app communicate with this server over unnamed socket. All is well.
I just needed to setup socket's permissions SELinux correctly for this to work.
This works for all versions of Bluedroid I could test with (4.4 - 6.0), but every version of Bluedroid needs it's own version of patch.
Related
I have a project in which I have to read vendor-specific data from a custom BLE device in Android. However, everywhere I looked says that Android "absorbs" HID reports and has no access points for it either through JDK or NDK.
I even tried to create a "priv-app" application and get the BLUETOOTH_PRIVILEGED permission to enable notifications on every characteristic of service 1812, but with no luck (notifications are enabled, but I'm never notified of an event).
Is there any possible way of doing this without building a custom version of Android?
Thanks in advance
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.
I'm trying to build a messenger that requires no bluetooth pairing. The message will be broadcast by the user who adds it and can be received by the listeners in the neighborhood.
I have read in several places that Bluetooth 4.0 has support for this. However most examples involve reading from a ibeacon or a similar device.
Can I use Bluetooth 4.0 to build both a broadcaster and a receiver android app?
I thought of leaving this here because it might be helpful for someone else.
Bluetooth 4.0 broadcast mode requires special hardware and it's only present in a few mobile devices. (Bluetooth peripheral mode) Therefore, instead of using bluetooth low energy, I used SDP (Service Discovery Protocol). The messages are limited to 13 characters.
However due to security restrictions, the app doesn't work for platforms above Jellybean.
Here's my development work. https://github.com/malithj/Seeder
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.
I want to initiate a pairing request (not connection at this point of time) to a non android device. This can be found working on Settings Application > Network > Bluetooth Settings > Click on a device after scan. A pop up appears on both the devices with a 6 digit pin.
As per Android's documentation this should have popped up in my application as well, if I do something like this
device.createRfcommSocketToServiceRecord(MY_UUID);
As per Android's API documentation
"Once a connection is made with a
remote device for the first time, a
pairing request is automatically
presented to the user."
And it is also mentioned that
"The current Android Bluetooth API's
require devices to be paired before an
RFCOMM connection can be established.
(Pairing is automatically performed
when you initiate an encrypted
connection with the Bluetooth APIs.)"
Even when I used the sample Bluetooth Chat application (only to test if it initiates a pairing on first connection) it didn't worked.
I also tried using a generic UDID like "00001101-0000-1000-8000-00805F9B34FB" but to no avail.
Couldn't find the source code of Settings Application (Android OS 2.1) to figure out myself. The sources available in Android GIT were for Android 2.3
Even if you cannot answer the question, only pointing out to Android Packages Settings App sources for Android 2.1 might do the trick for me.
It works for me with this UUID : "00001101-0000-1000-8000-00805F9B34FB".
The intent for pairing request is launched when you call socket.connect() if I remember correctly.