package de.tudarmstadt.informatik.hostage.sync; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.UUID; import android.util.Log; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothServerSocket; import android.bluetooth.BluetoothSocket; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; import android.widget.AdapterView.OnItemClickListener; import de.tudarmstadt.informatik.hostage.R; import de.tudarmstadt.informatik.hostage.persistence.HostageDBOpenHelper; public class BluetoothSync extends Activity{ private static final int CONNECTION_ESTABLISHED = 0x0; private static final int CONNECTION_FAILED = 0x1; private static final int MESSAGE_SENT = 0x2; private static final int MESSAGE_RECIEVED = 0x3; private UUID serviceUUID; private BluetoothAdapter mBluetoothAdapter; private ArrayAdapter arrayAdapter; private ServerThread serverThread; private ClientThread clientThread; CommunicationThread commThread; TextView mInfoText; ListView listView; LinearLayout layout; @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_bluetooth); serviceUUID = UUID.fromString(getResources().getString(R.string.UUID)); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); arrayAdapter = new ArrayAdapter(this, R.layout.list_view_bluetooth_devices); setLayoutElement(); registerBroadcastReceiver(); if (mBluetoothAdapter == null) { // Device does not support Bluetooth mInfoText.setText("Bluetooth is not available on this device."); } else if (!mBluetoothAdapter.isEnabled()) { mInfoText.setText("Enable Bluetooth before synchronizing."); Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivity(enableBtIntent); } else { startConnectionListener(); chooseDevice(); } } @Override public void onDestroy(){ super.onDestroy(); if(mRecieverRegistered){ unregisterBroadcastReceiver(); } if(commThread != null) { commThread.cancel(); } if(clientThread != null){ clientThread.cancel(); } if(serverThread != null){ serverThread.cancel(); } } private void chooseDevice(){ arrayAdapter.clear(); if (!mBluetoothAdapter.startDiscovery()) return; mInfoText.setText("Choose Device for synchronizing:\n"); layout.addView(listView); setContentView(layout); } private void startConnectionListener() { Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); startActivity(discoverableIntent); serverThread = new ServerThread(); serverThread.start(); } private void manageConnectedSocket(BluetoothSocket socket) { mBluetoothAdapter.cancelDiscovery(); unregisterBroadcastReceiver(); commThread = new CommunicationThread(socket); commThread.start(); HostageDBOpenHelper dbh = new HostageDBOpenHelper(this); ArrayList> localNetworkInformation = dbh.getNetworkInformation(); commThread.write(localNetworkInformation); } private class ClientThread extends Thread { private final BluetoothSocket socket; public ClientThread(BluetoothDevice device) { BluetoothSocket tmp = null; try { tmp = device.createRfcommSocketToServiceRecord(serviceUUID); } catch (IOException e) { } socket = tmp; } /** Will cancel an in-progress connection, and close the socket */ public void cancel() { try { socket.close(); } catch (IOException e) { } } @Override public void run() { try { socket.connect(); } catch (IOException connectException) { mHandler.obtainMessage(CONNECTION_FAILED).sendToTarget(); // Unable to connect; close the socket and get out try { socket.close(); } catch (IOException closeException) { } return; } mHandler.obtainMessage(CONNECTION_ESTABLISHED, socket).sendToTarget(); manageConnectedSocket(socket); } } private class ServerThread extends Thread { private final BluetoothServerSocket serverSocket; public ServerThread() { BluetoothServerSocket tmp = null; try { tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(getResources().getString(R.string.app_name), serviceUUID); } catch (IOException e) { } serverSocket = tmp; } /** Will cancel the listening socket, and cause the thread to finish */ public void cancel() { try { serverSocket.close(); } catch (IOException e) { } } @Override public void run() { BluetoothSocket socket = null; while (true) { try { socket = serverSocket.accept(); } catch (IOException e) { e.printStackTrace(); mHandler.obtainMessage(CONNECTION_FAILED).sendToTarget(); break; } if (socket != null) { // Do work to manage the connection (in a separate thread) manageConnectedSocket(socket); mHandler.obtainMessage(CONNECTION_ESTABLISHED, socket).sendToTarget(); try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } break; } } } } private class CommunicationThread extends Thread { private final BluetoothSocket mmSocket; private final ObjectInputStream objectInput; private final ObjectOutputStream objectOuput; public CommunicationThread(BluetoothSocket socket) { mmSocket = socket; ObjectInputStream tmpIn = null; ObjectOutputStream tmpOut = null; // Get the input and output streams, using temp objects because // member streams are final try { tmpOut = new ObjectOutputStream(socket.getOutputStream()); tmpIn = new ObjectInputStream(socket.getInputStream()); } catch (IOException e) { e.printStackTrace(); } objectInput = tmpIn; objectOuput = tmpOut; } /* Call this from the main activity to shutdown the connection */ public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } @Override public void run() { // Keep listening to the InputStream until an exception occurs while (true) { try { // TODO Ersetze dbh mit Logger HostageDBOpenHelper dbh = new HostageDBOpenHelper(getContext()); // Read from the InputStream ArrayList> remoteNetworkInformation = (ArrayList>) objectInput.readObject(); // update database dbh.updateNetworkInformation(remoteNetworkInformation); mHandler.obtainMessage(MESSAGE_RECIEVED).sendToTarget(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); break; } } } /* Call this from the main activity to send data to the remote device */ public void write(ArrayList> networkInformation) { try { objectOuput.writeObject(networkInformation); mHandler.obtainMessage(MESSAGE_SENT).sendToTarget(); } catch (IOException e) { e.printStackTrace(); } } } // Create a BroadcastReceiver for ACTION_FOUND private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // When discovery finds a device if (BluetoothDevice.ACTION_FOUND.equals(action)) { // Get the BluetoothDevice object from the Intent BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // Add the name and address to an array adapter to show in a ListView arrayAdapter.add(device.getName() + "\n" + device.getAddress()); arrayAdapter.notifyDataSetChanged(); }else if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)){ int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1); Log.i("BluetoothSync", state + ""); if(state == BluetoothAdapter.STATE_ON){ startConnectionListener(); chooseDevice(); }else if(state == BluetoothAdapter.STATE_OFF || state == BluetoothAdapter.STATE_TURNING_OFF){ mInfoText.setText("Enable Bluetooth before synchronizing."); layout.removeView(listView); } } } }; private boolean mRecieverRegistered = false; // Register the BroadcastReceiver private void registerBroadcastReceiver() { IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); filter.addAction(BluetoothAdapter. ACTION_STATE_CHANGED); registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy mRecieverRegistered = true; } private void unregisterBroadcastReceiver(){ unregisterReceiver(mReceiver); mRecieverRegistered = false; } private Context getContext(){ return this; } private void setLayoutElement(){ mInfoText = (TextView) findViewById(R.id.bluetoothInfoText); layout = (LinearLayout) findViewById(R.id.bluetoothLayout); listView = new ListView(this); listView.setAdapter(arrayAdapter); listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { String deviceInfo = arrayAdapter.getItem(position); String mac = deviceInfo.substring(deviceInfo.indexOf("\n") + 1); clientThread = new ClientThread(mBluetoothAdapter.getRemoteDevice(mac)); clientThread.start(); } }); } private boolean message_sent = false; private boolean message_recieved = false; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch(msg.what){ case CONNECTION_ESTABLISHED: layout.removeView(listView); BluetoothSocket socket = (BluetoothSocket) msg.obj; String deviceName = socket.getRemoteDevice().getName(); mInfoText.setText("Synchronizing with " + deviceName + "..."); break; case CONNECTION_FAILED: mInfoText.setText("Synchronization failed!"); break; case MESSAGE_SENT: message_sent = true; if(message_recieved) mInfoText.setText("Synchronization successfull!"); break; case MESSAGE_RECIEVED: message_recieved = true; if(message_sent) mInfoText.setText("Synchronization successfull!"); break; } } }; }