How to handle InputStream and OutputStream via Bluetooth in Android - java

I'm developing an Android app that handles an alarm system made with an Arduino.
I have to handle InputStream from the Arduino and OutputStream to Arduino. First, I used a thread to initialize the connection for the Bluetooth socket and it works, but inside the thread I have to call a sort of Service/Thread that could make me handle streams from and to Arduino but I don't know how to do it.
The fact is that the hypothetical service has to listen continuously if there are streams, it has to stop only when I want and not after a certain period of time. Thanks for the help! Here is the code related to the Bluetooth socket connection:
public class ConnectThread extends Thread {
private final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
private final BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket,
// because mmSocket is final
BluetoothSocket tmp = null;
mmDevice = device;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) { }
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
while (!Thread.currentThread().isInterrupted()) {
mBluetoothAdapter.cancelDiscovery();
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
try {
mmSocket.close();
Log.i("Log", "Socket closed");
this.interrupt();
Log.i("Log", "Thread interrupted");
} catch (IOException closeException) {
}
}
//I think here I have to start a sort of Service/Thread..
}
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
this.interrupt();
Log.i("Log", "Thread interrupted");
} catch (IOException e) { }
}
}

I have implemented a similar algorithm, that I basically copied from the BluetoothChatSample, that for example comes with android studio samples, too.
You can see all the concepts, how to receive and send a String in the sample and they have added permissions, dialogs to ask the user about enabling Bluetooth and such, too.

Related

Android bluetooth send message working first time only

I need to send string message from Raspberry PI to Android device. I am getting message first time only. After that it does not work at all. I am using PYTHON code in Raspberry PI. After first time, it is unable to search for a bluetooth device, which is running that UUID. However, if I restart Android application - again it works fine for first time. I am using AcceptThread as suggested here. I have not used ConnectThread or ConnectedThread in my application, as I need only incoming messages. Do I need to close something on Pause or Destroy. Or, do I need to do something which is not mentioned in that page?
Here is that code:
private UUID MY_UUID = UUID.fromString("1e0ca4ea-299d-4335-93eb-27fcfe7fa848");
private AcceptThread acceptThread;
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
// Use a temporary object that is later assigned to mmServerSocket,
// because mmServerSocket is final
BluetoothServerSocket tmp = null;
try {
// MY_UUID is the app's UUID string, also used by the client code
tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(TAG, MY_UUID);
} catch (IOException e) { }
mmServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned
while (true) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
break;
}
// If a connection was accepted
if (socket != null) {
// Do work to manage the connection (in a separate thread)
manageConnectedSocket(socket);
try {
mmServerSocket.close();
}
catch(IOException e){
}
break;
}
}
}
/** Will cancel the listening socket, and cause the thread to finish */
public void cancel() {
try {
mmServerSocket.close();
} catch (IOException e) { }
}
}
I am not using PI message, just logging a string. As mentioned above, it works first time:
private void manageConnectedSocket(BluetoothSocket socket) {
Log.i(TAG, "Hurray!! I am here");
//acceptThread.cancel();
}
Here is the PYTHON code in Raspberry PI:
import sys
import bluetooth
uuid = "1e0ca4ea-299d-4335-93eb-27fcfe7fa848"
service_matches = bluetooth.find_service( uuid = uuid )
if len(service_matches) == 0:
print "couldn't find the BluetoothWithPi service"
sys.exit(0)
first_match = service_matches[0]
port = first_match["port"]
name = first_match["name"]
host = first_match["host"]
print "connected to \"%s\" on %s" % (name, host)
sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM )
sock.connect((host, port))
sock.send("Hello from Raspberry PI!!")
sock.close()
First time it displays 'Connected to ...' message. Second time it displays 'Couldn't find...' message.
We just need to add some code into manageConnectedSocket block. Basically we need to cancel the acceptThread if not null and restart the service:
private void manageConnectedSocket(BluetoothSocket socket) {
Log.i(TAG, "Hurray!! I am here");
//
if (acceptThread != null) {
acceptThread.cancel();
acceptThread = null;
}
//
if (acceptThread == null) {
acceptThread = new AcceptThread();
acceptThread.start();
}
}

How to programmatically connect to a Bluetooth device after it's already paired (bonded) in Android

