/Android/RcCarv0.5.2/RCCAR/src/com/cs421/rccar/Util/BluetoothCommunicationService.java

https://github.com/mewsicalcat/RcCar · Java · 523 lines · 333 code · 67 blank · 123 comment · 32 complexity · 3ff251fcc057d401c1a9ab9b40337039 MD5 · raw file

  1. package com.cs421.rccar.Util;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.OutputStream;
  5. import java.util.UUID;
  6. import android.bluetooth.BluetoothAdapter;
  7. import android.bluetooth.BluetoothDevice;
  8. import android.bluetooth.BluetoothServerSocket;
  9. import android.bluetooth.BluetoothSocket;
  10. import android.content.Context;
  11. import android.os.Handler;
  12. import android.util.Log;
  13. import com.cs421.rccar.UI.SlaveActivity;
  14. /**
  15. * A service which handles all states of a Bluetooth connection
  16. * between two paired Android devices
  17. * Used with Permission from the Android Developer Website
  18. *
  19. * @author David Widen
  20. * @author Jessie Young
  21. * @author Thomas Cheng
  22. *
  23. */
  24. public class BluetoothCommunicationService
  25. {
  26. private static UUID MY_UUID = UUID.fromString("437ee550-fde6-11e0-be50-0800200c9a66");
  27. private static String AppName = "RcCar";
  28. private final BluetoothAdapter mAdapter;
  29. private final Handler mHandler;
  30. private AcceptThread mAcceptThread;
  31. private ConnectThread mConnectThread;
  32. private ConnectedThread mConnectedThread;
  33. private BluetoothState mState;
  34. public static final int STATE_NONE = 0; // we're doing nothing
  35. public static final int STATE_LISTEN = 1; // now listening for incoming connections
  36. public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
  37. public static final int STATE_CONNECTED = 3; // now connected to a remote device
  38. /**
  39. * Default constructor to create a new BluetoothCommunicationService
  40. * @param context the context of the activity that called this method
  41. * @param handler the handler which this service will report to
  42. */
  43. public BluetoothCommunicationService(Handler handler)
  44. {
  45. mAdapter = BluetoothAdapter.getDefaultAdapter();
  46. mState = BluetoothState.STATE_NONE;
  47. mHandler = handler;
  48. }
  49. /**
  50. * Set the current state of the connection
  51. * @param state the current state of the connection
  52. */
  53. private synchronized void setState(BluetoothState state)
  54. {
  55. mState = state;
  56. }
  57. /**
  58. * Get the current state of the connection
  59. * @return the state of the connection
  60. */
  61. public synchronized BluetoothState getState()
  62. {
  63. return mState;
  64. }
  65. /**
  66. * Inherited from Thread, starts the BluetoothCommunicationService
  67. */
  68. public synchronized void start()
  69. {
  70. Log.d("ARG", "BCS start()");
  71. if (mConnectThread != null)
  72. {
  73. mConnectThread.cancel();
  74. mConnectThread = null;
  75. }
  76. if (mConnectedThread != null)
  77. {
  78. mConnectedThread.cancel();
  79. mConnectedThread = null;
  80. }
  81. setState(BluetoothState.STATE_LISTEN);
  82. if (mAcceptThread == null)
  83. {
  84. mAcceptThread = new AcceptThread();
  85. mAcceptThread.start();
  86. }
  87. }
  88. /**
  89. * This device is connected to the remote device via BluetoothSocket
  90. * @param socket the socket which the devices use to communication
  91. * @param device the remove device this device is in communication with
  92. */
  93. public synchronized void connected(BluetoothSocket socket, BluetoothDevice device)
  94. {
  95. Log.d("ARG", "connected()");
  96. if (mConnectThread != null)
  97. {
  98. mConnectThread.cancel();
  99. mConnectThread = null;
  100. }
  101. if (mConnectedThread != null)
  102. {
  103. mConnectedThread.cancel();
  104. mConnectThread = null;
  105. }
  106. if (mAcceptThread != null)
  107. {
  108. mAcceptThread.cancel();
  109. mAcceptThread = null;
  110. }
  111. mConnectedThread = new ConnectedThread(socket);
  112. mConnectedThread.start();
  113. //Message handler stuff here
  114. setState(BluetoothState.STATE_CONNECTED);
  115. }
  116. /**
  117. * The connection has failed, and will attempt to restart itself
  118. */
  119. private void connectionFailed()
  120. {
  121. //Message handler, send message back to activity
  122. //Start service over!
  123. Log.d("ARG", "connectionFailed()");
  124. BluetoothCommunicationService.this.start();
  125. }
  126. /**
  127. * The connection has been lost, and will attempt to restart itself
  128. */
  129. private void connectionLost()
  130. {
  131. //Message handler, send message back to activity
  132. //Start service over!
  133. BluetoothCommunicationService.this.start();
  134. }
  135. /**
  136. * Connect this device to an external Bluetooth device
  137. * @param device the device to connect this Bluetooth device to
  138. */
  139. public synchronized void connect(BluetoothDevice device)
  140. {
  141. Log.d("ARG", "connect()");
  142. // Cancel any thread attempting to make a connection
  143. if (mState == BluetoothState.STATE_CONNECTING)
  144. {
  145. if (mConnectThread != null)
  146. {
  147. mConnectThread.cancel();
  148. mConnectThread = null;
  149. }
  150. }
  151. // Cancel any thread currently running a connection
  152. if (mConnectedThread != null)
  153. {
  154. mConnectedThread.cancel();
  155. mConnectedThread = null;
  156. }
  157. // Start the thread to connect with the given device
  158. mConnectThread = new ConnectThread(device);
  159. mConnectThread.start();
  160. setState(BluetoothState.STATE_CONNECTING);
  161. }
  162. /**
  163. * This class encapsulates a BluetoothServerSocket to use for communication
  164. * with an external Bluetooth device
  165. * Used with permission, originally developed on the Android Developer website
  166. *
  167. * @author David
  168. *
  169. */
  170. private class AcceptThread extends Thread
  171. {
  172. private final BluetoothServerSocket mServerSocket;
  173. public AcceptThread()
  174. {
  175. BluetoothServerSocket temp = null;
  176. try
  177. {
  178. temp = mAdapter.listenUsingRfcommWithServiceRecord(AppName, MY_UUID);
  179. }
  180. catch (IOException e)
  181. {
  182. //Add processing here for null value
  183. }
  184. mServerSocket = temp;
  185. }
  186. /**
  187. * Inherited from the Thread class, this starts the thread
  188. */
  189. public void run()
  190. {
  191. Log.d("ARG", "Accept ThreadRun!");
  192. BluetoothSocket socket = null;
  193. while (mState != BluetoothState.STATE_CONNECTED)
  194. {
  195. Log.d("ARG", "STATE: " + mState);
  196. try
  197. {
  198. socket = mServerSocket.accept();
  199. Log.d("ARG", "still running mServerSocket.accept()");
  200. }
  201. catch (IOException e)
  202. {
  203. Log.d("ARG", "Accept Thread caught Exception");
  204. break;
  205. }
  206. if (socket != null)
  207. {
  208. synchronized (BluetoothCommunicationService.this)
  209. {
  210. switch (mState)
  211. {
  212. case STATE_LISTEN:
  213. case STATE_CONNECTING:
  214. connected(socket, socket.getRemoteDevice());
  215. break;
  216. case STATE_NONE:
  217. case STATE_CONNECTED:
  218. try
  219. {
  220. socket.close();
  221. }
  222. catch (IOException e)
  223. {
  224. //add processing for not-closing
  225. }
  226. break;
  227. }
  228. }
  229. }
  230. }
  231. }
  232. /**
  233. * Cancels the thread, and closes the socket
  234. */
  235. public void cancel()
  236. {
  237. try
  238. {
  239. mServerSocket.close();
  240. }
  241. catch (IOException e)
  242. {
  243. //add processing for not-closing
  244. }
  245. }
  246. }
  247. /**
  248. * Encapsulates a BluetoothSocket and an external BluetoothDevice so they can be
  249. * connected to this Android device
  250. * Used with permission, originally developed on the Android Developer website
  251. *
  252. * @author David
  253. *
  254. */
  255. private class ConnectThread extends Thread
  256. {
  257. private final BluetoothSocket mSocket;
  258. private final BluetoothDevice mDevice;
  259. /**
  260. * Default constructor, initializes the BluetoothSocket
  261. * @param device the BluetoothDevice to connect to
  262. */
  263. public ConnectThread(BluetoothDevice device)
  264. {
  265. mDevice = device;
  266. BluetoothSocket temp = null;
  267. try
  268. {
  269. temp = device.createRfcommSocketToServiceRecord(MY_UUID);
  270. }
  271. catch (IOException e)
  272. {
  273. Log.d("ARG", "cannot createRfcommSocketToServiceRecord() in ConnectThread Constructor");
  274. }
  275. mSocket = temp;
  276. }
  277. /**
  278. * Inherited from Thread, starts the ConnectThread
  279. */
  280. public void run()
  281. {
  282. Log.d("ARG", "Connect Thread Run!");
  283. mAdapter.cancelDiscovery();
  284. try
  285. {
  286. mSocket.connect();
  287. }
  288. catch (IOException e)
  289. {
  290. try
  291. {
  292. mSocket.close();
  293. }
  294. catch (IOException e1)
  295. {
  296. //add processing for failure to close
  297. }
  298. connectionFailed();
  299. return;
  300. }
  301. synchronized (BluetoothCommunicationService.this)
  302. {
  303. mConnectThread = null;
  304. }
  305. connected(mSocket, mDevice);
  306. }
  307. /**
  308. * Closes the socket, and stops the thread
  309. */
  310. public void cancel()
  311. {
  312. try
  313. {
  314. mSocket.close();
  315. }
  316. catch (IOException e)
  317. {
  318. //add processing for failure to close
  319. }
  320. }
  321. }
  322. /**
  323. * Cancel all running threads
  324. */
  325. public synchronized void stop()
  326. {
  327. Log.d("ARG", "Stop");
  328. if (mConnectThread != null)
  329. {
  330. mConnectThread.cancel();
  331. mConnectThread = null;
  332. }
  333. if (mConnectedThread != null)
  334. {
  335. mConnectedThread.cancel();
  336. mConnectedThread = null;
  337. }
  338. if (mAcceptThread != null)
  339. {
  340. mAcceptThread.cancel();
  341. mAcceptThread = null;
  342. }
  343. setState(BluetoothState.STATE_NONE);
  344. }
  345. /**
  346. * Write data to the external BluetoothDevice
  347. * @param out the byte[] to send via Bluetooth
  348. */
  349. public void write(byte[] out)
  350. {
  351. // Create temporary object
  352. ConnectedThread r;
  353. // Synchronize a copy of the ConnectedThread
  354. synchronized (this)
  355. {
  356. if (mState != BluetoothState.STATE_CONNECTED)
  357. return;
  358. r = mConnectedThread;
  359. }
  360. // Perform the write unsynchronized
  361. r.write(out);
  362. Log.d("ARG", "BCS write!");
  363. }
  364. /**
  365. * Encapsulates a BluetoothSocket for remote communication to an external Bluetooth device
  366. * Allows for direct communication between the two devices via Bluetooth
  367. * Used with permission, originally developed on the Android Developer website
  368. *
  369. * @author David
  370. *
  371. */
  372. private class ConnectedThread extends Thread
  373. {
  374. private final BluetoothSocket mSocket;
  375. private final InputStream mInputStream;
  376. private final OutputStream mOutputStream;
  377. /**
  378. * Default Constructor for a ConnectedThread
  379. * @param socket the BluetoothSocket to communicate with
  380. */
  381. public ConnectedThread(BluetoothSocket socket)
  382. {
  383. mSocket = socket;
  384. InputStream tempIn = null;
  385. OutputStream tempOut = null;
  386. try
  387. {
  388. tempIn = socket.getInputStream();
  389. tempOut = socket.getOutputStream();
  390. }
  391. catch (IOException e)
  392. {
  393. //add processing for null streams
  394. }
  395. mInputStream = tempIn;
  396. mOutputStream = tempOut;
  397. }
  398. /**
  399. * Inherited from Thread, starts the ConnectedThread
  400. */
  401. public void run()
  402. {
  403. Log.d("ARG", "ConnectedThreadRun!");
  404. byte[] buffer = new byte[1024];
  405. int bytes;
  406. while (true)
  407. {
  408. try
  409. {
  410. bytes = mInputStream.read(buffer);
  411. //handler stuff? send to activity?
  412. mHandler.obtainMessage(SlaveActivity.MESSAGE_READ, bytes, -1, buffer).sendToTarget();
  413. Log.d("Herro!", "obtainedMessage!");
  414. }
  415. catch (IOException e)
  416. {
  417. Log.d("ARG", "going to run connectionLost()");
  418. connectionLost();
  419. BluetoothCommunicationService.this.start();
  420. break;
  421. }
  422. }
  423. }
  424. /**
  425. * Write to the external Bluetooth device
  426. * @param buffer the byte[] to send via Bluetooth
  427. */
  428. public void write(byte[] buffer)
  429. {
  430. try
  431. {
  432. mOutputStream.write(buffer);
  433. //handler stuff? send to activity?
  434. }
  435. catch (IOException e)
  436. {
  437. //handle failure to write data
  438. }
  439. Log.d("ARG", "ConnectedThread write()");
  440. }
  441. /**
  442. * Close the socket and stop the thread
  443. */
  444. public void cancel()
  445. {
  446. try
  447. {
  448. mSocket.close();
  449. }
  450. catch (IOException e)
  451. {
  452. //handle failure to close socket
  453. }
  454. }
  455. }
  456. }