Xamarin bluetooth in Android connection fails - android

I'm trying to establish a bluetoothconnection to another phoner. Later on, it'll be a board with a HC5 module, but for debugging I'm just using a phone.
The problem is, that connect fails and throws an IO Exception:
" read failed, socket might closed or timeout, read ret: -1"
A quick google-search shows a lot having this problem. The only way I can see it solved, is by using a method not public in the API
Method m = mmDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
mmSocket = (BluetoothSocket) m.invoke(mmDevice, 1);
The problem just is, that createRfcommSocket has been removed, and the result from getMethod will be null.
My code is from the example: https://github.com/xamarin/monodroid-samples/tree/master/BluetoothChat which for connecting is:
public ConnectThread(BluetoothDevice device, BluetoothChatService service)
{
UUID MY_UUID = UUID.FromString("00001101-0000-1000-8000-00805f9b34fb");
mmDevice = device;
_service = service;
BluetoothSocket tmp = null;
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try
{
if ((int)Android.OS.Build.VERSION.SdkInt >= 10) // Gingerbread 2.3.3 2.3.4
tmp = device.CreateInsecureRfcommSocketToServiceRecord(MY_UUID);
else
tmp = device.CreateRfcommSocketToServiceRecord(MY_UUID);
}
catch (Java.IO.IOException e)
{
Log.Error(TAG, "create() failed", e);
}
mmSocket = tmp;
}
Since the 'original hack' doesn't work, and I haven't found any other solution, I'm hoping somebody here knows how to fix this.
Best regards!

This is the issue I and others in my company have come across when working with Bluetooth devices from Android phones. It is well described on SO here: Service Discovery Failed Exception Using Bluetooth On Android
The method you describe as being removed is, in fact, still operational. And it is the one we have successfully used. We attempt connection using the
tmp = device.CreateRfcommSocketToServiceRecord(MY_UUID);
method you show above.
Use a try...catch block around tmp.Connect() (your code does not show the Connect call)
In the catch block "re-create" the BluetoothSocket using the createRfcommSocket method. I used a small method to do this:
private BluetoothSocket CreateRfcommSocket(BluetoothDevice bTdevice)
{ // This is an "undocumented" call that is needed to (mostly) avoid a Bluetooth Connection error
// introduced in Android v4.2 and higher. It is used as a "fallback" connection.
// Full paths version of code!
//Java.Lang.Reflect.Method mi = device.Class.GetMethod("createRfcommSocket", new Java.Lang.Class[] { Java.Lang.Integer.Type });
//_bluetoothSocket = (BluetoothSocket)mi.Invoke(device, 1);
// Compact version of above
var mi = bTdevice.Class.GetMethod("createRfcommSocket", Integer.Type);
return (BluetoothSocket)mi.Invoke(bTdevice, 1);
}
This is the method indicated here: Xamarin Forum Post
I have tested this on Android 4.4.2 and Android 8.0 and it works on these systems. Another person in the company has tested the Java equivalent code on Android: 4.2.2, 4.4.2, 7.0 and 8.0 and it works in every case.

Related

createRfcommSocketToServiceRecord works but listenUsingRfcommWithServiceRecord does not

I am trying to control a Hands-Free link with my device. The following works just fine:
UUID HFP_UUID_GET_HF = UUID.fromString("0000111E-0000-1000-8000-00805F9B34FB");
BluetoothSocket aBluetoothSocket = mDevice
.createRfcommSocketToServiceRecord(HFP_UUID_GET_HF);
and I get a socket that I can read and right to. No problem. However, I also want to listen for an incoming connection and get that socket. I tried this:
UUID HFP_UUID = UUID.fromString("0000111F-0000-1000-8000-00805F9B34FB");
UUID HFP_UUID_GET_HF = UUID.fromString("0000111E-0000-1000-8000-00805F9B34FB");
BluetoothServerSocket tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("HFP", HFP_UUID);
BluetoothSocket aBluetoothSocket = tmp.accept();
However, even though the two devices connect I never get a socket back. BTW if I use the UUID that starts with 111E in this second code block here I get a service discovery io error, which makes sense -- I know that my device is using uuid 111F and the other device uses UUID 111E.
Has anyone ran into this issue before? I need to be able to have complete control over all data that gets sent from the phone on that rfcomm channel. I cannot use reflection ; i.e.
Class<?>[] args = new Class[] { int.class };
int HFP_CHANNEL = 10;
Method listenOn = BluetoothAdapter.class.getDeclaredMethod("listenUsingRfcommOn", args);
BluetoothServerSocket my_server = (BluetoothServerSocket) (listenOn.invoke(mBluetoothAdapter,
new Object[] { HFP_CHANNEL }));
BluetoothSocket m_BluetoothSocket = my_server.accept();
because that also throws an io error -- channel already in use, unless anyone knows a way to turn off the hands-free system service. Afaik that is part of bluetoothd (Im using Android 4.1 here) and I need that to remain running (Im not sure if I even can turn it off)

