I have a device which supports the OBEX Object Push Profile, this profile is based upon the Serial Port Profile. My guess is that I can use the Android Bluetooth Chat example for connecting this device to my Android Phone. But I ran into a problem, regarding the socket.accept() functionality in the android SDK. I try to accomplish to connect my phone with this device like this:
adapter = BluetoothAdapter.getDefaultAdapter();
device = adapter.getRemoteDevice("00:1B:DC:0F:EC:7E");
AcceptThread = new AcceptThread(true, adapter, device);
AcceptThread.start();
The constructor in AcceptThread is coded like this:
public AcceptThread(boolean secure, BluetoothAdapter adapter, BluetoothDevice device) {
BluetoothServerSocket tmp = null;
this.adapter = adapter;
this.device = device;
// Create a new listening server socket
try {
tmp = adapter.listenUsingInsecureRfcommWithServiceRecord(device.getName(), UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
} catch (Exception e) {
Log.e(TAG, ".AcceptThread # listen() failed", e);
}
mmServerSocket = tmp;
}
The problem is when I try to do a connect() as I said before
public void run() {
BluetoothSocket socket = null;
// Listen to the server socket if we're not connected
while (mState != STATE_CONNECTED) {
try {
// This is a blocking call and will only return on a
// successful connection or an exception
Log.d(TAG, "AcceptThread.run: accepting server socket connection");
socket = mmServerSocket.accept(20000);
Log.d(TAG, ".AcceptThread.run # server socket connection accepted");
} catch (Exception e) {
Log.e(TAG, ".run # accept() failed: "+e);
break;
}
}
}
As you can see the ServerSocket accept every incomming connection for 20 seconds or 20000 ms. When the time is up, the app will throw an IOException like this
07-11 10:30:08.355: E/SIMPLECONNECT(1301): .run # accept() failed: java.io.IOException: Connection timed out
which tells me that my device couldnt connect to my android phone. The device doesnt have a connect button on the display, just a send functionalitywhich will send a file to my phone. I believe that this send functionality also do a connect in the background, but I am not sure.
Can anybody pinpoint any solutions for me? I am running my app on a Samsung Galaxy SIII with Android 4.0.4
I finally solved it, the problem is that different Android Versions and different devices seemes to need different sockets. I tryed it with Samsung Galaxy XCOVER, Tab1, Tab2, Nexus, Note, Motorola Defy and HTC Flyer.
The Sockets I used are:
A:
Method m = mmDevice.getClass().getMethod("createRfcommSocket", new Class[] { int.class });
mSocket = (BluetoothSocket) m.invoke(mmDevice, Integer.valueOf(1));
B:
Method m = mmDevice.getClass().getMethod("createInsecureRfcommSocket", new Class[]{int.class});
mSocket=(BluetoothSocket)m.invoke(mmDevice,Integer.valueOf(1));
C:
mSocket=BluetoothAdapter.getDefaultAdapter().getRemoteDevice(mmDevice.getAddress()).createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
Android 4.0.x works for Nexus, Flyer,Tab1 with A,B
Android 4.0.3 works for Tab2 with B
Android 3,6,x works for DEFY with A,B
Android 2.3.6 works for XCOVER with C
I can't find a solution witch works for all devices and I;m not able to find out witch socket will work before I create and use the Socket, especially the XCOVER perform the connect() for all Sockets without throwing an exception, but catch if i try tro write(). So if you want to setup a bloothoh connection wich works for all devices you have to create the sockets, connect an write and then remeber the socket wich works (e.g. in preferences)
Related
I have an Android tablet that acts as a Bluetooth server and allows up to 6 clients to connect (I set this limit, knowing that the theoretical maximum is 7, as per the Bluetooth piconet specification). I tried with two different tablet models from the same manufacturer: Huawei Mediapad T3 and Huawei MediaPad T5. On the T3, I can get up to 6 connections that remain stable and allow communicating almost seamlessly with the clients. On the T5, however, the tablet will not accept more than 4 simultaneous connections. If I disconnect one device, one of the two remaining ones which keep requesting to connect gets accepted in its place. I do not get any error messages from the calls to the accept() method, or any other errors regarding Bluetooth in the Android Logcat.
Both tablets run under EMUI 8.0.0 (the Huawei brew of Android 8.0.0).
Here is the code I run for the thread that accepts the connections :
private class AcceptThread extends Thread {
private BluetoothServerSocket serverSocket;
AcceptThread(String name, String uuidStr) {
btAdapter.cancelDiscovery();
try{
serverSocket = btAdapter.listenUsingInsecureRfcommWithServiceRecord(name, UUID.fromString(uuidStr));
} catch (IOException ex){
onStatusListener.OnStatus("server.error.COULD_NOT_LISTEN");
Log.e(TAG, "Could not open socket", ex);
}
}
public void run() {
onStatusListener.OnStatus("server.listening");
while (connections.size() < maxConnections) {
setState(STATE_LISTENING);
try {
BluetoothSocket socket = serverSocket.accept();
if (socket != null) {
ConnectedThread conn = new ConnectedThread(socket);
setState(STATE_CONNECTING);
conn.start();
connections.add(conn);
conn.setOnDisconnectEvent(() -> {
onStatusListener.OnStatus("server.disconnected." + socket.getRemoteDevice().getAddress());
connections.remove(conn);
});
onStatusListener.OnStatus("server.connected." + socket.getRemoteDevice().getAddress());
}
} catch (IOException ex) {
onStatusListener.OnStatus("server.error.COULD_NOT_ACCEPT");
Log.e(TAG, "Socket's accept() method failed", ex);
break;
}
}
onStatusListener.OnStatus("server.not_listening");
cancel();
}
void cancel(){
try {
setState(STATE_NONE);
serverSocket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close server socket", e);
}
}
}
What can cause my code to work on the T3 tablet and not on the T5?
Is there anything I could do differently to get my 6 simultaneous connections working with both tablets?
When it comes to the maximum connections allowed by a device, the limitation is usually related to the hardware and not the software. In other words, it is the Bluetooth hardware on the T5 that is preventing you from creating further connections. This is evident by the fact that both tablets are running the same OS yet still exhibit this difference.
What I find strange is the fact that you are not getting any error response back when you attempt to exceed the number of possible connections. Unfortunately I don't think there is a way to increase the limit on the T3. I would contact Huawei if possible as they would be able to confirm this discrepancy.
I have two apps: one acting as a Server in a device with Android 7.1.2 (a camera) ,and another one acting as Client in Android 7.0. (Samsung Galaxy S7). I did the pairing so they both appear in each other discovery method.
Client does:
...
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mmSocket = device.createInsecureRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
...
mBluetoothAdapter.cancelDiscovery();
try {
mmSocket.connect();
} catch (IOException connectException) {
connectException.printStackTrace();
}
...
And Server does:
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mmServerSocket = mBluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord("name",UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
...
BluetoothSocket socket = null;
boolean connected = false;
// Keep listening until exception occurs or a socket is returned.
while (true) {
if(!connected) {
try {
MyLog.d(TAG, "accepting");
socket = mmServerSocket.accept();
} catch (IOException e) {
MyLog.e(TAG, "Socket's accept() method failed");
break;
}
}
...
}
Everything works fine when I test my apps in two normal Android phones, and when I use my server in a phone and my camera as a client.
But if I try to run the server in the camera and the client in the phone then the camera gets stuck in
socket = mmServerSocket.accept();
and the client returns an IOException in
mmSocket.connect();
java.io.IOException: read failed, socket might closed or timeout, read
ret: -1
I guess it's something to do with the camera Bluetooth not accepting connections but I don't know that much about it and everything works fine when the roles are switched and the camera runs the client app.
Any ideas?
Thanks!
I would like to manually connect a bluetooth device with its MAC address because it is faster and I know exactly which MAC to connect.
I use this method to get the BluetoothDevice : http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getRemoteDevice%28byte[]%29
But the Android doc does not say if Android ensure that the device is in range before creating the BluetoothDevice object.
Do you have this information ?
My code can automatically connect the device, and I would like to check if the target is in range before trying to connect, but without perform a large scan (which can be long...)
When local device connects to remote device using BluetoothSocket, an exception is required.
If remote device isn't in range, It's not found
private class ConnectThread extends Thread {
public ConnectThread(BluetoothDevice device, boolean isSecure, UUID sharedUUID) throws IncorrectSetupException {
try {
//Secure connections requires to get paired before connect
//Insecure connections allows to connect without pairing
if (isSecure) {
mSocket = device.createRfcommSocketToServiceRecord(sharedUUID);
} else {
mSocket = device.createInsecureRfcommSocketToServiceRecord(sharedUUID);
}
} catch (IOException e) {
//Is there some problem with the setup?
}
}
public void run() {
try {
mSocket.connect();
} catch (IOException e) {
//If device is not found, this exception is throwed
}
}
}
I already managed to get it working using this method at android 2.3.3 version, but now I am testing using another device with 2.2 version..
And I can find many devices using discovery, but can't connect to other devices using:
BluetoothSocket socket = deviceToConnect.createRfcommSocketToServiceRecord(UUID.fromString(MY_UUID));
On the other side, I am using the proper thread to accept the connection using :
mBluetoothAdapter.cancelDiscovery();
BluetoothServerSocket ss;
try {
ss = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(MainPage.SD_FolderName, UUID.fromString(MY_UUID));
new Thread(new ListenerHandler(ss, this, resultCode)).start();
} catch (IOException e) {
Toast.makeText(this, "There was a problem opening the bluetooth server socket!", Toast.LENGTH_LONG).show();
finish();
}
Then on the ListenerHandler I have this:
BluetoothSocket clientSocket = ss.accept();
But the connection is never stablished, any thoughs?
Thanks in advance!
I'm currently working on an Android application that connects to an instrument via Bluetooth and need to write string commands and receive string responses back. Currently I have the connect/read/write working for TCP/IP over Wi-Fi and now trying to implement Bluetooth. But I am running into some roadblocks. I have been searching the web trying to find examples of something similar and haven't had any luck. I have been using the Android developer resource example: Bluetooth Chat as my main reference point.
My current code seems to work.. Then it throws a Service Discovery Failed exception at the point of the connection. I am using the DeviceListActivity class to do the discovery and selecting of the device I want to connect to. It returns anActivityResult and then my Bluetooth class waits for it to handle that and then does the connect to it. The code beneath is almost identical to the Bluetooth Chat App.
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(!m_BluetoothAdapter.isEnabled())
{
m_BluetoothAdapter.enable();
}
switch (requestCode) {
case REQUEST_CONNECT_DEVICE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
// Get the device MAC address
String address = data.getExtras()
.getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
// Get the BLuetoothDevice object
BluetoothDevice device = m_BluetoothAdapter.getRemoteDevice(address);
// Attempt to connect to the device
connect(device);
}
break;
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK) {
// Bluetooth is now enabled, so set up a chat session
}
else {
// User did not enable Bluetooth or an error occured
Toast.makeText(this, "Bluetooth not enabled", Toast.LENGTH_SHORT).show();
finish();
}
}
}
This is my connect function:
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private void connect(BluetoothDevice device) {
m_Device = device;
BluetoothSocket tmp = null;
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try {
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
}
catch (IOException e) {
}
m_Socket = tmp;
m_BluetoothAdapter.cancelDiscovery();
try {
// This is a blocking call and will only return on a
// successful connection or an exception
m_Socket.connect();
}
catch (IOException e) {
try {
m_Socket.close();
}
catch (IOException e2) {
}
return;
}
}
Hopefully, whatever I am doing wrong is simple, but I'm afraid it's never that easy. This is my first time doing any Bluetooth development, and maybe I'm doing something blatantly wrong... But I'm not sure why I get the service discovery failed exception.
You can pair/find the device at all times manually on the phone... It does require a passcode, but I don't think that is the problem that I am having.
After three days I got it figured out thanks to some very helpful posts.
I had to replace:
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
with:
Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
tmp = (BluetoothSocket) m.invoke(device, 1);
and voilĂ it works!
As of API 15 you can use the following method:
Try replacing your UUID with the return value of getUuids() method of BluetoothDevice class.
What worked for me was something like this:
UUID uuid = bluetoothDevice.getUuids()[0].getUuid();
BluetoothSocket socket = bluetoothDevice.createRfcommSocketToServiceRecord(uuid);
The reason this works is that different devices support different UUIDs and by getting the UUIDs of the device using getUuids you are supporting all features and devices.
Another interesting new method (supported since API 14) is this: BluetoothHealth.getConnectionState. Haven't tried it but looks promising...
This was a suggested edit from an anonymous user attempting to reply to the accepted answer.
One big difference between your before and after code is the UUID you are passing. I found my answer here: http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createRfcommSocketToServiceRecord(java.util.UUID)
I had to replace:
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
with:
private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
tmp = device.createRfcommSocketToServiceRecord(SPP_UUID);
and voila it works!
The original code is for a peer to peer android app. It makes no sense to use the app UUID when connecting to a simple serial bluetooth device. Thats why discovery fails.
So as it mentioned above, the point is that you need to use the UUID that the server is waiting for.
If you are connecting to a bluetooth device, such as a headset or mouse, you need to check which UUIDs the device is listening for. You can see the UUIDs like this.
UUID[] uuids = bluetoothDevice.getUuids();
And if you want to know what these UUIDs mean, see this.
This is a realy old one question but i found that using the createInsecureRfcommSocketToServiceRecord() instead of createRfcommSocketToServiceRecord() along with the getUuids() previously mentioned do the trick for me
UUID uuid = bluetoothDevice.getUuids()[0].getUuid();
BluetoothSocket socket = bluetoothDevice.createInsecureRfcommSocketToServiceRecord(uuid);