title: How to get bluetooth RFCOMM to work consistently?
body: <p>I am trying to build an Android application that will interface with an external GPS receiver via the Bluetooth Serial Port Profile (SPP). I am using a Nexus One running 2.3.3. I have managed to get my application to receive data from GPS, but I have two issues: 1) When I connect to the device, it only works some of the time. Sometimes the connection just times out, other times it says the device is busy or in use. 2) I haven't been able to figure out how to send data back to the device, which is probably an issue of how I'm using the streams since the incoming stream is a blocking call.</p>
  
  <p>I moved just the relevant code to a new Android application for testing, which is the following:</p>
  
  <p>/res/layout/main.xml (two buttons and a textview)</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"&gt;
  &lt;Button android:id="@+id/btnStart" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Connect"&gt;&lt;/Button&gt;
  &lt;Button android:id="@+id/btnSend" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Send Message"&gt;&lt;/Button&gt;
  &lt;TextView android:id="@+id/textStatus" android:textSize="24sp" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Status Goes Here" /&gt;
  &lt;/LinearLayout&gt;
  </code></pre>
  
  <p>/src/com.example.bluetoothspp/MainActivity.java</p>
  
  <pre><code>package com.example.bluetoothspp;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.lang.reflect.Method;
  import java.net.SocketTimeoutException;
  import java.util.UUID;
  
  import android.app.Activity;
  import android.bluetooth.BluetoothAdapter;
  import android.bluetooth.BluetoothDevice;
  import android.bluetooth.BluetoothSocket;
  import android.os.Bundle;
  import android.os.Handler;
  import android.os.Message;
  import android.util.Log;
  import android.view.View;
  import android.view.View.OnClickListener;
  import android.widget.Button;
  import android.widget.TextView;
  
  public class MainActivity extends Activity {
      private static final String TAG = "MainActivity";
      private static final String BTAG = "BTThread";
      static final int MSG_BT_GOT_DATA = 1;
      static final int MSG_BT_STATUS_MSG = 2;
      static final int MSG_BT_FINISHED = 99;
  
      Button btnStart, btnSend;
      TextView textStatus;
      private BluetoothAdapter mBluetoothAdapter = null;
      private BluetoothDevice btdevice = null;
      Thread bThread;
      BluetoothSocket bsocket;
      InputStream bis = null; //Bluetooth input stream
      OutputStream bos = null; //Bluetooth output stream
      private String MACAddress = "00:01:95:06:1F:32";
  
  
      @Override
      public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.main);
          btnStart = (Button)findViewById(R.id.btnStart);
          btnSend = (Button)findViewById(R.id.btnSend);
          textStatus = (TextView)findViewById(R.id.textStatus);
          btnStart.setOnClickListener(btnStartListener);
          btnSend.setOnClickListener(btnSendListener);
  
          mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
      }
  
      private OnClickListener btnStartListener = new OnClickListener() {
          public void onClick(View v){
              if(btnStart.getText().equals("Connect")){
                  Log.i(TAG, "Connect button pressed");
                  if (mBluetoothAdapter == null) { //No adapter. Fail
                      Log.e(TAG, "getDefaultAdapter returned null");
                      textStatus.setText("getDefaultAdapter returned null");
  
                  } else {
                      if (!mBluetoothAdapter.isEnabled()) { //Bluetooth disabled
                          Log.e(TAG, "Bluetooth is Disabled");
                          textStatus.setText("Bluetooth is Disabled");
  
                      } else {
                          Log.i(TAG, "Connecting to Device: " + MACAddress);
                          btdevice = mBluetoothAdapter.getRemoteDevice(MACAddress);
                          Log.i(TAG, "Device: " + btdevice.getName());
                          Log.i(TAG, "Trying to Connect...");
                          textStatus.setText("Trying to Connect...");
                          Log.i(TAG, "Starting Thread");
                          try {
                              bThread = new Thread(new BluetoothClient(btdevice, true));
                              bThread.start();
                          } catch (IOException e) {
                              Log.e(TAG, "Could not create thread for bluetooth: " + e);
                              textStatus.setText("Could not create thread for bluetooth...");
                          }
                          btnStart.setText("Disconnect");
                      }
                  }
  
              } else {
                  Log.i(TAG, "Disconnect button pressed");
  
                  btnStart.setText("Connect");
              }
          }
      };
      private OnClickListener btnSendListener = new OnClickListener() {
          public void onClick(View v){
              textStatus.setText("Sending Message to Thread.");
              SendDataToBluetooth("something\r\n");
          }
      };
  
  
      public class BluetoothClient implements Runnable {
          public BluetoothClient(BluetoothDevice device, boolean IsAnHTCDevice) throws IOException {
              if (IsAnHTCDevice) {
                  //This is a workaround for HTC devices, but it likes to throw an IOException "Connection timed out"
                  try {
                      Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
                      bsocket = (BluetoothSocket) m.invoke(device, Integer.valueOf(1));
                  } catch (Exception e) {
                      Log.e(BTAG, "Error at HTC/createRfcommSocket: " + e);
                      e.printStackTrace();
                      handler.sendMessage(handler.obtainMessage(MSG_BT_STATUS_MSG, "MethodException: " + e));
                  }
              } else {
                  //This is the normal method, but on a Nexus One it almost always throws an IOException "Service discovery failed" message
                  try {
                      UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
                      bsocket = device.createRfcommSocketToServiceRecord(MY_UUID);
                  } catch (Exception e) {
                      Log.e(BTAG, "Error at createRfcommSocketToServiceRecord: " + e);
                      e.printStackTrace();
                      handler.sendMessage(handler.obtainMessage(MSG_BT_STATUS_MSG, "MethodException: " + e));
                  }
              }
          }
  
          public void run() {
              try {
                  Log.i(BTAG, "Cancelling Discovery");
                  mBluetoothAdapter.cancelDiscovery();
                  Log.i(BTAG, "Connecting to Socket");
                  bsocket.connect();
                  bis = bsocket.getInputStream();
                  bos = bsocket.getOutputStream();
                  Log.i(BTAG, "Socket created, streams assigned");
                  handler.sendMessage(handler.obtainMessage(MSG_BT_STATUS_MSG, "Device Connected"));
                  Log.i(BTAG, "Waiting for data...");
                  byte[] buffer = new byte[4096];
                  int read = bis.read(buffer, 0, 4096); // This is blocking
                  Log.i(BTAG, "Getting data...");
                  while (read != -1) {
                      byte[] tempdata = new byte[read];
                      System.arraycopy(buffer, 0, tempdata, 0, read);
                      handler.sendMessage(handler.obtainMessage(MSG_BT_GOT_DATA, tempdata));
                      read = bis.read(buffer, 0, 4096); // This is blocking
                  }
              } catch (SocketTimeoutException e) {
                  e.printStackTrace();
              } catch (IOException e) {
                  e.printStackTrace();
              } catch (Exception e) {
                  e.printStackTrace();
              } finally {
                  Log.i(BTAG, "Finished");
                  handler.sendMessage(handler.obtainMessage(MSG_BT_FINISHED));
              }
          }
      }
      public void SendDataToBluetooth(String cmd) { // You run this from the main thread.
          try {
              if (bsocket != null) {
                  bos.write(cmd.getBytes());
              }
          } catch (Exception e) {
              Log.e("SendDataToBluetooth", "Message send failed. Caught an exception: " + e);
          }
      }
  
      public Handler handler = new Handler() { // Handler for data coming from the network and bluetooth sockets
          @Override
          public void handleMessage(Message msg) {
              switch (msg.what) {
              case MSG_BT_GOT_DATA:
                  Log.i("handleMessage", "MSG_BT_GOT_DATA: " + (String) msg.obj);
                  textStatus.setText((String) msg.obj);
                  break;
              case MSG_BT_STATUS_MSG:
                  Log.i("handleMessage", "MSG_BT_STATUS_MSG: " + (String) msg.obj);
                  textStatus.setText((String) msg.obj);
                  break;
              case MSG_BT_FINISHED:
                  Log.i("handleMessage", "MSG_BT_FINISHED");
                  btnStart.setText("Connect");
                  break;
              default:
                  super.handleMessage(msg);
              }
          }
      };
  
  
      @Override
      protected void onDestroy() {
          super.onDestroy();
          if (bThread != null) { // If the thread is currently running, close the socket and interrupt it.
              Log.i(BTAG, "Killing BT Thread");
              try {
                  bis.close();
                  bos.close();
                  bsocket.close();
                  bsocket = null;
              } catch (IOException e) {
                  Log.e(BTAG, "IOException");
                  e.printStackTrace();
              } catch (Exception e) {
                  Log.e(BTAG, "Exception");
                  e.printStackTrace();
              }
              try {
                  Thread moribund = bThread;
                  bThread = null;
                  moribund.interrupt();
              } catch (Exception e) {}
              Log.i(BTAG, "BT Thread Killed");
          }
      }
  }
  </code></pre>
  
  <p>I found that using the normal "bsocket = device.createRfcommSocketToServiceRecord(MY_UUID);" method would usually result in a "Service discovery failed" message for me, so I also tried the "bsocket = (BluetoothSocket) m.invoke(device, Integer.valueOf(1));" method. That works more often, but likes to time out when I try to connect.</p>
  
  <p>What am I doing wrong here?</p>