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!
Related
I tried to create a simple android application to connect to my ELM327 device to get some car diagnostic data. But I wasn't able to set up the bluetooth connection b/t my android phone and my ELM327 device.
My code is very simple as below:
public class Bluetooth {
protected BluetoothAdapter mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter();
private ConnectThread mConnectThread = null;
private AcceptThread mAcceptThread = null;
private WorkerThread mWorkerThread = null;
private BluetoothDevice mOBDDevice = null;
private BluetoothSocket mSocket = null;
private String uuid;
Bluetooth() {
mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> pairedDevices;
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled())
return;
pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
// There are paired devices. Get the name and address of each paired device.
for (BluetoothDevice device : pairedDevices) {
String deviceName = device.getName();
String deviceHardwareAddress = device.getAddress(); // MAC address
//TODO: check whether this is OBD and whether it is connected
//by sending a command and check response
if (deviceName.contains("OBD")) {
mOBDDevice = device;
uuid = device.getUuids()[0].toString();
break;
}
}
}
mBluetoothAdapter.cancelDiscovery();
}
/**
* Start the chat service. Specifically start AcceptThread to begin a session
* in listening (server) mode. Called by the Activity onResume()
*/
public synchronized void connect()
{
try {
// Get a BluetoothSocket to connect with the given BluetoothDevice.
// MY_UUID is the app's UUID string, also used in the server code.
mSocket = mOBDDevice.createRfcommSocketToServiceRecord(UUID.fromString(uuid));
} catch (IOException e) {
Log.e(TAG, "Socket's create() method failed", e);
}
try {
// Connect to the remote device through the socket. This call blocks
// until it succeeds or throws an exception.
mSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and return.
try {
mSocket.close();
} catch (IOException closeException) {
Log.e(TAG, "Could not close the client socket", closeException);
}
return;
}
}
}
In the mainactivity, I will first new a Bluetooth class then call bluetooth.connect():
mBluetooth = new Bluetooth();
mBluetooth.connect();
When I debug the program, I was able to get my ELM327 bluetooth device by querying all the bonded devices with a name of "OBD". I also was able to get the device's uuid and create a socket using createRfcommSocketToServiceRecord. But in the connect function, mSocket.connect() always fail with a return value of -1 and get a IOexception.
My questions are:
When my android application connect to the ELM327 device, my android phone is the bluetooth client and my ELM327 device is the bluetooth server, is this understanding correct?
Is there a server program running on my ELM327 device listening and accept incoming connection? Is this defined behavior of ELM327 protocol?
Any idea why mSocket.connect()has failed? Any idea on how to look into this issue? Or any obvious error in my program? Thanks.
problem solved. see source codes below:
public synchronized void connect() throws IOException {
try {
// Get a BluetoothSocket to connect with the given BluetoothDevice.
// MY_UUID is the app's UUID string, also used in the server code.
mSocket = mOBDDevice.createRfcommSocketToServiceRecord(UUID.fromString(uuid));
} catch (IOException e) {
Log.e(TAG, "Socket's create() method failed", e);
}
try {
// Connect to the remote device through the socket. This call blocks
// until it succeeds or throws an exception.
mSocket.connect();
} catch (IOException e1) {
Log.e(TAG, "There was an error while establishing Bluetooth connection. Falling back..", e1);
Class<?> clazz = mSocket.getRemoteDevice().getClass();
Class<?>[] paramTypes = new Class<?>[]{Integer.TYPE};
try {
Method m = clazz.getMethod("createRfcommSocket", paramTypes);
Object[] params = new Object[]{Integer.valueOf(1)};
mFallbackSocket = (BluetoothSocket) m.invoke(mSocket.getRemoteDevice(), params);
mFallbackSocket.connect();
mSocket.close();
mSocket = mFallbackSocket;
} catch (Exception e2) {
Log.e(TAG, "Couldn't fallback while establishing Bluetooth connection.", e2);
mSocket.close();
//throw new IOException();
}
}
inputStream = mSocket.getInputStream();
outputStream = mSocket.getOutputStream();
}
I don't know much about Android, although I know about OBD2 and the lot.
It depends on the type of your adapter. If you have a WiFi adapter, you can consider the adapter being the server and you the client. You connect to a socket and then read from it. In the case of a Bluetooth adapter, it's different. If you connect via rfcomm, it's a serial protocol and neither is the server nor the client. If you connect via BTLE, the OBD2 dongle is the Peripheral and you are the Central.
On WiFi adapters, yes. This behavior is not part of ELM327 though. ELM327 only specifies the serial commands. How you transfer these is not part of the spec, since it happens on the layer above (WiFi, rfcomm, BTLE, USB, etc.).
Are you sure that rfcomm works via the socket interface? It's a serial interface, so I would have expected file-like operations.
I'm struggling with getting consistent bluetooth connections in a star topology. I have one master phone which is a Samsung Galaxy S4 running API 10. All of the phones that connect to the bluetoothserver socket on the S4 are LG Dynamic Tracfones also running API 10.
Over the past few days, I have seen a LOT of conflicting information on the web about what type of connection to use.
This is my current set up:
MASTER CODE
public void acceptConnection() {
.... (enable bt adapter) ...
// initializes a Bluetooth server socket
bluetoothServerSocket = bc.createBluetoothServerSocket();
//connection made to Master, discovery no longer needed
bluetoothAdapter.cancelDiscovery();
BluetoothSocket bluetoothSocket;
// loops until the thread is interrupted or an exception occurs
while (!isInterrupted()) {
try {
// attempts to accept the slave application's connection
bluetoothSocket = bluetoothServerSocket.accept();
} catch (IOException e) {
// prints out the exception's stack trace
e.printStackTrace();
Log.v("Default Thread", "Connection to slave failed.");
// breaks out of the while loop
return;
}
try {
... (enumerate all input and output streams, and all bt sockets) ...
} catch (IOException e) {
// prints out the exception's stack trace
e.printStackTrace();
}
}
This is the method that is called when creating a blueToothServerSocket, and this is where half of my confusion is. How should I listen on the adapter? Currently, I'm doing it insecurely.
public BluetoothServerSocket createBluetoothServerSocket() {
// gets the name of the application
String name = "PVCED";
// gets a common UUID for both the master and slave applications
UUID uuid = UUID.fromString("23ea856c-49da-11e4-9e35-164230d1df67");
// initializes an empty Bluetooth server socket
serverSocket = null;
try {
// creates a Bluetooth socket using a common UUID
serverSocket = bluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord(name, uuid);
} catch (IOException e) {
// prints out the exception's stack trace
e.printStackTrace();
}
return serverSocket;
}
SLAVE CODE
And this is where the other half of my confusion is, how should I create a socket? Currently I'm doing it insecurely.
private BluetoothSocket createBluetoothSocket(Set<BluetoothDevice> pairedDevices) {
// gets a common UUID for both the master and slave applications
UUID uuid = UUID.fromString("23ea856c-49da-11e4-9e35-164230d1df67");
// initialises an empty Bluetooth socket
BluetoothSocket bluetoothSocket = null;
// checks to see if there are any paired devices
if (pairedDevices.size() > 0) {
// loops through each paired device
for (BluetoothDevice device : pairedDevices) {
// checks to see if the name of the paired device is MASTER
if (device.getName().equals("MASTER")) {
try {
master = device;
// creates a Bluetooth socket using a common UUID
//bluetoothSocket = master.createRfcommSocketToServiceRecord(uuid);
//Method m = master.getClass().getMethod("createRfcommSocketToServiceRecord", new Class[] {int.class});
//bluetoothSocket = (BluetoothSocket) m.invoke(master, 1);
bluetoothSocket = master.createInsecureRfcommSocketToServiceRecord(uuid);
} catch(Exception e){
Log.v("Connect Exception", e.getMessage());
}
}
}
}
//check if we paired succesfully to a master, if not, prompt user to do so.
if (master == null){
... (tell user to pair with master via toast) ...
}
return bluetoothSocket;
}
My logcat is often filled with errors such as "Bad File Descriptor", "Unable to start Service Discovery", or "Service Discovery has failed."
What is the best connection scheme to use for my scenario? If you guys need more details on how I'm enabling/disabling bt adapters, or closing bt connections, I can supply more code.
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 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)
I am developing an Android bluetooth application based on the BluetoothChat exemple. i am starting a bluetooth server and listening for a device(not a phone) to connect to mine app on an insecure rfcomm connection.
private class AcceptThread extends Thread {
// The local server socket
private final BluetoothServerSocket mmServerSocket;
public AcceptThread(boolean secure) {
BluetoothServerSocket tmp = null;
// Create a new listening server socket
try {
tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(mServiceName, MY_UUID_INSECURE);
} catch (Exception e) {
Log.e(TAG, ".AcceptThread # listen() failed", e);
}
mmServerSocket = tmp;
}
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 conn");
socket = mmServerSocket.accept(); //FIXME: it blocks here
Log.d(TAG, ".AcceptThread.run # server socket connection accepted");
} catch (Exception e) {
MMLog.e(TAG, ".run # accept() failed: "+e);
connectionFailed();
break;
}
// If a connection was accepted
if (socket != null) {
synchronized (BluetoothService.this) {
switch (mState) {
case STATE_LISTEN:
case STATE_CONNECTING:
// starting the thread where i will receive input
// streams from the other device
connected(socket, socket.getRemoteDevice());
break;
case STATE_NONE:
case STATE_CONNECTED:
// Either not ready or already connected. Terminate new socket.
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close unwanted socket", e);
}
break;
}
}
}
}
}
public void cancel() {
try {
if(mmServerSocket != null) {
mmServerSocket.close();
}
} catch (IOException e) {
Log.e(TAG, ".cancel # Could not close server socket: ", e);
}
}
}
I am using a HTC Desire S, android 2.3.5. The device gets paired, but i don't receive data, because the connection gets blocked in the '.accept()' method. It just keeps on waiting.
socket = mmServerSocket.accept();
//...and waiting
Why does it still wait, if the device is paired?
How can i establish the connection, because i also tried reflection, and still no result
Is there a problem with HTC's Bluetooth stack? Has anyone established the connection maybe using another android phone?
I think there is something wrong with your code, shouldn't it be socket = tmp.accept(); here is what I have to make a socket server connection:
BluetoothServerSocket serverSocket = null;
BluetoothAdapter bta = BluetoothAdapter.getDefaultAdapter();
try {
serverSocket = bta.listenUsingInsecureRfcommWithServiceRecord("BluetoothChatInsecure", UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
} catch (IOException e) { e.printStackTrace(); }
while(!Thread.interrupted()) {
try {
socket = serverSocket.accept();
if (socket != null) {
Log.d("CONNECTED", "Connected bluetooth");
/// do your stuff
Chances are, this has to do with your other device (this is happening to me). Your Android already does its job which is listing for incoming connections. There are many reason why your special device won't initiate connections properly to your Android phone:
The device mysteriously switch to other Bluetooth profile e.g. HDP instead of SPP
The device somehow remembers a different Android phone in its memory (it was last connected to or something like that) and keeps trying to connect to that phone but not the one you are using right now.
I suppose your best chance is to query the manufacturer/ seller of the special device for detailed specifications and/or software/ driver to configure/ test it.