Make rfcomm connections thread based to prevent blocking calls

Change-Id: I0018c06ac5e100fa6dd00d945690fb39493c658f
Cherry-Pick of: https://android-review.googlesource.com/#/c/231675/
diff --git a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothRfcommFacade.java b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothRfcommFacade.java
index c362b7e..f25e93e 100644
--- a/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothRfcommFacade.java
+++ b/Common/src/com/googlecode/android_scripting/facade/bluetooth/BluetoothRfcommFacade.java
@@ -62,6 +62,7 @@
   private Map<String, BluetoothConnection>
           connections = new HashMap<String, BluetoothConnection>();
   private BluetoothSocket mCurrentSocket;
+  private ConnectThread mCurrThread;
 
   public BluetoothRfcommFacade(FacadeManager manager) {
     super(manager);
@@ -105,22 +106,28 @@
     BluetoothSocket mSocket;
     BluetoothConnection conn;
     mDevice = mBluetoothAdapter.getRemoteDevice(address);
-    mSocket = mDevice.createRfcommSocketToServiceRecord(UUID.fromString(uuid));
-
     // Register a broadcast receiver to bypass manual confirmation
     IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
     mService.registerReceiver(mPairingReceiver, filter);
-
-    // Always cancel discovery because it will slow down a connection.
-    mBluetoothAdapter.cancelDiscovery();
-    mSocket.connect();
-    conn = new BluetoothConnection(mSocket);
-    mCurrentSocket = mSocket;
-
+    ConnectThread t = new ConnectThread(mDevice, uuid);
+    t.run();
+    mCurrThread = t;
+    conn = new BluetoothConnection(mCurrThread.getSocket());
+    Log.d("Connection Successful");
     mService.unregisterReceiver(mPairingReceiver);
     return addConnection(conn);
   }
 
+  @Rpc(description = "Kill thread")
+  public void bluetoothRfcommKillConnThread() {
+    try {
+        mCurrThread.cancel();
+        mCurrThread.join(5000);
+    } catch (InterruptedException e) {
+        Log.e("Interrupted Exception: " + e.toString());
+    }
+  }
+
   /**
    * Closes an active Rfcomm socket
    */
@@ -170,6 +177,7 @@
     BluetoothSocket mSocket = mServerSocket.accept(timeout.intValue());
     BluetoothConnection conn = new BluetoothConnection(mSocket, mServerSocket);
     mService.unregisterReceiver(mPairingReceiver);
+    mCurrentSocket = mSocket;
     return addConnection(conn);
   }
 
@@ -291,8 +299,50 @@
     }
     connections.clear();
   }
+  private class ConnectThread extends Thread {
+    private final BluetoothSocket mmSocket;
+
+    public ConnectThread(BluetoothDevice device, String uuid) {
+      BluetoothSocket tmp = null;
+      try {
+        tmp = device.createRfcommSocketToServiceRecord(UUID.fromString(uuid));
+      } catch (IOException createSocketException) {
+        Log.e("Failed to create socket: " + createSocketException.toString());
+      }
+      mmSocket = tmp;
+    }
+
+    public void run() {
+      mBluetoothAdapter.cancelDiscovery();
+      try {
+        mmSocket.connect();
+      } catch(IOException connectException) {
+        Log.e("Failed to connect socket: " + connectException.toString());
+        try {
+          mmSocket.close();
+        } catch(IOException closeException){
+          Log.e("Failed to close socket: " + closeException.toString());
+        }
+        return;
+      }
+    }
+
+    public void cancel() {
+      try {
+        mmSocket.close();
+      } catch (IOException e){
+
+      }
+    }
+
+    public BluetoothSocket getSocket() {
+      return mmSocket;
+    }
+  }
+
 }
 
+
 class BluetoothConnection {
   private BluetoothSocket mSocket;
   private BluetoothDevice mDevice;