Bluetooth host not detecting incoming connections - android

I want to connect two cell phones using bluetooth with one of them being the host(listening for connections) and the other one initiating the connection. The code that initiates the connection works well and gets successfully connected to the other phone.
However the host gets stuck at socket.accept() because it doesn't detect the connection. The UUIDs are the same on both devices so I really have no clue about what the porblem is.
Here's the AcceptThread of the host:
private class AcceptThread extends Thread {
// The local server socket
private final BluetoothServerSocket mmServerSocket;
boolean running = true;
public AcceptThread() {
BluetoothServerSocket tmp = null;
// Create a new listening server socket
try {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, MY_UUID_SECURE);
} catch (IOException e) {
running = false;
Toast.makeText(getApplicationContext(), "socket failed: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
mmServerSocket = tmp;
}
public void run() {
setName("AcceptThread");
BluetoothSocket socket = null;
int state = getMState();
// Listen to the server socket if we're not connected
while (running) {
try {
// This is a blocking call and will only return on a
// successful connection or an exception
socket = mmServerSocket.accept();
} catch (IOException e) {
break;
}
// If a connection was accepted
if (socket != null) {
setState(STATE_CONNECTED);
Toast.makeText(getApplicationContext(), "Connected to: " + socket.getRemoteDevice().getName(), Toast.LENGTH_SHORT).show();
startConnectedThread(socket);
}
}
}
I can assure you the UUIDs that the both devices are using are the same: 00001101-0000-1000-8000-00805f9b34fb
Also I was testing this app on an older phone that has API Level lower than 15(as the host) and another phone(initiating) with API level 17. Can that cause connection issues??

I think that in a while loop should be running = false Once accepts is OK and also close acceptThread when starting ConnectedThread.
I would add check that mmServerSocket != Null
Alternatively, if that does not help to, add here more code (for ex. what is in StartConnectedThread)

Related

Android bluetooth connection to ELM327/OBD2 device

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.

How to connect two Bluetooth SPP devices within the same app?

I was wondering, does anyone know how to connect to two Bluetooth SPP devices within the same app? I looked at the BluetoothChat example, however, it doesn't give any information on how to connect to two Bluetooth SPP devices. I can't seem to find much information elsewhere either.
Let us assume we have two Bluetooth Devices B and C. To connect them we need
Bluetooth Sockets, one for each device.
Input and Output Streams to send messages.
Connection parameters: { Bluetooth Device(MAC Address), UUID }
To have multiple connections we must create these connection parameters dedicated to a connection.
This Thread is inside my service class.
First, bind service and create a method in service class like this,
call this method and pass Bluetooth mac address. it will connect in the background. for the second device also follow the similar procedure.
public synchronized void connectToDevice(String macAddress){
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(macAddress);
if (mState == STATE_CONNECTING){
if (mConnectThread != null){
mConnectThread.cancel();
mConnectThread = null;
}
}
if (mConnectedThread != null){
mConnectedThread.cancel();
mConnectedThread = null;
}
mConnectThread = new ConnectBtThread(device);
toast("connecting");
mConnectThread.start();
setState(STATE_CONNECTING);
}
Here i am creating Thread class to connect and run in background
private class ConnectBtThread extends Thread{
private final BluetoothSocket mSocket;
private final BluetoothDevice mDevice;
public ConnectBtThread(BluetoothDevice device){
mDevice = device;
BluetoothSocket socket = null;
try {
socket = device.createInsecureRfcommSocketToServiceRecord(UUID.fromString(B_UUID));
} catch (IOException e) {
e.printStackTrace();
}
mSocket = socket;
}
#Override
public void run() {
if (mBluetoothAdapter.isDiscovering()){
mBluetoothAdapter.cancelDiscovery();
}
try {
mSocket.connect();
Log.d("service","Bluetooth one running (connected)");
SharedPreferences pre = getSharedPreferences("BT_NAME",0);
pre.edit().putString("bluetooth_connected",mDevice.getName()).apply();
int i = 0;
Log.d("service","one + " +i++);
} catch (IOException e) {
try {
mSocket.close();
Log.d("service","connect thread run method ( close function)");
} catch (IOException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
connected(mSocket);
}
public void cancel(){
try {
mSocket.close();
//Toast.makeText(getApplicationContext(),"Failed to connect one",Toast.LENGTH_SHORT).show();
Log.d("service","connect thread cancel method");
} catch (IOException e) {
e.printStackTrace();
}
}
}
Similar to this create one more method and thread class to keep both Bluetooth devices in the Connected state.
I followed this and its working fine for me.

Bluetooth socket connection with Bluetooth PC server fails "ava.io.IOException: read failed, socket might closed or timeout, read ret: -1"

I am trying to create a connection between an Android smartphone (Client) with a Bluetooth app (server) running on a PC.
Below is the code snippet for Client
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private class ConnectThread extends Thread {
private BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
try {
//tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
tmp = device.createInsecureRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
Log.d(TAG, "create() failed", e);
e.printStackTrace();
}
mmSocket = tmp;
}
public void run() {
mAdapter.cancelDiscovery();
try {
mmSocket.connect();
}
catch (IOException e) {
//Exception caught
//java.io.IOException: read failed, socket might closed or timeout, read ret: -1
...
}
...
}
Below is the server code (Uses BlueCover jar)
private void waitForConnection() {
LocalDevice local = null;
StreamConnectionNotifier notifier;
StreamConnection connection = null;
try {
local = LocalDevice.getLocalDevice();
local.setDiscoverable(DiscoveryAgent.GIAC);
String uuidstr = "00001101-0000-1000-8000-00805F9B34FB";
String uuid_wo_space = uuidstr.replaceAll("-", "");
String url = "btspp://localhost:" + uuid_wo_space + ";authenticate=false;encrypt=false;name=RemoteBluetooth";
notifier = (StreamConnectionNotifier) Connector.open(url);
}
catch (Exception e) {
e.printStackTrace();
return;
}
// waiting for connection
while(true) {
try {
connection = notifier.acceptAndOpen();
Thread processThread = new Thread(new ProcessConnectionThread(connection));
processThread.start();
}
catch(Exception e) {
e.printStackTrace();
return;
}
}
I have read several links suggesting to change the UUID to "00001101-0000-1000-8000-00805F9B34FB", which i have already tried. I have also tried creating a not secure socket using createInsecureRfcommSocketToServiceRecord, which still fails with the same result.
Below is the IOException stack trace
java.io.IOException: read failed, socket might closed or timeout, read ret: -1
at android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:900)
at android.bluetooth.BluetoothSocket.readInt(BluetoothSocket.java:912)
at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:531)
Sorry for writing a new answer but this way the information is more visible than the reply. Here's an example list of UUIDs for my device:
UUID: 0000xxxx-0000-1000-8000-00805f9b34fb
i xxxx Status Mode
0 110a N.A.
1 1105 Connected Serial Port Protocol (SPP)
2 1106 Connected File transfer (FTP)
3 1116 N.A.
4 112d Connected Remote SIM mode
5 112f Connected Phone book request
6 1112 Connected
7 111f Connected
8 1132 Connected Message access request
There are usually a set of UUIDs that denote different modes of operation like File Transfer (FTP), Remote SIM, Phone book request etc.
You may query and try all the UUIDs on your interface like this:
device = (from bd in adapter.BondedDevices
where bd.Name == "YourDeviceName"
select bd).FirstOrDefault();
Android.OS.ParcelUuid[] parcel = device.GetUuids();
for (int i = 0; i < parcel.Length; i++) {
socket = device.CreateRfcommSocketToServiceRecord(parcel[i].Uuid);
try {
socket.Connect();
break;
}
catch {
throw new Exception("Unsupported UUID");
}
}
Also make sure no other device is connected to PC/Android and have an open socket because only one socket can be serviced at a time. You can have as many pairs as you want but only one socket running.

pairing blue tooth with user confirmation only

i want to pair Bluetooth with the confirmation from other side only..but i implemented a code and here no confirmation message send to other side ..so now how do i send confirmation message to other before pairing two devices via Bluetooth ..
i use this below code:
private class AcceptThread extends Thread {
// The local server socket
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
// Create a new listening server socket
try {
tmp = mAdapter
.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) {
Log.e(TAG, "listen() failed", e);
}
mmServerSocket = tmp;
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
mmDevice = device;
BluetoothSocket tmp = null;
// Get a BluetoothSocket for a connection with the given
// BluetoothDevice
try {
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
Log.e(TAG, "create() failed", e);
}
mmSocket = tmp;
}
#Override
public void run() {
Log.i(TAG, "BEGIN mConnectThread");
setName("ConnectThread");
// Always cancel discovery because it will slow down a connection
mAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket.connect();
} catch (IOException e) {
connectionFailed();
// Close the socket
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG,"unable to close() socket during connection failure",
e2);
}
// Start the service over to restart listening mode
BluetoothChatService.this.start();
return;
}
so pls see my code and pls suggest me how to pair 2 devices only when authenticated from remote side...i am using api level 7
You cannot send a message to the other device as long as the two devices are not paired, because you need a BluetoothSocket for that, which cannot be obtained unless you have the device's MAC address.
But what's the problem with the pairing request? It will show only the first time, then you can always find the device among the paired devices (mBluetoothAdapter.getBondedDevices()).
Buuut, if it's absolutely necessary for you to get rid of the Pairing request dialog showing at the beginning on the both parts, then you may try use an insecure channel (create the server socket with listenUsingInsecureRfcommWithServiceRecord and the client socket with createInsecureRfcommSocketToServiceRecord). The problem here is that you'll have to perform a scan every time you need to connect to a device, as the devices are not paired.
Hope it suits you, goodluck.

BluetoothServerSocket.accept() does not return even if device paired

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.

Categories

Resources