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
Related
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 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 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.
I am little confused about System.Global. According to this document (third point under Important Behavioral Changes) it says that few of the features like turning airplane mode on/off have been include in System.Global in Android 4.2 and higher so its now read only we cannot write it.
Along with airplane mode there is also Bluetooth turn on/off feature included in System.Global which means we shouldn't be able to toggle Bluetooth on/off programmatically since its read only.
But I have some app in my Nexus 7 which runs on version 4.4.2 where the app can easily turn on/off Bluetooth on voice command (one such app is 'Assistant')
How is it possible if the features in System.Global are read only?
Any explanation on this topic will be very much appreciated. Thanks in advance :)
System settings are generally read-only for normal apps. The "Assistant" or "Settings" applications are bundled with the platform and have special permissions. Bluetooth does expose the ability to turn a given "adapter" off and on via the BluetoothAdapter class.
Starting with Android 5.0, it's possible to access some of the settings.
You can use the method setGlobalSetting() in the DevicePolicyManager for that.
However, the caller app must be device owner which is not available to apps deployed on Google Play.
To deploy and activate a device owner, you must perform an NFC data
transfer from a programming app to the device while the device is in
its unprovisioned state. This data transfer sends the same information
as in the provisioning intent described in Managed provisioning.
Source: Android 5.0 APIs
I was reading this
http://developer.android.com/guide/topics/wireless/bluetooth.html#QueryingPairedDevices
which is allot of help on how to pair,connect to a bluetooth device.
I have a situation where I have several BT devices that are in Non-Discover mode always. I know the MAC and the PIN of these devices. IS there a way in Android Dev to manually add devices to the PAIRED list so i can just use the connect as a client.
I understand this maual is written allot for V3. i think i will need to do this on 2.0 ; 2.1- has anybody done this before?
Basically these devices I want to connect to are power saving modules I used pre built BT modules to monitor daylight, another one humidity, etc.. every 3hrs or when interrupted and runs of a single battery for months. So turning off divcory on server saves immense power and prevents other people trying to connect and waste battery.
Not sure what you mean by "manually": Do you mean "manually" as in GUI/user interaction, or "manually" as "I do it in my own application code"?
Some suggestions though:
If you can make your BT devices discoverable at all, you could do it this way:
Make your BT device discoverable
Let Android search for and find the device and then initiate a connection
Android will ask for the PIN for pairing with the device; enter the PIN.
Once pairing was successful, Android stores the pairing information for future use, so that you can
Make your BT device invisible again.
From then on your app should be able to connect to the BT device at any time without further pairing operations.
If the said is not an option for you, maybe you want to go another way:
In current Android versions there are different API routines implemented which are neither documented nor exposed in the normal SDK. A hack kind of solution may be to use some of these "hidden" ("#hide"...) APIs, either via reflection or via modification of your SDK installation.
But be aware that this is always a hack and it may work on a specific device with a specific version of Android and is likely to break your app on another device and/or any other Android version.
Having said that, here comes some reference:
Example of how to access "hidden" bluetooth API.
Then, have a look at the source code for android.bluetooth.BluetoothDevice, e.g. here.
In there, public boolean createBond(){...} may do what you want.