I want to create two apps, one to just send text over Bluetooth and the other to just receive it. But the problem is that even though both devices are connected successfully no text is being transferred. Particularly the outStream.write(bytes) in Messages activity is no working.
Unlike most questions, I just want one-way simplex chat from Sender to Receiver; not a two-way chat.
Any help would be appreciated.
This is the sender code:
//member variables
private BluetoothAdapter btAdapter=null;
private ConnectThread btConnectThread;
private ConnectedThread btConnectedThread;
private int btState;
// Constants that indicate the current connection state
public static final int STATE_NONE = 0; // we're doing nothing
public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
public static final int STATE_CONNECTED = 3; // now connected to a remote device
//dev name to be returned to UI
private static final int DEVICE_NAME=0;
//sent message returned to UI
private static final int SENT_MESSAGE=1;
private static final int STATUS=2;
/**
* Return Intent extra
*/
public static String EXTRA_DEVICE_ADDRESS = "device_address";
// Unique UUID for this application
private static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
//handler for UI thread
private final Handler handle=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
TextView dvNm=(TextView) findViewById(R.id.connectedTo);
TextView sntMsg=(TextView) findViewById(R.id.sentMessage);
TextView stat=(TextView) findViewById(R.id.statusTest);
EditText tyMsg=(EditText) findViewById(R.id.typedMessage);
String temp;
switch (msg.what)
{
case DEVICE_NAME:
{
temp=dvNm.getText().toString();
dvNm.setText(temp+": "+msg.obj.toString());
break;
}
case SENT_MESSAGE:
{
temp=msg.obj.toString();
sntMsg.setText("Sent: "+temp);
tyMsg.setText("");
break;
}
case STATUS:
{
temp=msg.obj.toString();
stat.setText(temp);
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messages);
btAdapter=BluetoothAdapter.getDefaultAdapter();
}
@Override
protected void onStart() {
super.onStart();
Intent dList=getIntent();
String macAddr=dList.getStringExtra(EXTRA_DEVICE_ADDRESS);
if(btState==STATE_NONE)
{
connect(macAddr);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(btState!=STATE_NONE)
stop();
}
//button listener for sending message
public void onSend(View v)
{
//get the typed message
EditText tyMsg=(EditText) findViewById(R.id.typedMessage);
//convert it to byte format
byte[] send=tyMsg.getText().toString().getBytes();
// Create temporary object
ConnectedThread cThrd;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
if (btState != STATE_CONNECTED) return;
cThrd = btConnectedThread;
}
// Perform the write asynchronized
cThrd.write(send);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_messages, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* Bluetooth Client component code
*/
private class ConnectThread extends Thread {
private final BluetoothSocket btSocket;
private final BluetoothDevice btDevice;
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to btSocket,
// because btSocket is final
BluetoothSocket tmp = null;
btDevice = 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) { }
btSocket = 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
btSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
try {
btSocket.close();
} catch (IOException closeException) { }
return;
}
// Do work to manage the connection (in a separate thread)
connected(btSocket,btDevice);
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
btSocket.close();
} catch (IOException e) { }
}
}
/**
* Code to manage the connected socket
*/
private class ConnectedThread extends Thread {
private final BluetoothSocket btSocket;
private final OutputStream outStream;
public ConnectedThread(BluetoothSocket socket) {
btSocket = socket;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
outStream = tmpOut;
}
public void run() { }
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
Message msg2=handle.obtainMessage(STATUS,"Inside write of connectedthread");
handle.sendMessage(msg2);
outStream.write(bytes);
outStream.flush();
Message msg1=handle.obtainMessage(STATUS,"Wrote to outstream");
handle.sendMessage(msg1);
Message msg=handle.obtainMessage(SENT_MESSAGE,bytes);
handle.sendMessage(msg);
} catch (IOException e) { }
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
btSocket.close();
} catch (IOException e) { }
}
}
/**
* Start the ConnectThread to initiate a connection to a remote device.
*
* @param macAddr is the mac-address The BluetoothDevice to connect
*/
public synchronized void connect(String macAddr) {
//get Bluetooth device from mac-address
BluetoothDevice device = btAdapter.getRemoteDevice(macAddr);
// Cancel any thread attempting to make a connection
if (btState == STATE_CONNECTING) {
if (btConnectThread != null) {
btConnectThread.cancel();
btConnectThread = null;
}
}
// Cancel any thread currently running a connection
if (btConnectedThread != null) {
btConnectedThread.cancel();
btConnectedThread = null;
}
// Start the thread to connect with the given device
btConnectThread = new ConnectThread(device);
btConnectThread.start();
btState=STATE_CONNECTING;
}
/**
* Start the ConnectedThread to begin managing a Bluetooth connection
*
* @param socket The BluetoothSocket on which the connection was made
* @param device The BluetoothDevice that has been connected
*/
public synchronized void connected(BluetoothSocket socket, BluetoothDevice
device) {
// Cancel the thread that completed the connection
if (btConnectThread != null) {
btConnectThread.cancel();
btConnectThread = null;
}
// Cancel any thread currently running a connection
if (btConnectedThread != null) {
btConnectedThread.cancel();
btConnectedThread = null;
}
// Start the thread to manage the connection and perform transmissions
btConnectedThread = new ConnectedThread(socket);
btConnectedThread.start();
// Send the name of the connected device back to the UI Activity
Message msg = handle.obtainMessage(DEVICE_NAME,device.getName());
handle.sendMessage(msg);
btState=STATE_CONNECTED;
}
/**
* Stop all threads
*/
public synchronized void stop(){
// Cancel the thread that completed the connection
if (btConnectThread != null) {
btConnectThread.cancel();
btConnectThread = null;
}
// Cancel any thread currently running a connection
if (btConnectedThread != null) {
btConnectedThread.cancel();
btConnectedThread = null;
}
btState=STATE_NONE;
}
}
And this is the receiver code:
//member variables
private BluetoothAdapter btAdapter=null;
private AcceptThread btAcceptThread;
private ConnectedThread btConnectedThread;
private int btState;
// Constants that indicate the current connection state
public static final int STATE_NONE = 0; // we're doing nothing
public static final int STATE_LISTEN = 1; // now listening for incoming connections
public static final int STATE_CONNECTED = 3; // now connected to a remote device
//dev name to be returned to UI
private static final int DEVICE_NAME=0;
//received message returned to UI
private static final int RECEIVED_MESSAGE=1;
// Name for the SDP record when creating server socket
private static final String NAME = "BluetoothAnnouncement";
// Unique UUID for this application
private static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
//handler for UI thread
private final Handler handle=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
TextView dvNm=(TextView) findViewById(R.id.connectedTo);
TextView rcvdMsg=(TextView) findViewById(R.id.receivedMessage);
String temp;
switch (msg.what)
{
case DEVICE_NAME:
{
temp=dvNm.getText().toString();
dvNm.setText(temp+": "+msg.obj.toString());
break;
}
case RECEIVED_MESSAGE:
{
temp=msg.obj.toString();
rcvdMsg.setText("Received: "+temp);
break;
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Acquiring Bluetooth Adapter
btAdapter = BluetoothAdapter.getDefaultAdapter();
//setting initial state
}
@Override
protected void onStart() {
super.onStart();
if(!btAdapter.isEnabled())
{
Toast.makeText(this, "Please enable Bluetooth to receive announcements",
Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onResume() {
super.onResume();
if(btAdapter.isEnabled())
{
if(btState==STATE_NONE)
{
start();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(btState!=STATE_NONE)
stop();
}
//enabling Bluetooth
public void btEnable(View v)
{
if (btAdapter.isEnabled())
{
Toast.makeText(this, "Bluetooth already enabled",
Toast.LENGTH_SHORT).show();
}
else
{
Intent discoverableIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 0);
startActivity(discoverableIntent);
}
}
/**
* Server component code
*/
private class AcceptThread extends Thread {
private final BluetoothServerSocket btServerSocket;
public AcceptThread() {
// Use a temporary object that is later assigned to btServerSocket,
// because btServerSocket is final
BluetoothServerSocket tmp = null;
try {
// MY_UUID is the app's UUID string, also used by the client code
tmp = btAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) { }
btServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
BluetoothDevice device;
// Keep listening until exception occurs or a socket is returned
while (true) {
try {
socket = btServerSocket.accept();
} catch (IOException e) {
break;
}
// If a connection was accepted
if (socket != null) {
device=socket.getRemoteDevice();
// Do work to manage the connection (in a separate thread)
connected(socket, device);
try {
btServerSocket.close();
} catch (IOException e) { }
break;
}
}
}
/** Will cancel the listening socket, and cause the thread to finish */
public void cancel() {
try {
btServerSocket.close();
} catch (IOException e) { }
}
}
/**
* Code to manage the connected socket
*/
private class ConnectedThread extends Thread {
private final BluetoothSocket btSocket;
private final InputStream inStream;
public ConnectedThread(BluetoothSocket socket) {
btSocket = socket;
InputStream tmpIn = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
} catch (IOException e) { }
inStream = tmpIn;
}
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 = inStream.read(buffer);
// Send the obtained bytes to the UI activity
Message msg = handle.obtainMessage(RECEIVED_MESSAGE,bytes);
handle.sendMessage(msg);
} catch (IOException e) {
break;
}
}
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
btSocket.close();
} catch (IOException e) { }
}
}
/**
* Start the chat service. Specifically start AcceptThread to begin a
* session in listening (server) mode. Called by the Activity onResume()
*/
public synchronized void start() {
// Cancel any thread currently running a connection
if (btConnectedThread != null) {
btConnectedThread.cancel();
btConnectedThread = null;
}
// Start the thread to listen on a BluetoothServerSocket
if (btAcceptThread == null) {
btAcceptThread = new AcceptThread();
btAcceptThread.start();
}
//set state
btState=STATE_LISTEN;
}
/**
* Start the ConnectedThread to begin managing a Bluetooth connection
*
* @param socket The BluetoothSocket on which the connection was made
* @param device The BluetoothDevice that has been connected
*/
public synchronized void connected(BluetoothSocket socket, BluetoothDevice
device) {
// Cancel any thread currently running a connection
if (btConnectedThread != null) {
btConnectedThread.cancel();
btConnectedThread = null;
}
// Cancel the accept thread because we only want to connect to one device
if (btAcceptThread != null) {
btAcceptThread.cancel();
btAcceptThread = null;
}
// Start the thread to manage the connection and perform transmissions
btConnectedThread = new ConnectedThread(socket);
btConnectedThread.start();
// Send the name of the connected device back to the UI Activity
Message msg = handle.obtainMessage(DEVICE_NAME,device.getName());
handle.sendMessage(msg);
btState=STATE_CONNECTED;
}
/**
* Stop all threads
*/
public synchronized void stop(){
// Cancel any thread currently running a connection
if (btConnectedThread != null) {
btConnectedThread.cancel();
btConnectedThread = null;
}
// Cancel the accept thread because we only want to connect to one device
if (btAcceptThread != null) {
btAcceptThread.cancel();
btAcceptThread = null;
}
btState=STATE_NONE;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}