Connecting to a bluetooth HID device (mouse) using L2CAP

I'm tring to find a way to connect to a HID bevice (mouse) using L2CAP, this for a android app. but i'm getting error when accepting the connection. I'm using reflection to create the socket. but some thing is wrong with this.
can some one please direct me to a example code for android that connect to a HID device using L2CAP this way, but without rooting.
What is your Android device and Android version?
If it's Android 4.2, they're now using Broadcom as I understood and so we're only able to create SDP connection.
I'm having the same problem while making a bluetooth connection between my Nexus 7 (Android 4.2.2 with CyanogenMod ROM 10) and a Wiimote. This is an HID device so I need to use L2CAP. Last versions of Android were able to create this connection (we can figure out just by looking at the market). If you search an application to handle this on the market, you'll see by looking at the description that all devices with Android version 4.0+ are not supported.
I just found this post few minutes ago which could help you: stackoverflow.com/a/7838587/1772805
Let me know if you solve this. I'll keep you in touch if I found anything.
EDIT #1: I tried the solution on the link above. I changed it to use a different constructor like this:
private static final int TYPE_RFCOMM = 1;
private static final int TYPE_SCO = 2;
private static final int TYPE_L2CAP = 3;
/**
* Create a BluetoothSocket using L2CAP protocol
* Useful for HID Bluetooth devices
* #param BluetoothDevice
* #return BluetoothSocket
*/
private static BluetoothSocket createL2CAPBluetoothSocket(BluetoothDevice device){
int type = TYPE_L2CAP; // L2CAP protocol
int fd = -1; // Create a new socket
boolean auth = false; // No authentication
boolean encrypt = false; // Not encrypted
int port = 0; // port to use (useless if UUID is given)
ParcelUuid uuid = new ParcelUuid(wiimoteUuid); // Bluetooth UUID service
try {
Constructor<BluetoothSocket> constructor = BluetoothSocket.class.getDeclaredConstructor(
int.class, int.class, boolean.class, boolean.class,
BluetoothDevice.class, int.class, ParcelUuid.class);
constructor.setAccessible(true);
BluetoothSocket clientSocket = (BluetoothSocket) constructor.newInstance(
type, fd, auth, encrypt, device, port, uuid);
return clientSocket;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
I succeeded to create the socket but when I call the method connect(), I get this error: bt l2cap socket type not supported, type:3. This log is a very bad new for me because I found this thread which says Android 4.2 does not support L2CAP (or just disabled by Google..).
Because my device is rooted with CyanogenMod 10, the feature will maybe come back on a new release. I hope..
EDIT #2: Here's a link pointing on the C file containing the reason of the problem: btif_sock.c. If anyone knows if it's possible re-write this file or how to add the L2CAP feature to Android with an external C library. I'm afraid it's not a simple task.

listenUsingRfcommWithServiceRecord (String name, UUID uuid) Not working

So im trying to get this little piece of code to run
public AcceptThread() {
// Use a temporary object that is later assigned to mmServerSocket,
// because mmServerSocket is final
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothServerSocket tmp = null;
try {
// MY_UUID is the app's UUID string, also used by the client code
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("Server", MY_UUID);
} catch (IOException e) { }
mmServerSocket = tmp;
}
But when i continue from the line where tmp should be assigned it is still null. Bluetooth is activated and everything but it simply wont set tmp to anything when i get to it. Any ideas why not? And btw. does this method not work on a 2.2 android machine since it crashes at that line on my 2.2 machine but not on my 4.1.2 device.
If any more information is needed to be able to answer please just ask for it and ill give it to the best of my ability.
Found out i hadn't given permission to the app to use bluetooth so solved.
I am completely new to Android development and ran into the same problem. Here is more help if other people run into this:
Because this is happening on the server side, be sure discoverability is enabled before starting the accept-connection thread. This can by starting the thread in the onActivityResult() method when the proper resultCode is received.

Android Bluetooth - source code

I have been strugling with a Bluetooth project on Android for weeks. Does anyone know where I can go to see the actual code that's used by Google to make their Bluetooth pairing and connection logic work?
I have been through all the documentaiton, the BluetoothChat application (which doesn't work as advertised ... tried it on 3 different handsets), as well as a bunch of other sites on the net, but still no luck. I need to get an app up and running on 2.1 or higher.
Any advice or help is greatly appreciated.
Yes the Bluetooth project didn't work for me also because the code for socket connection is not working
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try {
if (secure) {
tmp = device.createRfcommSocketToServiceRecord(
MY_UUID_SECURE);
} else {
tmp = device.createInsecureRfcommSocketToServiceRecord(
MY_UUID_INSECURE);
}
} catch (IOException e) {
Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
}
this is not working ...
replace this by the following code
BluetoothDevice hxm = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(device.getAddress());
Method m;
m = hxm.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
socket = (BluetoothSocket)m.invoke(hxm, Integer.valueOf(1));
Ah, if you're having issues with application level code I'm not sure staring at the Bluetooth manager source will be much help, but here you go: https://android.googlesource.com/platform/packages/apps/Bluetooth the Bluetooth manager app code.
I'll re-iterate it: this is honestly probably not going to be helpful for what you want. You should be able to get a reasonably working Bluetooth app without having to look at this.
EDIT: if you want the code that implements the Bluetooth packages (android.bluetooth), see https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/bluetooth for that.
You can browse all the android.bluetooth package around here:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/bluetooth/BluetoothClass.java#BluetoothClass

Programmatically connect to paired Bluetooth device

Is there a way, using the Android SDK, to programmatically connect to an already-paired Bluetooth device?
In other words: I can go into Settings -> Wireless & networks -> Bluetooth settings, and tap the device (listed as "Paired but not connected"), at which point it will connect. I'd like to be able to do this programmatically, but don't see a way to do this.
I see the options to create an RFCOMM socket, and for a SPP device, I'm assuming that'll do the connection part as well, but for an A2DP device, where the actual data transfer will be handled by the OS rather than by my app, I think that's not applicable?
Okay, since this was driving me crazy, I did some digging into the source code and I've found a 100% reliable (at least on my Nexus 4, Android 4.3) solution to connect to a paired A2DP device (such as a headset or Bluetooth audio device). I've published a fully working sample project (easily built with Android Studio) that you can find here on Github.
Essentially, what you need to do is:
Get an instance of the BluetoothAdapter
Using this instance, get a profile proxy for A2DP:
adapter.getProfileProxy (context, listener, BluetoothProfile.A2DP);
where listener is a ServiceListener that will receive a BluetoothProfile in its onServiceConnected() callback (which can be cast to a BluetoothA2dp instance)
Use reflection to acquire the connect(BluetoothDevice) method on the proxy:
Method connect = BluetoothA2dp.class.getDeclaredMethod("connect", BluetoothDevice.class);
Find your BluetoothDevice:
String deviceName = "My_Device_Name";
BluetoothDevice result = null;
Set<BluetoothDevice> devices = adapter.getBondedDevices();
if (devices != null) {
for (BluetoothDevice device : devices) {
if (deviceName.equals(device.getName())) {
result = device;
break;
}
}
}
And invoke the connect() method:
connect.invoke(proxy, result);
Which, at least for me, caused an immediate connection of the device.
the best way I found to solve my problem was finding out that I can create a button that brings up the Bluetooth Settings screen. I didn't realize you could do this, or I would have from the beginning.
startActivity(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
if the device is already paired , then you can use
if(device.getBondState()==device.BOND_BONDED){
Log.d(TAG,device.getName());
//BluetoothSocket mSocket=null;
try {
mSocket = device.createInsecureRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e1) {
// TODO Auto-generated catch block
Log.d(TAG,"socket not created");
e1.printStackTrace();
}
try{
mSocket.connect();
}
catch(IOException e){
try {
mSocket.close();
Log.d(TAG,"Cannot connect");
} catch (IOException e1) {
Log.d(TAG,"Socket not closed");
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
for the MY_UUID use
private static final UUID MY_UUID = UUID.fromString("0000110E-0000-1000-8000-00805F9B34FB");
the above code snippet is just to connect your device to an A2DP supported device.
I hope it will work.
I used the code here as a starting point for this functionality in my app: http://developer.android.com/guide/topics/wireless/bluetooth.html#ConnectingDevices
Once the device is paired, the app has no problem connecting the two devices together programmtically.

Categories

Resources