Android BluetoothSocket can't connect - java

I'm doing some stuff with bluetooth on android and I would like to connect to one of the discovered devices and open a socket connection towards it.
I've granted all of the needed permissions: Bluetooth, Bluetooth_Admin, Access_Fine_Location and Access_Coarse_Location and ask for them before I do anything with bluetooth.
Now, I've discovered some devices with adapter.startDiscovery(); and activity.registerReceiver(receiver, filter);
In the receiver finds a device of a certain name, I try connecting to it like this:
adapter.cancelDiscovery();
Log.d(TAG, "Create Bond");
device.createBond();
try {
socket = device.createRfcommSocketToServiceRecord(uuid);
Log.d(TAG, "Sleep 10");
sleep(10000);
Log.d(TAG, "Create Socket");
//socket = device.createInsecureRfcommSocketToServiceRecord(uuid);
Log.d(TAG, "Connect socket");
socket.connect();
Log.d(TAG, "Connecting Done");
} catch (Exception e) {
Log.d(TAG, "Failed to connect to device", e);
try {
socket.close();
} catch (Exception e2) {
Log.d(TAG, "Failed to close socket", e2);
}
}
This is a test code with which I'm trying to create a socket and open a connection.
I get the following Exception on .connect():
java.io.IOException: read failed, socket might closed or timeout, read
ret: -1
at android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:684)
at android.bluetooth.BluetoothSocket.readInt(BluetoothSocket.java:696)
at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:373)
What am I doing wrong.
The bluetooth device I connect to is a Android mobile device, but I plan on using others when I manage to get the connection.
Update1:
Android version is 7.0

use fetchUuidsWithSdp() and getUuids() to find all the published services and their associated UUID values.

You don't need to call device.createBond(); to connect to a Bluetooth device.
Try removing this line. Also check, that your phone is not already paired with the device you're trying to connect to.
You can check that on the Bluetooth settings screen (open it with a long press on the Bluetooth icon on your smartphone.
Here is a sample code to initiates a Bluetooth connection :
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket
// because mmSocket is final.
BluetoothSocket tmp = null;
mmDevice = device;
try {
// Get a BluetoothSocket to connect with the given BluetoothDevice.
// MY_UUID is the app's UUID string, also used in the server code.
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
Log.e(TAG, "Socket's create() method failed", e);
}
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it otherwise slows down the connection.
bluetoothAdapter.cancelDiscovery();
try {
// Connect to the remote device through the socket. This call blocks
// until it succeeds or throws an exception.
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and return.
try {
mmSocket.close();
} catch (IOException closeException) {
Log.e(TAG, "Could not close the client socket", closeException);
}
return;
}
// The connection attempt succeeded. Perform work associated with
// the connection in a separate thread.
manageMyConnectedSocket(mmSocket);
}
// Closes the client socket and causes the thread to finish.
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close the client socket", e);
}
}
}
This code is from Android official doc:
https://developer.android.com/guide/topics/connectivity/bluetooth#ConnectAsAClient

I wrote another code instead of what I was using for server side.
Log.d(TAG,"Start server");
BluetoothServerSocket serverSocket = null;
try {
serverSocket = adapter.listenUsingRfcommWithServiceRecord("ime", uuid);
} catch (Exception e) {
e.printStackTrace();
}
while (true) {
try {
serverSocket.accept();
} catch (Exception e) {
e.printStackTrace();
}
}
I used this code inside of a thread which starts instead of calling the code from the question.
Installing the App with server code on one app and calling "connect" on socket did the trick.
I used the same UUID (previous was random generated, new one was static from string).

Related

Android: BluetoothSocket receives its own output

