BluetoothSyncActivity.java 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. package de.tudarmstadt.informatik.hostage.sync.bluetooth;
  2. import java.util.UUID;
  3. import android.app.Activity;
  4. import android.bluetooth.BluetoothAdapter;
  5. import android.bluetooth.BluetoothDevice;
  6. import android.bluetooth.BluetoothSocket;
  7. import android.content.BroadcastReceiver;
  8. import android.content.Context;
  9. import android.content.Intent;
  10. import android.content.IntentFilter;
  11. import android.os.Bundle;
  12. import android.os.Handler;
  13. import android.os.Message;
  14. import android.view.View;
  15. import android.widget.AdapterView;
  16. import android.widget.ArrayAdapter;
  17. import android.widget.ListView;
  18. import android.widget.TextView;
  19. import android.widget.AdapterView.OnItemClickListener;
  20. import de.tudarmstadt.informatik.hostage.R;
  21. /**
  22. * Activity that allows the user to choose a bluetooth device to
  23. * synchronize with and informs about the status of the synchronization.
  24. *
  25. * @author Lars Pandikow
  26. */
  27. public class BluetoothSyncActivity extends Activity{
  28. public static final int CONNECTING = 0x0;
  29. public static final int CONNECTION_ESTABLISHED = 0x1;
  30. public static final int CONNECTION_FAILED = 0x2;
  31. public static final int SYNC_SUCCESSFUL = 0x3;
  32. public static final int SYNC_FAILED = 0x4;
  33. public static UUID serviceUUID;
  34. private BluetoothAdapter mBluetoothAdapter;
  35. private ArrayAdapter<String> arrayAdapter;
  36. private ServerThread serverThread;
  37. private ClientThread clientThread;
  38. private CommunicationThread commThread;
  39. private TextView mInfoText;
  40. private ListView listView;
  41. @Override
  42. public void onCreate(Bundle savedInstanceState){
  43. super.onCreate(savedInstanceState);
  44. setContentView(R.layout.activity_bluetooth);
  45. serviceUUID = UUID.fromString(getResources().getString(R.string.UUID));
  46. mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  47. arrayAdapter = new ArrayAdapter<String>(this, R.layout.list_view_bluetooth_devices);
  48. setLayoutElement();
  49. registerBroadcastReceiver();
  50. if(savedInstanceState != null){
  51. CharSequence text = savedInstanceState.getCharSequence("mInfoText");
  52. mInfoText.setText(text);
  53. String[] data = savedInstanceState.getStringArray("adapter");
  54. if(data != null){
  55. for(int i = 0; i < data.length; i++){
  56. arrayAdapter.add(data[i]);
  57. arrayAdapter.notifyDataSetChanged();
  58. }
  59. }
  60. if(savedInstanceState.getBoolean("listView")){
  61. listView.setVisibility(View.VISIBLE);
  62. }else{
  63. listView.setVisibility(View.GONE);
  64. }
  65. }
  66. if (mBluetoothAdapter == null) {
  67. // Device does not support Bluetooth
  68. mInfoText.setText("Bluetooth is not available on this device.");
  69. }
  70. else if (!mBluetoothAdapter.isEnabled()) {
  71. mInfoText.setText("Enable Bluetooth before synchronizing.");
  72. Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
  73. startActivity(enableBtIntent);
  74. } else if(savedInstanceState == null){
  75. startConnectionListener();
  76. chooseDevice();
  77. }
  78. }
  79. @Override
  80. public void onDestroy(){
  81. super.onDestroy();
  82. if(mRecieverRegistered){
  83. unregisterBroadcastReceiver();
  84. }
  85. cancelThreads();
  86. }
  87. @Override
  88. protected void onSaveInstanceState(Bundle outState){
  89. String[] data = new String[arrayAdapter.getCount()];
  90. for(int i = 0; i < arrayAdapter.getCount(); i++){
  91. data[i] = arrayAdapter.getItem(i);
  92. }
  93. outState.putStringArray("adapter", data);
  94. outState.putCharSequence("mInfoText", mInfoText.getText());
  95. outState.putBoolean("listView", listView.isShown());
  96. super.onSaveInstanceState(outState);
  97. }
  98. /**
  99. * Starts discovery of bluetooth devices.
  100. */
  101. private void chooseDevice(){
  102. if (!mBluetoothAdapter.startDiscovery())
  103. return;
  104. mInfoText.setText("Choose Device for synchronizing:\n");
  105. listView.setVisibility(View.VISIBLE);
  106. }
  107. /**
  108. * Start a ServerThread to listen for incoming connections
  109. * @see ServerThread
  110. */
  111. private void startConnectionListener() {
  112. if(mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE){
  113. Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
  114. discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
  115. startActivity(discoverableIntent);
  116. }
  117. serverThread = new ServerThread(mHandler, getResources().getString(R.string.app_name));
  118. serverThread.start();
  119. }
  120. /**
  121. * Called when a connection has been established.
  122. * Starts a {@link CommunicationThread} for communication.
  123. * @param socket The socket of the connection.
  124. */
  125. protected void manageConnectedSocket(BluetoothSocket socket) {
  126. mBluetoothAdapter.cancelDiscovery();
  127. unregisterBroadcastReceiver();
  128. listView.setVisibility(View.GONE);
  129. String deviceName = socket.getRemoteDevice().getName();
  130. mInfoText.setText("Synchronizing with " + deviceName + "...");
  131. commThread = new CommunicationThread(this, socket, mHandler);
  132. commThread.start();
  133. }
  134. /**
  135. * BroadcastReciever listens for state changes of bluetooth and discovery of new devices.
  136. */
  137. private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
  138. @Override
  139. public void onReceive(Context context, Intent intent) {
  140. String action = intent.getAction();
  141. // When discovery finds a device
  142. if (BluetoothDevice.ACTION_FOUND.equals(action)) {
  143. // Get the BluetoothDevice object from the Intent
  144. BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
  145. // Add the name and address to an array adapter to show in a ListView
  146. arrayAdapter.add(device.getName() + "\n" + device.getAddress());
  147. arrayAdapter.notifyDataSetChanged();
  148. }else if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)){
  149. int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
  150. if(state == BluetoothAdapter.STATE_ON){
  151. startConnectionListener();
  152. chooseDevice();
  153. }else if(state == BluetoothAdapter.STATE_OFF || state == BluetoothAdapter.STATE_TURNING_OFF){
  154. mInfoText.setText("Enable Bluetooth before synchronizing.");
  155. listView.setVisibility(View.GONE);
  156. }
  157. }
  158. }
  159. };
  160. private boolean mRecieverRegistered = false;
  161. /**
  162. * Register the BroadcastReceiver
  163. */
  164. private void registerBroadcastReceiver() {
  165. IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
  166. filter.addAction(BluetoothAdapter. ACTION_STATE_CHANGED);
  167. registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
  168. mRecieverRegistered = true;
  169. }
  170. /**
  171. * Unregister the BroadcastReceiver
  172. */
  173. private void unregisterBroadcastReceiver(){
  174. unregisterReceiver(mReceiver);
  175. mRecieverRegistered = false;
  176. }
  177. /**
  178. * Creates the list of bluetooth devices.
  179. * Starts a {@link ClientThread} to establish connection when a device is clicked.
  180. */
  181. private void setLayoutElement(){
  182. mInfoText = (TextView) findViewById(R.id.bluetoothInfoText);
  183. listView = (ListView) findViewById(R.id.bluetoothListView);
  184. listView.setAdapter(arrayAdapter);
  185. listView.setOnItemClickListener(new OnItemClickListener() {
  186. @Override
  187. public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
  188. String deviceInfo = arrayAdapter.getItem(position);
  189. String mac = deviceInfo.substring(deviceInfo.indexOf("\n") + 1);
  190. String name = deviceInfo.substring(0, deviceInfo.indexOf("\n"));
  191. mHandler.obtainMessage(CONNECTING, name).sendToTarget();
  192. clientThread = new ClientThread(mBluetoothAdapter.getRemoteDevice(mac), mHandler);
  193. clientThread.start();
  194. }
  195. });
  196. }
  197. private void cancelThreads(){
  198. if(commThread != null) {
  199. commThread.cancel();
  200. }
  201. if(clientThread != null){
  202. clientThread.cancel();
  203. }
  204. if(serverThread != null){
  205. serverThread.cancel();
  206. }
  207. }
  208. /**
  209. * Handles message sent from the background threads and updates UI.
  210. */
  211. private Handler mHandler = new Handler() {
  212. @Override
  213. public void handleMessage(Message msg) {
  214. switch(msg.what){
  215. case CONNECTING:
  216. listView.setVisibility(View.GONE);
  217. mInfoText.setText("Connecting to " + (String)msg.obj + "!");
  218. break;
  219. case CONNECTION_ESTABLISHED:
  220. BluetoothSocket socket = (BluetoothSocket) msg.obj;
  221. manageConnectedSocket(socket);
  222. break;
  223. case CONNECTION_FAILED:
  224. mInfoText.setText("Failed to connect to device!");
  225. break;
  226. case SYNC_SUCCESSFUL:
  227. mInfoText.setText("Synchronization successfull!");
  228. break;
  229. case SYNC_FAILED:
  230. commThread.cancel();
  231. mInfoText.setText("Synchronization failed!");
  232. break;
  233. }
  234. }
  235. };
  236. }