I have been working on trying to get a Bluetooth device like a keyboard or a remote to connect to an android device. More specifically when this program runs for the first time it would scan for Bluetooth devices and attempt to pair and connect with one that it finds. I have tried seemingly every possible way to accomplish this but I am only able to pair the device, not connect it completely.
I have tried the examples in the Android Bluetooth guide and many others. One consistency is the javi.io error I get when the BluetoothSocket is calling connect.
java.io.IOException: read failed, socket might closed or timeout, read ret: -1
at android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:505)
at android.bluetooth.BluetoothSocket.waitSocketSignal(BluetoothSocket.java:482)
at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:324)
at BTConnectThread.run(BTConnectThread.java:61)
I have tried different UUIDs. Some I generated myself others I pulled from the devices. I also tried writing code assuming both are acting as servers that mirrors mostly what I am doing here and what is in the Android Bluetooth guide. have tried all variations of calling createBond() on the device. All attempts leave the device paired/bonded but not connected. Any help is greatly appreciated.
` public BTConnectThread(BluetoothDevice bluetoothDevice) {
BluetoothSocket tempSocket = null;
try {
// tempSocket = bluetoothDevice.createRfcommSocketToServiceRecord(WELL_KNOWN_UUID);
// tempSocket = bluetoothDevice.createInsecureRfcommSocketToServiceRecord(WELL_KNOWN_UUID);
//Magic?
Method method = bluetoothDevice.getClass().getMethod("createRfcommSocket",
new Class[]{int.class});
tempSocket = (BluetoothSocket) method.invoke(bluetoothDevice, 1);
} catch (Exception e) {
e.printStackTrace();
}
m_bluetoothSocket = tempSocket;
}
public void run() {
//cancel discovery
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter != null)
bluetoothAdapter.cancelDiscovery();
//TODO: Try brute force approach. Loop until it connects.
//TODO: Try a fallback socket.
try {
m_bluetoothSocket.connect();
Log.d(TAG, "Connection Established");
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
Log.d(TAG, "Fail to connect!", connectException);
try {
m_bluetoothSocket.close();
} catch (IOException closeException) {
Log.d(TAG, "Fail to close connection", closeException);
}
return;
}
}
public void cancel() {
try {
m_bluetoothSocket.close();
} catch (IOException e) {
}
}`
Bluetooth connection require to create more than 3 threads, so you can try to use https://android-arsenal.com/details/1/1859.
Kotlin
Connect Function
fun connect(btDevice: BluetoothDevice?){
val id: UUID = btDevice?.uuids?.get(0)!!.uuid
val bts = btDevice.createRfcommSocketToServiceRecord(id)
bts?.connect()
}
Call this in main thread
val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
val device = bluetoothAdapter.getRemoteDevice("your mac address")
connect(device)

How to Use Classes - Bluetooth Thread

I'm trying to connect android and arduino and send data between them. I am following the guide http://developer.android.com/guide/topics/connectivity/bluetooth.html#ManagingAConnection
I think I vaguely understand how this works but I don't have a complete mastery of the basics so I am a bit stuck.
I am looking at the code for "connecting as a client":
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;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) { }
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
mBluetoothAdapter.cancelDiscovery();
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
try {
mmSocket.close();
} catch (IOException closeException) { }
return;
}
// Do work to manage the connection (in a separate thread)
manageConnectedSocket(mmSocket);
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
and for "managing connection"
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) { }
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 (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
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) { }
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
I basically copied the exact code and made new java files containing them.
I want to actually use these classes to send data so I paired the devices and then found the IDs like:
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0)
{
// Loop through paired devices
for (BluetoothDevice device : pairedDevices)
{
if (device.getName().equals("HC-06"))
{
//NEED TO INSERT CODE HERE (I think...)
}
else
{
Intent intentneedsetting = new Intent(this, NeedSettingsActivity.class);
startActivity(intentneedsetting);
}
}
}
else
{
Intent intentneedsetting = new Intent(this, NeedSettingsActivity.class);
startActivity(intentneedsetting);
}
Any help regarding how to use these classes (ConnectThread/ConnectedThread) will be very appreciated!
I'm not sure what did you vaguley understood and what not but i'll try to explain the purpose of these classes in general..
ConnectThread - receives a bluetooth device that was discovered in the discovery stage (which is prior to connection obviously) gets the BT socket from the device and when run() is called it tries to connect to it.
if the connection succeeded - in the code it just says manageConnectedSocket(mmSocket); but that means that u should open a ConnectedThread for receiving and sending data through the socket.
ConnectedThread - as mentioned, is the thread for managing sending and receiving data. as you can see in the run() it constantly listens using a while(true) it calls read which is blocking - meaning "the thread is stuck there" until it receives incoming data.
When data is received it handles it with the mHandler which is also not implemented here, again you should just implement whatever you want to do with the data received.
The write method simply receives an array of bytes and writes it to the socket, note that this is also a blocking call therefore u should use it from another thread.
Hope this helps u understand

Bluetooth works one way only

