The Android Bluetooth API allows you to register an SDP service using:
String BLUETOOTH_NAME="MyBluetoothService";
mAdapter.listenUsingRfcommWithServiceRecord(BLUETOOTH_NAME, UUID.fromString(uuid));
It also allows you to initiate a Service Discovey on a remote Bluetooth Device to find the list of active service UUID's:
device.fetchUuidsWithSdp();
However, there doesn't seem to be any public method available to get the service name. Can it be acquired by other means?
I suppose you want to get the names of services running on the device as you would do on a linux box with
sdptool browse local | egrep "Service Name:"
So the answer is no, as there is no Android API method and sdptool is not on android.
However you might write a c library containing an according function using the NDK and call the function via JNI (see Bluetooth for Programmers for the first on http://people.csail.mit.edu/rudolph/Teaching/Articles/BTBook.pdf).
By the way: Why do you want to list the services by name and not by UUID. It is my experience that service names slightly differ with implementations while UUIDS are credible.
Related
First, the source code for the BLE Peripheral Simulator is a tremendous resource for anyone investigating Web Bluetooth.
There is a an approved list of GATT Services.
When I modified the Android source code to use a custom defined GATT service (easy to do by simply specifying your own UUID in the Android code) pairing from the web page to the Android app running the GATT sever fails.
The Web Bluetooth documentation does state, "If device’s advertised Service UUIDs have a non-empty intersection with the set of Service UUIDs, add device to result and abort these sub-steps [for pairing]."
Does this mean only services in the approved GATT list are supported? If so, what is the rational? It seems that such a restriction would limit innovation.
I am working with web-bluetooth also and i was able to talk with custom services, yet to read data from them you have to have device docs explaining how to talk to that services. I think this approved list is like generally used list which doesn't require unique logic to get data. However there is difference since some characteristics are blacklisted for web-bluetooth yet available to fetch data from using ios/android stuff.
If I had done some more research on Stack Overflow I would have realized the UUID spec requires lowercase a-f.
Type of Character generated by UUID
The following values work for a custom defined service and characteristic:
private static final UUID SERVICE_UUID = UUID.fromString("29143321-ef6c-4761-947c-c858f9a2e8f1");
private static final UUID CHARACTERISTIC_UUID = UUID.fromString("92f3131b-ffa8-4dd1-a12b-641d65a78857");
After initially setting up attributes for the NsdServiceInfo and calling registerService, how is it possible to update the attributes?
With iOS, you just call [service setTXTRecordData...]. I don't see any way to do it with Android so far.
I know everyone hates that type of answers...
But consider trying 3rd party lib for doing that.
E.g. JmDNS: https://github.com/jmdns/jmdns
Pros:
it doesn't have issues on pre-Marshmallow (built-in Android NSD is very buggy on pre-M, e.g. you can't read attributes of the discovered service);
you can update registered service attributes using the setText() method of ServiceInfo object.
Cons:
it doesn't work if Android device is used as a hotspot (has no Internet access and provides its own WiFi access point without Internet access).
I'm not familiar with iOS API, but I don't think there is a direct way to do this with NSD API, according to rfc 6762 section 8.4:
At any time, if the rdata of any of a host's Multicast DNS records
changes, the host MUST repeat the Announcing step described above to
update neighboring caches. For example, if any of a host's IP
addresses change, it MUST re-announce those address records. The
host does not need to repeat the Probing step because it has already
established unique ownership of that name.
In the case of shared records, a host MUST send a "goodbye"
announcement with RR TTL zero (see Section 10.1, "Goodbye Packets")
for the old rdata, to cause it to be deleted from peer caches, before
announcing the new rdata. In the case of unique records, a host
SHOULD omit the "goodbye" announcement, since the cache-flush bit on
the newly announced records will cause old rdata to be flushed from
peer caches anyway.
Attributes are usually advertised in TXT record, So I don't think iOS has some magic to update the TXT record, it must re-announce or send a "goodbye" announcement. Since Android NSD doesn't provide an API to send a single TXT record, AFAIK, the only way to do this is to call NsdManager.unregisterService() then NsdManager.registerService().
FWIW the native bonjour API supports updating txt records w/o unregistering the service.
From dns_sd.h
DNSServiceUpdateRecord
*
* Update a registered resource record. The record must either be:
* - The primary txt record of a service registered via DNSServiceRegister()
* - A record added to a registered service via DNSServiceAddRecord()
* - An individual record registered by DNSServiceRegisterRecord()
I would like to know high level idea of how Android Modem code will call/pass message to Android application layer. Say we take SMS for example. If network sends SMS and Modem (say Qualcomm C code parses it) how is it transmitted to Android Application layer?
Is there always a JNI call happening? as interface between modem and Android? Can you please share the information with us. Thanks
In almost all android source base as found in the AOSP/CAF/CM source (Android Open Source Project, CodeAurora Forum, Cyanogenmod respectively), will have C code called the rild, (Radio Interface Layer Daemon). This is commonly found within the /hardware/ril of the source tree.
This daemon runs from the moment Android boots up, and creates a socket called /dev/socket/rild and /dev/socket/rild-debug. There will be a proprietary library coming from Qualcomm, HTC, that gets dynamically loaded at run time upon boot. It is that proprietary library that in turn, communicates to the radio firmware. And the rild's hooks for the call-backs into the proprietary library is established there and then.
At the rild layer, via the aforementioned socket, is how the Android layer (found in the source tree, frameworks/base/telephony/com/android/internal/telephony/RIL.java) communicates.
On the Java side, it opens the socket for reading/writing, along with establishing intents and setting up delegates for broadcasting/receiving events via this socket.
For example, an incoming call, the proprietary library, invokes a callback hook as set up by rild. The rild writes standard generic AT Hayes modem commands to the socket, on the Java side, it reads and interprets the modem commands, and from there, the PhoneManager broadcasts CALL_STATE_RINGING, in which Phone application (found in the source packages/apps/Phone) has registered a receiver and kickstarts the User interface, and that is how you get to answer the call.
Another example, making an outgoing call, you dial a number on Android, the intent gets created and which in turn the PhoneManager (This is the root of it all, here, cannot remember top of my head, think its in frameworks/base/core/java somewhere in the source tree) receives the intent, convert it into either a sequence of AT Hayes modem commands, write it out to the socket, the rild then invokes a callback to the proprietary library, the proprietary library in turn delegates to the radio firmware.
Final example, sending text messages, from the Messaging (found in packages/apps/Mms source tree) application, the text you type, gets shoved into an intent, the PhoneManager receives the intent, converts the text into GSM-encoded using 7-bit GSM letters (IIRC), gets written out to the socket, the rild in turn invokes a callback to the proprietary library, the proprietary library in turn delegates to the radio firmware and the text has now left the domain of the handset and is in the airwaves somewhere... :) Along with sending a broadcast message within Android itself, provided that READ_PHONE_STATE permission is used and specified in the AndroidManifest.xml.
Likewise conversely, when receiving a text message, it is in the reverse, radio firmware receives some bytes, the proprietary library invokes the callback to the rild, and thus writes out the bytes to the socket. On the Java side, it reads from it, and decodes the sequence of bytes, converts it to text as we know of, fires a broadcast with a message received notification. The Messaging application in turn, has registered receivers for the said broadcast, and sends an intent to the notification bar to say something like "New message received from +xxxxxx"
The intents are found in frameworks/base/telephony/java/com/android/internal/telephony/TelephonyIntents.java
That is the gist of how the telephony system works, the real beauty is, that it uses generic AT Hayes modem commands thusly simplifying and hiding the real proprietary mechanisms.
As for the likes of Qualcomm, HTC, forget about it in thinking they'd ever open source the library in question because the radio telephony layer is embedded within the S-o-C (System on a Chip) circuitry!
Which is also, as a side note, why its risky to flash radio firmware, some handsets provide the capability to do it, flash the wrong firmware (such as an incompatible or not suitable for handset), kiss the handset good-bye and use that as a door stopper or paper-weight! :)
It should be noted, that there is zero JNI mechanisms involved.
This is from my understanding of how it works, from what I can tell is this, the radio firmware is loaded into a memory address somewhere where the linux kernel has reserved the address space and does not touch it, something like back in the old PC days when DOS booted up, there was reserved addresses used by the BIOS, I think, its similar here, the addresses marked as reserved are occupied by the firmware, in which the proprietary radio library talks to it - and since the library is running in the address space owned by the kernel, a lá owned by root with root privileges, it can "talk" to it, if you think of using the old BASIC dialect of peek and poke, I'd guess you would not be far off the mark there, by writing a certain sequence of bytes to that address, the radio firmware acts on it, almost like having a interrupt vector table... this am guessing here how it works exactly. :)
Continuing from the explanation by t0mm13b, When we talk about a smartphone, think of 3 layer operations wrt to SMS/Calls.
RIL (User level) <-> AP <-> CP
AP : Application Processor(Where your Android OS runs. Think of games, songs, videos, camera etc running on this processor)
CP : Cellular Processor (Which actually deals with Air-interface for incoming/outgoing calls/sms, interacts with Network Tower etc ..)
Now let say some data is received at CP side (It could be internet data/sms/call). Now there are certain logical channels between AP and CP. So CP will push the data received to a corresponding channel based on type of data. This data will be received by AP. AP will send this data back to RIL/App. RIL will decode this data (specially call/sms data). Based on that gives notification to User about SMS/Call.
Is there any way for Android to connect to a Bluetooth device using a specific port instead of using service UUID?
I know this option is available in other platforms which provide Bluetooth support (Java ME for example by specifying a "btspp://" style URL).
Thanks!
Ok, it's been a while, but I found a solution to the problem. I actually intended to give up and use UUID, but I kept getting a Service Discovery Failed (IO)exception, and when I tried to find a solution to the service discovery issue, I found the solution to my original question... Ain't life something?:)
Anyways, this is the link I stumbled upon, though you should note there is a mistake in the answer (they actually simply connected to port 1, instead of using a service UUID).
And after this short history lesson, here is the solution:
Using reflection, it is possible to create the Rfcomm socket connecting to a port number instead of UUID:
int bt_port_to_connect = 5; // just an example, could be any port number you wish
BluetoothDevice device = ... ; // get the bluetooth device (e.g., using bt discovery)
BluetoothSocket deviceSocket = null;
...
// IMPORTANT: we create a reference to the 'createInsecureRfcommSocket' method
// and not(!) to the 'createInsecureRfcommSocketToServiceRecord' (which is what the
// android SDK documentation publishes
Method m = device.getClass().getMethod("createInsecureRfcommSocket", new Class[] {int.class});
deviceSocket = (BluetoothSocket) m.invoke(device,bt_port_to_connect);
A few things to notice:
since we're using Invoke, the first parameter is the object we're invoking the method on, the second parameter of invoke is actually the first function parameter)
There is also a secure version available ('createRfcommSocket'), which accepts a bluetooth channel number as a single parameter (again, since this is invoke style, you'll need to pass the object to invoke the method on, as mentioned in -1- )
I found what appears to be a link to these functions' prototypes
Good luck to all.
Bluetooth Android connections are exclusively done via UUID. Each Bluetooth device has a UUID for every service it runs (see Bluetooth SDP).
You just give Android the UUID to watch for and, in client mode, it will find a socket to connect to automatically (including port). In server mode, it will wait for the specified device to initiate a connection using the specified UUID.
The BluetoothSocket object is also valid when connection is established (use getInput/Output Stream)
See Server Socket documentation and Client Socket documentation.
If you really want to check everything, you can see what Android decodes from the other device's SDP and the UUID you provided.
Use this tutorial to get the Bluetooth interface (very easy to do).
Then the code should look something like this:
IBluetooth ib =getIBluetooth();
Int otherDevicePort = ib.getRemoteServiceChannel(otherDeviceAddress, UUID);
I'm using bluecove which allow me to do so with the function Connector.open().
I use the following url:
btspp://" + phoneID + ":" + phonePort
N.b.: Some options can be added (e.g.: authenticate=false; or encrypt=false;).
With phoneID being the the being the Bluetooth address and phonePort the port number.
How to find the Bluetooth address?
From this link:
From the Home screen, open the app drawer, then open “Settings“.
Select “System“. (Skip this step on some models)
Scroll down to the bottom and tap “About Phone“, “About device“, or “About tablet“.
Scroll down to the bottom and tap “Status“.
Scroll down and the “Bluetooth address” will be shown in the list.
How to find the port number?
I haven't been able to find which port is supposed to be used yet...
I used 5 and it works but I need to research why and if I want to change the phone I will need to know if I also need to change the port.
Can anyone give me an idea on how to read the values from the OBD II Bluetooth adapter in an android application.
I want to start with scanning for the bluetooth devices from my android application, then after bluetooth device is found, how would I interact with it and get the values from it?
You should start by reading this http://developer.android.com/guide/topics/wireless/bluetooth.html
it contains step by step procedure .
add required permissions,
make a bt adapter,
then find paired/unpaired devices
I used the BluetoothChat Application and was able to get some basic communications, I am not moving into data logging. You can use this application to have a sort of instant messenger conversation with your ECM.
What particular dongle are you using?
Do you know what protocols are in use within your vehicle?
Download the BluetoothChat sample application -
They will have already handled the intricacies of the connection for you, you will have to change the UUID in order to connect with your device - 00001101-0000-1000-8000-00805F9B34FB
Read up on your particular dongle, some require the return character to be sentat the end of every command "\r"
This should get you started!
Once you have made the Bluetooth connection using the android bluetooth api, use the transport to send and receive data via the Bluetooth channel.
This is new developer resource document:
https://developer.android.com/guide/topics/connectivity/bluetooth.html
The general workflow of the application functionality should go like this:
1) connect to the OBDII adapter through Bluetooth;
2) initialize OBDII adapter with AT commands;
3) continuously get data from the vehicle through issuing the corresponding PID codes.
This article also may be helpful.
http://blog.lemberg.co.uk/how-guide-obdii-reader-app-development