I have an app that connects to a RaspberryPi via Bluetooth and loops the same data to it while it receives some data back.
I had some issues with the connection so this workaround is needed to connect my android phone to the RaspberryPi: IOException: read failed, socket might be closed - Bluetooth on Android 4.3
For some reason, the android phone is receiving its own output.
The String "Hello Raspberry. It's me, AndroidPhone" is sent to the output in a never-ending loop. The incoming data (from the RaspberryPi) is also read in a never-ending loop.
But somehow I don't only receive the data from the RaspberryPi but also the string sends via smartphone. This is my code:
public class MainActivity extends AppCompatActivity {
private BluetoothAdapter bluetoothAdapter;
UUID SERIAL_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
#Override
protected void onCreate(Bundle savedInstanceState) {
// (...)
// Only GUI-stuff until this point
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice raspberryPi = bluetoothAdapter.getRemoteDevice("B8:27:EB:56:DC:B2");
BluetoothSocket btSocket;
try {
btSocket = raspberryPi.createRfcommSocketToServiceRecord(SERIAL_UUID);
btSocket.connect();
} catch (IOException e) {
Log.e("BTError", e.getMessage());
// Workaround, found on: https://stackoverflow.com/questions/18657427/ioexception-read-failed-socket-might-closed-bluetooth-on-android-4-3
try {
Log.e("BTError", "Trying fallback...");
btSocket = (BluetoothSocket) raspberryPi.getClass().getMethod("createRfcommSocket", new Class[]{int.class}).invoke(raspberryPi, 1);
btSocket.connect();
(new Thread(new SendingThread(btSocket))).start();
(new Thread(new ReceivingThread(btSocket))).start();
} catch (Exception e2) {
Log.e("BTError", e2.getMessage());
Log.e("BTError", "Couldn't establish Bluetooth connection!");
}
}
}
private class SendingThread extends Thread {
private OutputStream out;
public SendingThread(BluetoothSocket btSocket) {
try {
out = btSocket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
try {
int delay = 100000000;
while (true) {
if (delay == 0) {
Log.i("WRT", "Written to RaspberryPi");
out.write("Hello Raspberry. It's me, AndroidPhone".getBytes());
delay = 100000000;
}
delay--;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private class ReceivingThread extends Thread {
private InputStream in;
public ReceivingThread(BluetoothSocket btSocket) {
try {
in = btSocket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
int data = 0;
while (true) {
try {
data = in.read();
} catch (IOException e) {
e.printStackTrace();
}
Log.i("RCV", String.valueOf((char) data));
}
}
}
On the RaspberryPi end, everything looks normal. A simple java program starts the Linux command rfcomm listen /dev/rfcomm0 and reads from/writes to the file /dev/rfcomm0 with FileReader and FileWriter. The only relevant lines on this end are:
run {
// Inside writer-thread
bluetoothWriter = new BufferedWriter(new FileWriter("/dev/rfcomm0"));
while(true) {
bluetoothWriter.write("This is RaspPi");
bluetoothWriter.flush();
}
}
and
run {
// Inside reader-thread
bluetoothReader = new BufferedReader(new FileReader("/dev/rfcomm0"));
while(true) {
int incData = bluetoothReader.read();
System.out.print((char) incData);
}
}
Thank you for your help!
edit: Still no solution to this problem. I suspected that the RaspberryPi is somehow sending back what it received. But when I disabled that it sends out anything, the smartphone still directly receives what it has sent out.
I scoured over the Bluetooth classes sources. The workaround seems legit from the first glances. Try this first:
if (delay == 0) {
Log.i("WRT", "Written to RaspberryPi");
out.write("Hello Raspberry. It's me, AndroidPhone".getBytes());
out.flush(); // <-- You are not flushing
delay = 100000000;
}
And the message sticks in you socket for you to read over and over again.
If that does not fix it the other option I can think of is that somehow the socket is initialized to be a socket to your Android device. The .createRfcommSocket() method seems to create a socket to your own device if the Bluetooth device is null when the socket was being created. I'm not sure how this would exactly happen, but if the Raspberry Pi's state is somehow mangled after exception I suppose it could be something to look into.
On the raspy side: If you are just starting both of those threads doesn't it mean that you are constantly sending messages to /dev/rfcomm0 and flushing. I recommend that you change it so that raspy reacts to a received message by sending back the wanted message instead of spamming all the time. I'm not sure if this is part of your problem but it would at least make debugging & development a bit easier.
I am not sure if this is the solution you need, because I don't know if you are using bluetooth classic or bluetooth 4.0>+, but I wrote a library for text based BLE and WiFi P2P 2-way communication for android (and I know the Raspberry Pi is capable of BLE communication), I don't create a socket connection for BLE communication though, but I do for WiFi P2P. Take a look, I hope it helps. It isn't published yet, so you would have to clone/fork the repo.
I think you have trouble writing
As far as I know, for buffer, should use \n and ...
bluetoothWriter.write("This is RaspPi\n");
But I prefer to use a combination of DataOutputStream and BufferedReader
For Read:
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
try {
String line = bufferedReader.readLine();
System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
}
for write:
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
String s = "Hi\n";
try {
dataOutputStream.write(s.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
It is better to correct the point made by a dear friend about flush() ...
I'm not sure, please test yourself ...

How do I close any previous Bluetooth sockets after my app starts?

In my app, I open and close a Bluetooth socket on the same device each session and listen for data. When I close one, I make sure to close the input and output streams and then socket in a cancel method. Still, for some people the app keeps trying to read from the device. I know because I read logs that are from run() in the listening thread, where there is a flag for listening that's set to false in cancel, and the listening thread will end when the socket is closed due to an IOException, but this never happens, so the socket must still be opened. I see logs of attempted reads every second of every day even though the person isn't using the app. This might be because the app crashes and the cancel method isn't called. Either way I can't guarantee the cancel method will be called. How do I close any Bluetooth sockets that were previously opened when I start up my app, if these were all opened in new threads created independently?
This guy had the same problem but I didn't see any solution:
Android bluetooth connection doesn't close after application crash
The accepted answer is no good because:
The current users haven't had the UncaughtExceptionHandler run that code yet and they need to have any previous connections closed when the new version is released
The UncaughtExceptionHandler must have a reference to the sockets, which it doesn't have. I want to be able to close any Bluetooth sockets when the app starts.
The guy who made that question asked how to get information about the socket to store for when the app starts up and you want to close them, and got no response.
EDIT:
How I open the socket (removed logging code):
try {
tmp.connect();;
} catch (IOException e) {
isConnected = false;
try {
tmp = (BluetoothSocket) device.getClass().getMethod("createRfcommSocket",
new Class[] {int.class}).invoke(device, 1);
} catch (Exception e2) {
e2.printStackTrace();
}
try {
tmp.connect();
setConnected();
} catch (IOException e1) {
e1.printStackTrace();
isConnected = false;
cancel();
}
How I close the socket:
public void cancel() {
isConnected = false;
listening = false;
try {
if (manageConnection.mmInStream != null) {
manageConnection.mmInStream.close();
manageConnection.mmInStream = null;
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (manageConnection.mmOutStream != null) {
manageConnection.mmOutStream.close();
manageConnection.mmOutStream = null;
}
} catch (IOException e) {
e.printStackTrace();
}
try {
mmSocket.close();
mmSocket = null;
manageConnection = null;
} catch (IOException e) {
// Logging code
}
}
}
Listening:
while (listening == true) {
try {
synchronized (ListeningActivity.lock) {
buffer = new byte[mmInStream.available()];
mmInStream.read(buffer);
....
} catch (IOException e) {
// Code that calls cancel()

Android interrupt threads on button click - avoiding race condition

I have an android app designed to pair with other phones and send/receive data over bluetooth. Specifically, when a user clicks a button, it will start discovery, connect to a phone, open a socket etc. In general this works, however, I also want to set it up so that during this whole process, if the user clicks the button again, it will correctly close/stop this process. The problem I'm having is that when the user clicks to stop, sometimes it will close a socket prematurely while the app is still trying to check for incoming data because this is all happening across multiple threads. I'm trying to find the correct way to handle this
So when the user clicks to start the process, discovery will happen and then it will try to connect to the paired device over a socket:
private class ConnectThread extends Thread {
private BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket,
// because mmSocket is final
mmDevice = device;
}
public void run() {
// Cancel discovery because it will slow down the connection
mBluetoothAdapter.cancelDiscovery();
while(!this.isInterrupted()){
BluetoothSocket tmp = null;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// SERVICE_UUID is the app's UUID string, also used by the server code
tmp = mmDevice.createRfcommSocketToServiceRecord(SERVICE_UUID);
} catch (IOException e) {
e.printStackTrace();
}
mmSocket = tmp;
if(mmSocket != null){
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
Log.d(TAG, "Socket connected");
// Do work to manage the connection (in a separate thread)
connectedThread = new ConnectedThread(mmSocket);
connectedThread.start();
break;
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
Log.d(TAG, "Unable to connect socket: " + connectException.getMessage());
}
}
}
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
Log.d(TAG, "Closing socket");
mmSocket.close();
this.interrupt();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Once the socket has connected, I start a different thread to set up the datastreams:
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (!this.isInterrupted()) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI activity
mHandler.obtainMessage(Constants.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
this.interrupt();
} catch (IOException e) {
e.printStackTrace();
}
}
}
So this all works as far as sending/receiving data goes. But when the user clicks the button a second time to stop the entire process (or kill the connection if it already exists) I get an error. On pressing Stop the following code gets executed:
if(btHelper.discoveryStarted){
this.discoveryStarted = false;
mBluetoothAdapter.cancelDiscovery();
}
//Stop socket connection
if(connectThread != null & connectedThread != null){
connectedThread.cancel();
connectThread.cancel();
}
The error I get is an ioexception: bt socket closed, read return: -1 and its pointing to the line where I'm trying to read from the datastream:
bytes = mmInStream.read(buffer)
So the problem is that its trying to read from the stream, but on button click I have already told the socket to close, therefore theres no socket to read from. Whats the correct way to interrupt these threads to avoid a race condition like this?
Furthermore, how do I set this up so that regardless of where the user is in this process the appropriate threads/sockets/connections will be closed correctly? (for example, sometimes the socket will be opened, but data streams have not been set up yet, vs both/neither have been created)

How to check if server connection exists?

In my app I have asyncTask classes, that connects to a local/remote server to get some data, I want to check the server connection before the asyncTask runs,
I have this function:
public static boolean checkServerAvailable(String hostURL) {
HttpURLConnection connection = null;
try {
URL u = new URL(hostURL);
connection = (HttpURLConnection) u.openConnection();
connection.setConnectTimeout(5000);
connection.setRequestMethod("HEAD");
int code = connection.getResponseCode();
System.out.println("" + code);
return true;
// You can determine on HTTP return code received. 200 is success.
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
This function uses timeout to connect to server, and if the timeout expires it means that there is no server. The problem is that I'm run this code and it's returning "there is no server" even if the server exists.
I've tried to set a big timeout like 5000ms but it pauses the UI very long time, and sometimes still returns "there is no server" even when the server is exist.
what can I do?
Thank you!
check the server connection before the asyncTask runs
Then you have to do that in another AsyncTask.
So this all makes little sense.
You are not using StrictMode is it?
try using socket here is example code
Socket socket;
final String host = "your.server.IP.or.host";
final int port = 80;
final int timeout = 5000; // 5 seconds or what ever time you want
try {
socket = new Socket();
socket.connect(new InetSocketAddress(host, port), timeout);
}
catch (UnknownHostException uhe) {
Log.e("ServerSock", "I couldn't resolve the host you've provided!");
}
catch (SocketTimeoutException ste) {
Log.e("ServerSock", "After a reasonable amount of time, I'm not able to connect, Server is probably down!");
}
catch (IOException ioe) {
Log.e("ServerSock", "Hmmm... Sudden disconnection, probably you should start again!");
}

Sending a string via Bluetooth from a PC as client to a mobile as server

I need help by transferring a string from a PC to an Android mobile device via Bluetooth. The Android mobile device should act as a server and displays the string message on the screen of the device. The PC which is the client should send the string to the mobile device.
I want the server react on the extracted string (transferred via Bluetooth). That means that on one side the server always has to listen for new strings to arrive, but on the other side still has to be able to react on these messages (e.g. navigate from one menu to another).
I tried it by using BlueCove (2.1.1) as BluetoothStack (for which I add the jar from BlueCove as a library to both projects) in combination with an example for a server-client communication that I found here.
Updates:
Updated code from server thanks to user_CC using a RFComm connection for the server:
public class RFCommServer extends Thread{
//based on java.util.UUID
private static UUID MY_UUID = UUID.fromString("446118f0-8b1e-11e2-9e96-0800200c9a66");
// The local server socket
private BluetoothServerSocket mmServerSocket;
// based on android.bluetooth.BluetoothAdapter
private BluetoothAdapter mAdapter;
private BluetoothDevice remoteDevice;
private Activity activity;
public RFCommServer(Activity activity) {
this.activity = activity;
}
public void run() {
BluetoothSocket socket = null;
mAdapter = BluetoothAdapter.getDefaultAdapter();
// Listen to the server socket if we're not connected
while (true) {
try {
// Create a new listening server socket
Log.d(this.getName(), ".....Initializing RFCOMM SERVER....");
// MY_UUID is the UUID you want to use for communication
mmServerSocket = mAdapter.listenUsingRfcommWithServiceRecord("MyService", MY_UUID);
//mmServerSocket = mAdapter.listenUsingInsecureRfcommWithServiceRecord(NAME, MY_UUID); // you can also try using In Secure connection...
// This is a blocking call and will only return on a
// successful connection or an exception
socket = mmServerSocket.accept();
} catch (Exception e) {
}
try {
Log.d(this.getName(), "Closing Server Socket.....");
mmServerSocket.close();
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
DataInputStream mmInStream = new DataInputStream(tmpIn);
DataOutputStream mmOutStream = new DataOutputStream(tmpOut);
// here you can use the Input Stream to take the string from the client whoever is connecting
//similarly use the output stream to send the data to the client
RelativeLayout layout = (RelativeLayout) activity.findViewById(R.id.relativeLayout_Layout);
TextView text = (TextView) layout.findViewById(R.id.textView_Text);
text.setText(mmInStream.toString());
} catch (Exception e) {
//catch your exception here
}
}
}
Code of the SPP Client from here:
/**
* A simple SPP client that connects with an SPP server
*/
public class SampleSPPClient implements DiscoveryListener{
//object used for waiting
private static Object lock=new Object();
//vector containing the devices discovered
private static Vector vecDevices=new Vector();
private static String connectionURL=null;
public static void main(String[] args) throws IOException {
SampleSPPClient client=new SampleSPPClient();
//display local device address and name
LocalDevice localDevice = LocalDevice.getLocalDevice();
System.out.println("Address: "+localDevice.getBluetoothAddress());
System.out.println("Name: "+localDevice.getFriendlyName());
//find devices
DiscoveryAgent agent = localDevice.getDiscoveryAgent();
System.out.println("Starting device inquiry...");
agent.startInquiry(DiscoveryAgent.GIAC, client);
try {
synchronized(lock){
lock.wait();
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Device Inquiry Completed. ");
//print all devices in vecDevices
int deviceCount=vecDevices.size();
if(deviceCount <= 0){
System.out.println("No Devices Found .");
System.exit(0);
}
else{
//print bluetooth device addresses and names in the format [ No. address (name) ]
System.out.println("Bluetooth Devices: ");
for (int i = 0; i <deviceCount; i++) {
RemoteDevice remoteDevice=(RemoteDevice)vecDevices.elementAt(i);
System.out.println((i+1)+". "+remoteDevice.getBluetoothAddress()+" ("+remoteDevice.getFriendlyName(true)+")");
}
}
System.out.print("Choose Device index: ");
BufferedReader bReader=new BufferedReader(new InputStreamReader(System.in));
String chosenIndex=bReader.readLine();
int index=Integer.parseInt(chosenIndex.trim());
//check for spp service
RemoteDevice remoteDevice=(RemoteDevice)vecDevices.elementAt(index-1);
UUID[] uuidSet = new UUID[1];
uuidSet[0]=new UUID("446118f08b1e11e29e960800200c9a66", false);
System.out.println("\nSearching for service...");
agent.searchServices(null,uuidSet,remoteDevice,client);
try {
synchronized(lock){
lock.wait();
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
if(connectionURL==null){
System.out.println("Device does not support Simple SPP Service.");
System.exit(0);
}
//connect to the server and send a line of text
StreamConnection streamConnection=(StreamConnection)Connector.open(connectionURL);
//send string
OutputStream outStream=streamConnection.openOutputStream();
PrintWriter pWriter=new PrintWriter(new OutputStreamWriter(outStream));
pWriter.write("Test String from SPP Client\r\n");
pWriter.flush();
//read response
InputStream inStream=streamConnection.openInputStream();
BufferedReader bReader2=new BufferedReader(new InputStreamReader(inStream));
String lineRead=bReader2.readLine();
System.out.println(lineRead);
}//main
//methods of DiscoveryListener
public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
//add the device to the vector
if(!vecDevices.contains(btDevice)){
vecDevices.addElement(btDevice);
}
}
//implement this method since services are not being discovered
public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
if(servRecord!=null && servRecord.length>0){
connectionURL=servRecord[0].getConnectionURL(0,false);
}
synchronized(lock){
lock.notify();
}
}
//implement this method since services are not being discovered
public void serviceSearchCompleted(int transID, int respCode) {
synchronized(lock){
lock.notify();
}
}
public void inquiryCompleted(int discType) {
synchronized(lock){
lock.notify();
}
}//end method
}
For testing I use a Galaxy Nexus (GT-I9250) with the latest Android API.
Thanks to user_CC, the client and server now runs without an exception. But sadly the client is not able to connect to the server (see the screenshot below). It is because the connectionURL is never set (thus it jumps in here if(connectionURL==null) by default.
How can I change the client code, so that I actually can connect it with the server? I need a proper connectionURL in the following line:
StreamConnection streamConnection=(StreamConnection)Connector.open(connectionURL)
So far I only found out that I somehow need to get the ServiceRecord, sadly this is also not described in the example code from here.
You will need to use the RFComm APIS to make the communication work I have managed to define a class which is a Thread and will be acting as a server and listening for client connections. I have also placed some comments for you to understand.
private class AcceptThread extends Thread {
// The local server socket
private BluetoothServerSocket mmServerSocket;
public AcceptThread() {
}
public void run() {
BluetoothSocket socket = null;
BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter();
// Listen to the server socket if we're not connected
while (true) {
try {
// Create a new listening server socket
Log.d(TAG, ".....Initializing RFCOMM SERVER....");
// MY_UUID is the UUID you want to use for communication
mmServerSocket = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
//mmServerSocket = mAdapter.listenUsingInsecureRfcommWithServiceRecord(NAME, MY_UUID); you can also try using In Secure connection...
// This is a blocking call and will only return on a
// successful connection or an exception
socket = mmServerSocket.accept();
} catch (Exception e) {
}
try {
Log.d(TAG, "Closing Server Socket.....";
mmServerSocket.close();
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
mmInStream = new DataInputStream(tmpIn);
mmOutStream = new DataOutputStream(tmpOut);
// here you can use the Input Stream to take the string from the client whoever is connecting
//similarly use the output stream to send the data to the client
} catch (Exception e) {
//catch your exception here
}
}
}
}
I hope this helps
For your another question:
Declaring javax.bluetooth.UUID on Client side (PC) UUID class should be from javax.bluetooth.UUID
uuidSet2[0] = new UUID("446118f08b1e11e29e960800200c9a66", false);
Declaring java.util.UUID at Server Side (Android)
UUID MY_UUID = UUID.fromString("446118f0-8b1e-11e2-9e96-0800200c9a66");
I'm not a Java developer but I've had a similar issue with Mono for Android (c#)
The UUID for SPP should be "00001101-0000-1000-8000-00805F9B34FB"
This is a well known UID to identify a Bluetooth SPP adapter.
In my c# code that looks like
private static UUID MY_UUID = UUID.FromString("00001101-0000-1000-8000-00805F9B34FB");
I'm guessing you can update your Java code to something like:
new UUID("00001101-0000-1000-8000-00805F9B34FB", true);
Although I'm not sure what parameters that function accepts, so you may have to check that.
I was using the Android device as a client, but the information may be of use to you,
so I'll include my c# code here which I originally translated from Java samples, so you should be able to translate it back:
btAdapter = BluetoothAdapter.DefaultAdapter;
btAdapter.CancelDiscovery(); //Always call CancelDiscovery before doing anything
remoteDevice = btAdapter.GetRemoteDevice(Settings["deviceaddress"].ToString());
socket = remoteDevice.CreateRfcommSocketToServiceRecord(MY_UUID);
socket.Connect();
Basically I get the default adapter, cancel any running discovery operations and then
create a socket to the other device. In your case you'll want to listen instead of connecting, but just for your information.
I hope it helps, sorry I could not give you more Java specific information.
'Update:' Just found a little sample in Java that more or less follows the same method
as what I'm using: Problems with connecting bluetooth SPP in android?

Categories

Resources