I am very new to android and java so be gentle :)
I'm trying to connect two phones via bloototh.
i am making both phones to listen of incoming calls by creating serversocket, then initializing connection from one phone (as a client). funny part is that when I try to make my LG (android version 2.3.4) to connect HTC (android 2.2.1) everything works fine, but when i try to make HTc phone to connect as a client i get no result. Debugger shows that HTC fails at mmSocket.connect(); and executes catch (IOException connectException). My code is basicly copy/paste from android bluetooth tutorial. Any suggestions why phones behaves differently? Connect thread:
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;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) { }
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
BtAdapter.cancelDiscovery();
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect(); **HTC phones fails here and goes to CATCH block**
// make info message
Message msg = mainHandler.obtainMessage();
Bundle bundle = new Bundle();
String btnTxt = "Connected";
bundle.putString("myKey", btnTxt);
msg.setData(bundle);
mainHandler.sendMessage(msg);
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
try {
mmSocket.close();
} catch (IOException closeException) { }
return;
}
// Do work to manage the connection (in a separate thread)
ConnectedThread conThread = new ConnectedThread(mmSocket);
conThread.start();
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
There may be in issue with
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
on your HTC 2.21 device. Check what features the HTC device's Bluetoth adapter supports, that could be related to why it is failing with your program.
"Use this socket only if an authenticated socket link is possible.
Authentication refers to the authentication of the link key to prevent
man-in-the-middle type of attacks. For example, for Bluetooth 2.1
devices, if any of the devices does not have an input and output
capability or just has the ability to display a numeric key, a secure
socket connection is not possible. In such a case, use {#link
createInsecureRfcommSocketToServiceRecord}. For more details, refer to
the Security Model section 5.2 (vol 3) of Bluetooth Core Specification
version 2.1 + EDR."
http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createRfcommSocketToServiceRecord%28java.util.UUID%29

Bluetooth socket freeze phone

I am developing an application for Android. This app should communicate with a Bluetooth (BT) device (sending some bytes). I have a problem with debugging/running this app on my device (Samsung Galaxy mini). When I create a BT socket and stop debugging, phone freeze and I have to restart it by getting out the battery. In case of running this app (from Eclipse) everything is OK, but when I try to run it again, phone freeze and app is not installed. If I try to unninstall this app manualy before second run, phone freeze again. Here is a problematic code:
private final BluetoothDevice mmDevice;
private UUID uuid;
public ConnectionThread(BluetoothDevice device) {
Log.d(TAG, "create ConnectionThread");
uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
BluetoothSocket tmp = null;
mmDevice = device;
try {
tmp = mmDevice.createRfcommSocketToServiceRecord(uuid);
} catch (IOException e) { }
mmSocket = tmp;
socketConnected = true;
}
This is a constructor of thread. When I comment the line
tmp = mmDevice.createRfcommSocketToServiceRecord(uuid);
the phone doesn´t freeze so problem is with creating socket (not connecting). Restarting phone after each debugging or running is pretty annoying and I have to do a lot of work yet.
If I run this app from a phone (disconnected from Eclipse), it works without any problems. Any ideas where could be a problem or how to fix it? Thank you.
I am using SGSIII mini as well for development. The following code works well for me:
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);
tmp = device.createInsecureRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
Log.e(LOG_TAG, "create() failed", e);
}
mmSocket = tmp;
Main.myBluetoothSocket = mmSocket;
Main.myBluetoothDevice = mmDevice;
}
#Override
public void run() {
Log.i(LOG_TAG, "BEGIN mConnectThread");
setName("ConnectThread");
// Always cancel discovery because it will slow down a connection
mAdapter.cancelDiscovery();
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(MESSAGE_TOAST);
Log.e(LOG_TAG, "Attempting connection to " + mmSocket.getRemoteDevice().getName());
String ss = "Attempting connection to " + mmSocket.getRemoteDevice().getName();
Bundle bundle = new Bundle();
bundle.putString(TOAST, ss);
msg.setData(bundle);
mHandler.sendMessage(msg);
// 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) {
Log.e(LOG_TAG, "*+*+*+* Connection Failed");
connectionFailed();
// Close the socket
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(LOG_TAG, "unable to close() socket during connection failure", e2);
}
// Start the service over to restart listening mode
BluetoothCommandService.this.start();
return;
}
// Reset the ConnectThread because we're done
synchronized (BluetoothCommandService.this) {
mConnectThread = null;
}
// Start the connected thread
connected(mmSocket, mmDevice);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(LOG_TAG, "close() of connect socket failed", e);
}
}
}
I am also facing same problem you can use Reflection method it will work
Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
BluetoothSocket socket = socket = (BluetoothSocket) m.invoke(device, 1);

Categories