Browse Source

Initial commit for Bluetooth related projects.

Cristian Tanas 11 năm trước cách đây
mục cha
commit
aef3d4a197
36 tập tin đã thay đổi với 1173 bổ sung0 xóa
  1. 33 0
      BluetoothConnect/AndroidManifest.xml
  2. BIN
      BluetoothConnect/ic_launcher-web.png
  3. BIN
      BluetoothConnect/libs/android-support-v4.jar
  4. BIN
      BluetoothConnect/res/drawable-hdpi/ic_launcher.png
  5. BIN
      BluetoothConnect/res/drawable-mdpi/ic_launcher.png
  6. BIN
      BluetoothConnect/res/drawable-xhdpi/ic_launcher.png
  7. BIN
      BluetoothConnect/res/drawable-xxhdpi/ic_launcher.png
  8. 47 0
      BluetoothConnect/res/layout/activity_main.xml
  9. 11 0
      BluetoothConnect/res/layout/list_footerview.xml
  10. 9 0
      BluetoothConnect/res/layout/list_item.xml
  11. 11 0
      BluetoothConnect/res/values-v11/styles.xml
  12. 12 0
      BluetoothConnect/res/values-v14/styles.xml
  13. 16 0
      BluetoothConnect/res/values/strings.xml
  14. 20 0
      BluetoothConnect/res/values/styles.xml
  15. 93 0
      BluetoothConnect/src/org/uab/android/bluetooth/connect/BluetoothAcceptConnectionThread.java
  16. 87 0
      BluetoothConnect/src/org/uab/android/bluetooth/connect/BluetoothConnectThread.java
  17. 87 0
      BluetoothConnect/src/org/uab/android/bluetooth/connect/BluetoothManageConnectionThread.java
  18. 133 0
      BluetoothConnect/src/org/uab/android/bluetooth/connect/BluetoothNeighboursListActivity.java
  19. 16 0
      BluetoothConnect/src/org/uab/android/bluetooth/connect/ConnectionInfo.java
  20. 241 0
      BluetoothConnect/src/org/uab/android/bluetooth/connect/MainActivity.java
  21. 33 0
      BluetoothNeighbourDiscovery/AndroidManifest.xml
  22. BIN
      BluetoothNeighbourDiscovery/ic_launcher-web.png
  23. BIN
      BluetoothNeighbourDiscovery/libs/android-support-v4.jar
  24. BIN
      BluetoothNeighbourDiscovery/res/drawable-hdpi/ic_launcher.png
  25. BIN
      BluetoothNeighbourDiscovery/res/drawable-mdpi/ic_launcher.png
  26. BIN
      BluetoothNeighbourDiscovery/res/drawable-xhdpi/ic_launcher.png
  27. BIN
      BluetoothNeighbourDiscovery/res/drawable-xxhdpi/ic_launcher.png
  28. 17 0
      BluetoothNeighbourDiscovery/res/layout/activity_main.xml
  29. 11 0
      BluetoothNeighbourDiscovery/res/layout/list_footerview.xml
  30. 9 0
      BluetoothNeighbourDiscovery/res/layout/list_item.xml
  31. 11 0
      BluetoothNeighbourDiscovery/res/values-v11/styles.xml
  32. 12 0
      BluetoothNeighbourDiscovery/res/values-v14/styles.xml
  33. 9 0
      BluetoothNeighbourDiscovery/res/values/strings.xml
  34. 20 0
      BluetoothNeighbourDiscovery/res/values/styles.xml
  35. 133 0
      BluetoothNeighbourDiscovery/src/org/uab/android/bluetooth/simple/BluetoothNeighboursListActivity.java
  36. 102 0
      BluetoothNeighbourDiscovery/src/org/uab/android/bluetooth/simple/MainActivity.java

+ 33 - 0
BluetoothConnect/AndroidManifest.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="org.uab.android.bluetooth.connect"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="14"
+        android:targetSdkVersion="19" />
+    
+    <uses-permission android:name="android.permission.BLUETOOTH"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity 
+            android:name=".BluetoothNeighboursListActivity"
+            android:label="@string/app_name"/>
+    </application>
+
+</manifest>

BIN
BluetoothConnect/ic_launcher-web.png


BIN
BluetoothConnect/libs/android-support-v4.jar


BIN
BluetoothConnect/res/drawable-hdpi/ic_launcher.png


BIN
BluetoothConnect/res/drawable-mdpi/ic_launcher.png


BIN
BluetoothConnect/res/drawable-xhdpi/ic_launcher.png


BIN
BluetoothConnect/res/drawable-xxhdpi/ic_launcher.png


+ 47 - 0
BluetoothConnect/res/layout/activity_main.xml

@@ -0,0 +1,47 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="${relativePackage}.${activityClass}" >
+
+    <Button
+        android:id="@+id/deviceDiscoveryBt"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentRight="true"
+        android:text="@string/discover"
+        android:enabled="false" />
+
+    <ProgressBar
+        android:id="@+id/progressBar"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentRight="true"
+        android:layout_alignParentTop="true"
+        android:indeterminate="true"
+        android:visibility="invisible" />
+
+    <TextView
+        android:id="@+id/statusTv"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBottom="@+id/progressBar"
+        android:layout_alignParentLeft="true"
+        android:layout_toLeftOf="@+id/progressBar"
+        android:layout_marginLeft="10dp"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
+
+    <TextView
+        android:id="@+id/bluetoothDataTv"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignLeft="@+id/statusTv"
+        android:layout_alignParentRight="true"
+        android:layout_below="@+id/statusTv"
+        android:layout_marginLeft="15dp"
+        android:layout_marginTop="136dp"
+        android:textAppearance="?android:attr/textAppearanceLarge" />
+
+</RelativeLayout>

+ 11 - 0
BluetoothConnect/res/layout/list_footerview.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/footer"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center_horizontal"
+    android:text="@string/discoverFooterView"
+    android:textSize="20sp" >
+    
+
+</TextView>

+ 9 - 0
BluetoothConnect/res/layout/list_item.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:padding="10dp"
+    android:textSize="24sp" >
+    
+
+</TextView>

+ 11 - 0
BluetoothConnect/res/values-v11/styles.xml

@@ -0,0 +1,11 @@
+<resources>
+
+    <!--
+        Base application theme for API 11+. This theme completely replaces
+        AppBaseTheme from res/values/styles.xml on API 11+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+        <!-- API 11 theme customizations can go here. -->
+    </style>
+
+</resources>

+ 12 - 0
BluetoothConnect/res/values-v14/styles.xml

@@ -0,0 +1,12 @@
+<resources>
+
+    <!--
+        Base application theme for API 14+. This theme completely replaces
+        AppBaseTheme from BOTH res/values/styles.xml and
+        res/values-v11/styles.xml on API 14+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+        <!-- API 14 theme customizations can go here. -->
+    </style>
+
+</resources>

+ 16 - 0
BluetoothConnect/res/values/strings.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <string name="app_name">BluetoothConnect</string>
+    <string name="hello_world">Hello world!</string>
+    <string name="discover">Device discovery</string>
+    <string name="discoverFooterView">Discover more devices</string>
+    <string name="clientMode">Connected in CLIENT mode.</string>
+    <string name="serverMode">Connected in SERVER mode.</string>
+    <string name="connecting">Connecting to remote Bluetooth device...</string>
+    <string name="connected">Connected to remote Bluetooth device.</string>
+    <string name="bluetoothError">Bluetooth error! See below.</string>
+    <string name="echoMessage">Hello, Bluetooth!</string>
+    <string name="appInfo">To enter SERVER mode press and hold the Device discovery button!</string>
+
+</resources>

+ 20 - 0
BluetoothConnect/res/values/styles.xml

@@ -0,0 +1,20 @@
+<resources>
+
+    <!--
+        Base application theme, dependent on API level. This theme is replaced
+        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Light">
+        <!--
+            Theme customizations available in newer API levels can go in
+            res/values-vXX/styles.xml, while customizations related to
+            backward-compatibility can go here.
+        -->
+    </style>
+
+    <!-- Application theme. -->
+    <style name="AppTheme" parent="AppBaseTheme">
+        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+    </style>
+
+</resources>

+ 93 - 0
BluetoothConnect/src/org/uab/android/bluetooth/connect/BluetoothAcceptConnectionThread.java

@@ -0,0 +1,93 @@
+package org.uab.android.bluetooth.connect;
+
+import java.io.IOException;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothServerSocket;
+import android.bluetooth.BluetoothSocket;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+public class BluetoothAcceptConnectionThread extends Thread {
+	
+	// Socket for listening incoming connection requests
+	BluetoothServerSocket 	serverSocket;
+	
+	// Reference to the local Bluetooth adapter
+	BluetoothAdapter		bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+	
+	// Handler object to communicate results back to the MainActivity
+	Handler					handler;
+	
+	public BluetoothAcceptConnectionThread(Handler handler) {
+		
+		this.handler = handler;
+		
+		// Get a BluetoothServerSocket
+		try {
+			
+			this.serverSocket = this.bluetoothAdapter
+					.listenUsingRfcommWithServiceRecord(
+							"Bluetooth Demo", 					// An arbitrary name (could be the application name).
+							ConnectionInfo.BLUETOOTH_APP_UUID	// UUID for the Bluetooth service
+							);
+		} catch (IOException e) { 
+			Message msg = this.handler.obtainMessage(MainActivity.BLUETOOTH_ERROR, e.getMessage());
+			this.handler.sendMessage(msg);
+		}
+	}
+
+	@Override
+	public void run() {
+		
+		BluetoothSocket clientSocket;
+		
+		// Start listening for connection requests
+		while ( true ) {
+			
+			// This is a blocking call and it only returns when either a connection has been accepted 
+			// or an exception has occurred.
+			try {
+				clientSocket = serverSocket.accept();
+			} catch (IOException e) {
+				break;
+			}
+			
+			// If the connection has been accepted
+			if ( clientSocket != null ) {
+				
+				// Manage the connection in a separate Thread
+				manageConnectedSocket(clientSocket);
+				
+				// Close the BluetoothServerSocket as typically only one connection is allows per RFCOMM channel
+				try {
+					serverSocket.close();
+				} catch (IOException e) {
+					Log.e("BLUETOOTH_CONNECT", e.getMessage());
+				}
+				
+				break;
+			}
+		}
+	}
+	
+	/**
+	 * Initiates a Thread for transferring data.
+	 * 
+	 * @param socket BluetoothSocket for which the connection has been accepted.
+	 */
+	private void manageConnectedSocket(BluetoothSocket socket) {
+		
+		BluetoothManageConnectionThread connectionThread = 
+				new BluetoothManageConnectionThread(
+						socket, 								// Incoming BluetoothSocket
+						this.handler									// Handler object to communicate results back to the main Thread
+						);
+		
+		Message msg = this.handler.obtainMessage(MainActivity.BLUETOOTH_SOCKET_CONNECTED, connectionThread);
+		this.handler.sendMessage(msg);
+		
+		connectionThread.start();
+	}
+}

+ 87 - 0
BluetoothConnect/src/org/uab/android/bluetooth/connect/BluetoothConnectThread.java

@@ -0,0 +1,87 @@
+package org.uab.android.bluetooth.connect;
+
+import java.io.IOException;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothSocket;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+public class BluetoothConnectThread extends Thread {
+	
+	// Bluetooth device to connect to
+	BluetoothDevice		connectToDevice;
+	
+	// Bluetooth socket for the remote bluetooth connection
+	BluetoothSocket		remoteBluetoothSocket;
+	
+	// UI Thread handler to communicate back connection results
+	Handler				handler;
+	
+	public BluetoothConnectThread(BluetoothDevice device, Handler handler) {
+		
+		this.connectToDevice = device;
+		this.handler = handler;
+		
+		// Initialize the BluetoothSocket that will connect to the BluetoothDevice
+		try {
+			this.remoteBluetoothSocket = this.connectToDevice
+					.createRfcommSocketToServiceRecord(
+							ConnectionInfo.BLUETOOTH_APP_UUID	// Service record UUID to search a RFCOMM channel
+							);
+		} catch (IOException e) {
+			
+			Message msg = this.handler.obtainMessage(MainActivity.BLUETOOTH_ERROR, e.getMessage());
+			this.handler.sendMessage(msg);
+		}
+	}
+
+	@Override
+	public void run() {
+		
+		// Make sure to stop the neighbour discovery before connecting to a device
+		if ( BluetoothAdapter.getDefaultAdapter().isDiscovering() )
+			BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
+		
+		// Connect to the Bluetooth device
+		try {
+			this.remoteBluetoothSocket.connect();	// This performs an SDP lookup on the remote device in order to match the UUID.
+		} catch (IOException e) {
+			
+			try { 
+				this.remoteBluetoothSocket.close(); 
+			} catch (IOException closeException) {
+				Log.e("BLUETOOTH_CONNECT", closeException.getMessage());
+			}
+			
+			Message msg = this.handler.obtainMessage(MainActivity.BLUETOOTH_ERROR, e.getMessage());
+			this.handler.sendMessage(msg);
+		}
+		
+		// Manage the connected socket in a separate Thread
+		manageConnectedSocket(this.remoteBluetoothSocket);
+	}
+	
+	/**
+	 * Initiates a Thread for transferring data.
+	 * 
+	 * @param socket BluetoothSocket for which the connection has been accepted.
+	 */
+	private void manageConnectedSocket(BluetoothSocket socket) {
+		
+		// Send a Message back to MainActivity informing that the socket has been connected 
+		// and pass in a reference to the connection Thread
+		BluetoothManageConnectionThread connectionThread = 
+				new BluetoothManageConnectionThread(
+						socket,
+						this.handler
+						);
+
+		Message msg = this.handler.obtainMessage(MainActivity.BLUETOOTH_SOCKET_CONNECTED, connectionThread);
+		this.handler.sendMessage(msg);
+
+		connectionThread.start();
+	}
+}

+ 87 - 0
BluetoothConnect/src/org/uab/android/bluetooth/connect/BluetoothManageConnectionThread.java

@@ -0,0 +1,87 @@
+package org.uab.android.bluetooth.connect;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import android.bluetooth.BluetoothSocket;
+import android.os.Handler;
+import android.os.Message;
+
+public class BluetoothManageConnectionThread extends Thread {
+
+	// Connected BluetoothSocket
+	BluetoothSocket bluetoothSocket;
+	
+	// Handler object to communicate results back to the main Thread
+	Handler			handler;
+	
+	// Stream objects to handle transmissions through the socket
+	InputStream 	socketInputStream;
+	OutputStream	socketOutputStream;
+	
+	public BluetoothManageConnectionThread(BluetoothSocket socket, Handler handler) {
+		
+		this.bluetoothSocket = socket;
+		this.handler = handler;
+		
+		// Initialize the InputStream and OutputStream to read and write data through the socket
+		try {
+			this.socketInputStream = this.bluetoothSocket.getInputStream();
+			this.socketOutputStream = this.bluetoothSocket.getOutputStream();
+		} catch(IOException e) {
+			
+			Message msg = this.handler.obtainMessage(MainActivity.BLUETOOTH_ERROR, e.getMessage());
+			this.handler.sendMessage(msg);
+		}
+	}
+	
+	@Override
+	public void run() {
+		
+		Message msg;
+		
+		// Buffer store for the stream
+		byte[] inputBuffer = new byte[1024];
+		
+		// Bytes read from the stream
+		int bytesRead;
+		
+		// Read from the InputStream. This call will block until there is something to read from the stream.
+		while ( true ) {
+			
+			try {
+				
+				bytesRead = socketInputStream.read(inputBuffer);
+				
+				// Send the obtained data back to the UI Thread
+				String stringData = new String(inputBuffer, 0, bytesRead);
+				msg = this.handler.obtainMessage(MainActivity.BLUETOOTH_DATA_RECEIVED, stringData);
+				this.handler.sendMessage(msg);
+				
+			} catch (IOException e) {
+				
+				msg = this.handler.obtainMessage(MainActivity.BLUETOOTH_ERROR, e.getMessage());
+				this.handler.sendMessage(msg);
+				break;
+			}
+		}
+	}
+	
+	/**
+	 * Sends data to the remote device.
+	 * 
+	 * @param bytesToWrite Bytes to send to the remote device.
+	 */
+	public void writeToSocket(byte[] bytesToWrite) {
+		
+		try {
+			
+			this.socketOutputStream.write(bytesToWrite);
+			
+		} catch (IOException e) {
+			Message msg = this.handler.obtainMessage(MainActivity.BLUETOOTH_ERROR, e.getMessage());
+			this.handler.sendMessage(msg);
+		}
+	}
+}

+ 133 - 0
BluetoothConnect/src/org/uab/android/bluetooth/connect/BluetoothNeighboursListActivity.java

@@ -0,0 +1,133 @@
+package org.uab.android.bluetooth.connect;
+
+import java.util.ArrayList;
+
+import android.app.ListActivity;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+public class BluetoothNeighboursListActivity extends ListActivity {
+
+	static final String EXTRA_DEVICES = "EXTRA_DEVICES";
+	
+	BluetoothAdapter		bluetoothAdapter;
+	
+	ListView				neighboursListView;
+	ArrayAdapter<String> 	neighboursListAdapter;
+	
+	public static Intent getCallingIntent(Context context, ArrayList<String> devices) {
+		
+		Intent listNeighboursIntent = new Intent(context, BluetoothNeighboursListActivity.class);
+		listNeighboursIntent.putStringArrayListExtra(EXTRA_DEVICES, devices);
+		return listNeighboursIntent;
+	}
+	
+	@Override
+	protected void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		
+		// Get a reference to the default BluetoothAdapter
+		bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+		
+		// Get a reference to the ListView
+		neighboursListView = getListView();
+		
+		// Create a FooterView for the ListView
+		LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+		View footerView = layoutInflater.inflate(R.layout.list_footerview, neighboursListView, false);
+		
+		neighboursListView.setFooterDividersEnabled(true);
+		
+		// Add the FooterView to the list
+		neighboursListView.addFooterView(footerView, null, true);
+		
+		// Get the list of paired devices already discovered
+		ArrayList<String> pairedDevices = getIntent().getStringArrayListExtra(EXTRA_DEVICES);
+		
+		// Initialize the list's ArrayAdapter
+		neighboursListAdapter = new ArrayAdapter<String>(
+				this, 						// Context
+				R.layout.list_item, 		// View for the list items
+				pairedDevices				// Data objects
+				);
+		neighboursListView.setAdapter(neighboursListAdapter);
+		
+		// Set the ListView OnItemClickListener
+		neighboursListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+
+			@Override
+			public void onItemClick(AdapterView<?> parent, View view, int position,
+					long id) {
+				
+				// If the user clicked on the ListView's footer start discovering neighbours
+				if ( parent.getAdapter().getItemViewType(position) == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER ) {
+					
+					bluetoothAdapter.startDiscovery();
+				}
+				else {
+					
+					// Cancel neighbours discovery
+					bluetoothAdapter.cancelDiscovery();
+					
+					// Get the device's MAC Address
+					String selectedDevice = (String) parent.getItemAtPosition(position);
+					String macAddress = selectedDevice.split("\n")[1];
+					
+					BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(macAddress);
+					
+					// Create an Intent to return the selected bluetooth device to the calling Activity
+					Intent dataIntent = new Intent();
+					dataIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, bluetoothDevice);
+					setResult(RESULT_OK, dataIntent);
+					finish();
+				}
+				
+			}
+		});
+	}
+	
+	@Override
+	protected void onResume() {
+		super.onResume();
+		
+		// Register a BroadcastReceiver for new devices discovery
+		IntentFilter discoveryFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
+		registerReceiver(neighboursDiscoveryReceiver, discoveryFilter);
+	}
+	
+	@Override
+	protected void onPause() {
+		super.onPause();
+		
+		bluetoothAdapter.cancelDiscovery();
+		unregisterReceiver(neighboursDiscoveryReceiver);
+	}
+	
+	
+	BroadcastReceiver neighboursDiscoveryReceiver = new BroadcastReceiver() {
+		
+		@Override
+		public void onReceive(Context context, Intent intent) {
+			
+			// A new Bluetooth device has been found
+			if ( intent.getAction().equals(BluetoothDevice.ACTION_FOUND) ) {
+				
+				BluetoothDevice device = intent
+						.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+				neighboursListAdapter.add(device.getName() + "\n" + device.getAddress());
+				neighboursListAdapter.notifyDataSetChanged();
+			}
+			
+		}
+	};
+}

+ 16 - 0
BluetoothConnect/src/org/uab/android/bluetooth/connect/ConnectionInfo.java

@@ -0,0 +1,16 @@
+package org.uab.android.bluetooth.connect;
+
+import java.util.UUID;
+
+public class ConnectionInfo {
+
+	// An identifiable name for the Bluetooth service.
+	// When a client attempts to connect with a Bluetooth device, it will 
+	// carry a UUID that uniquely identifies the service with which it wants 
+	// to connect. The UUID from the client must match the stored UUID in the 
+	// server for the connection to be accepted.
+	//
+	// More on UUID: http://en.wikipedia.org/wiki/Universally_unique_identifier
+	public static UUID BLUETOOTH_APP_UUID = 
+			UUID.fromString("66702e86-c33e-4d47-9b55-7f7ea66c704a");
+}

+ 241 - 0
BluetoothConnect/src/org/uab/android/bluetooth/connect/MainActivity.java

@@ -0,0 +1,241 @@
+package org.uab.android.bluetooth.connect;
+
+import java.util.ArrayList;
+import java.util.Set;
+
+import android.app.Activity;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class MainActivity extends Activity {
+	
+	// Bluetooth Message IDs
+	public static final int BLUETOOTH_ERROR = 500;
+	public static final int BLUETOOTH_SOCKET_CONNECTED = 200;
+	public static final int BLUETOOTH_DATA_RECEIVED = 201;
+
+	// Request codes
+	static final int BLUETOOTH_ENABLE_REQ = 101;
+	static final int BLUETOOTH_CHOOSE_NEIGHBOUR = 102;
+	
+	// Represent the local Bluetooth adapter (Bluetooth radio).
+	// Is the entry-point for all Bluetooth interaction.
+	BluetoothAdapter	bluetoothAdapter;
+	
+	// Determines if the Bluetooth adapter is connected in server or in client mode
+	boolean 			isInServerMode;
+	
+	// Layout Views references
+	ProgressBar			progressBar;
+	
+	TextView			statusTv;
+	TextView			bluetoothDataTv;
+	
+	Button				deviceDiscoveryButton;
+
+	@Override
+	protected void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		setContentView(R.layout.activity_main);
+		
+		progressBar = (ProgressBar) findViewById(R.id.progressBar);
+		statusTv = (TextView) findViewById(R.id.statusTv);
+		statusTv.setText(R.string.clientMode);
+		bluetoothDataTv = (TextView) findViewById(R.id.bluetoothDataTv);
+		
+		deviceDiscoveryButton = (Button) findViewById(R.id.deviceDiscoveryBt);
+		
+		// Discover local device's neighbours if users clicks on this Button
+		deviceDiscoveryButton.setOnClickListener(new View.OnClickListener() {
+			
+			@Override
+			public void onClick(View v) {
+				
+				discoverNeighbours();
+			}
+		});
+		
+		// Set the Bluetooth adapter in server mode if the user long-clicks this Button
+		deviceDiscoveryButton.setOnLongClickListener(new View.OnLongClickListener() {
+			
+			@Override
+			public boolean onLongClick(View v) {
+				
+				statusTv.setText(R.string.serverMode);
+				
+				isInServerMode = true;
+				enableServerMode();
+				return true;
+			}
+		});
+		
+		// Get a reference to the BluetoothAdapter and exit if not available
+		bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+		if ( bluetoothAdapter == null ) finish();
+		
+		// Check if Bluetooth is enabled and launch an Intent through the system settings if not
+		if ( !bluetoothAdapter.isEnabled() ) {
+			
+			Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
+			startActivityForResult(enableBluetooth, BLUETOOTH_ENABLE_REQ);
+		}
+		else {
+			
+			setButtonsEnabled(true);
+		}
+		
+		Toast.makeText(this, getString(R.string.appInfo), Toast.LENGTH_LONG)
+			.show();
+	}
+	
+	/**
+	 * Discovers Bluetooth devices that are in the local device's range (in a separate Thread).
+	 */
+	private void discoverNeighbours() {
+		
+		// Check whether there are already paired devices
+		Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
+		
+		ArrayList<String> pairedDevicesInfo = new ArrayList<String>();
+		
+		if ( pairedDevices.size() > 0 ) { 
+			
+			for ( BluetoothDevice device : pairedDevices ) { // Loop through the paired devices
+				
+				pairedDevicesInfo.add(device.getName() + "\n" + device.getAddress());
+			}
+		}
+		
+		// Start an Activity that shows a list of possible neighbours and allows the 
+					// user to select a device to connect to.
+		Intent listNeighboursIntent = BluetoothNeighboursListActivity
+				.getCallingIntent(this, pairedDevicesInfo);
+		startActivityForResult(listNeighboursIntent, BLUETOOTH_CHOOSE_NEIGHBOUR);
+	}
+	
+	/**
+	 * Configures the Bluetooth adapter in server mode (in a separate Thread).
+	 */
+	private void enableServerMode() {
+		
+		setButtonsEnabled(false);
+		new BluetoothAcceptConnectionThread(bluetoothConnectionHandler).start();
+	}
+	
+	@Override
+	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+		
+		// If the user did not enable Bluetooth exit
+		if ( requestCode == BLUETOOTH_ENABLE_REQ ) {
+			
+			if (resultCode == RESULT_OK)  {
+				setButtonsEnabled(true);
+			}
+			else {
+				finish();
+			}
+		}
+		// If the user has selected a Bluetooth device to connect to, initiate a connection request
+		else if ( requestCode == BLUETOOTH_CHOOSE_NEIGHBOUR ) {
+			
+			if ( resultCode == RESULT_OK ) {
+				
+				BluetoothDevice selectedDevice = data
+						.getParcelableExtra(
+								BluetoothDevice.EXTRA_DEVICE
+								);
+				connectToBluetoothDevice(selectedDevice);
+			}
+		}
+	}
+	
+	/**
+	 * Connects to a specific Bluetooth device.
+	 * 
+	 * @param device The device to connect to.
+	 */
+	private void connectToBluetoothDevice(BluetoothDevice device) {
+		
+		statusTv.setText(R.string.connecting);
+		progressBar.setVisibility(View.VISIBLE);
+		
+		// Start a new Thread to connect to the Bluetooth device since 
+		// a bluetooth connection is blocking!
+		new BluetoothConnectThread(device, bluetoothConnectionHandler)
+			.start();
+	}
+	
+	// Handler object to process incoming messages from worker threads.
+	Handler bluetoothConnectionHandler = new Handler(new Handler.Callback() {
+		
+		// Managing connection Thread
+		BluetoothManageConnectionThread connectionThread;
+		
+		@Override
+		public boolean handleMessage(Message msg) {
+			
+			switch (msg.what) {
+			// There has been an exception with the Bluetooth service. Inform the user.
+			case BLUETOOTH_ERROR:
+				
+				progressBar.setVisibility(View.INVISIBLE);
+				statusTv.setText(R.string.bluetoothError);
+				
+				bluetoothDataTv.setText((String) msg.obj);
+				break;
+				
+			// There has been a successful connection between two Bluetooth devices
+			case BLUETOOTH_SOCKET_CONNECTED:
+				
+				progressBar.setVisibility(View.INVISIBLE);
+				statusTv.setText(R.string.connected);
+				
+				connectionThread = (BluetoothManageConnectionThread) msg.obj;
+				
+				// If in client mode send some data to the server
+				if ( !isInServerMode ) {
+					String echoMessage = getString(R.string.echoMessage);
+					connectionThread.writeToSocket(echoMessage.getBytes());
+				}
+				
+				break;
+				
+			// Data has been received by one of the Bluetooth devices
+			case BLUETOOTH_DATA_RECEIVED:
+				// Display the data received from the server
+				String receivedData = (String) msg.obj;
+				bluetoothDataTv.setText(receivedData);
+				
+				// If in server mode, echo the received data
+				if ( isInServerMode ) {
+					connectionThread.writeToSocket(receivedData.getBytes());
+				}
+				break;
+
+			default:
+				break;
+			}
+			
+			return true;
+		}
+	});
+	
+	/**
+	 * Sets the state of the device discovery Button.
+	 * 
+	 * @param state Boolean indicating the state of the Button.
+	 */
+	private void setButtonsEnabled(boolean state) {
+		
+		deviceDiscoveryButton.setEnabled(state);
+	}
+}

+ 33 - 0
BluetoothNeighbourDiscovery/AndroidManifest.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="org.uab.android.bluetooth.simple"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="14"
+        android:targetSdkVersion="19" />
+    
+    <uses-permission android:name="android.permission.BLUETOOTH"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity 
+            android:name=".BluetoothNeighboursListActivity"
+            android:label="@string/app_name"/>
+    </application>
+
+</manifest>

BIN
BluetoothNeighbourDiscovery/ic_launcher-web.png


BIN
BluetoothNeighbourDiscovery/libs/android-support-v4.jar


BIN
BluetoothNeighbourDiscovery/res/drawable-hdpi/ic_launcher.png


BIN
BluetoothNeighbourDiscovery/res/drawable-mdpi/ic_launcher.png


BIN
BluetoothNeighbourDiscovery/res/drawable-xhdpi/ic_launcher.png


BIN
BluetoothNeighbourDiscovery/res/drawable-xxhdpi/ic_launcher.png


+ 17 - 0
BluetoothNeighbourDiscovery/res/layout/activity_main.xml

@@ -0,0 +1,17 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="${relativePackage}.${activityClass}" >
+
+    <Button
+        android:id="@+id/deviceDiscoveryBt"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentRight="true"
+        android:text="@string/discover"
+        android:enabled="false" />
+
+</RelativeLayout>

+ 11 - 0
BluetoothNeighbourDiscovery/res/layout/list_footerview.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/footer"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center_horizontal"
+    android:text="@string/discoverFooterView"
+    android:textSize="20sp" >
+    
+
+</TextView>

+ 9 - 0
BluetoothNeighbourDiscovery/res/layout/list_item.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:padding="10dp"
+    android:textSize="24sp" >
+    
+
+</TextView>

+ 11 - 0
BluetoothNeighbourDiscovery/res/values-v11/styles.xml

@@ -0,0 +1,11 @@
+<resources>
+
+    <!--
+        Base application theme for API 11+. This theme completely replaces
+        AppBaseTheme from res/values/styles.xml on API 11+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+        <!-- API 11 theme customizations can go here. -->
+    </style>
+
+</resources>

+ 12 - 0
BluetoothNeighbourDiscovery/res/values-v14/styles.xml

@@ -0,0 +1,12 @@
+<resources>
+
+    <!--
+        Base application theme for API 14+. This theme completely replaces
+        AppBaseTheme from BOTH res/values/styles.xml and
+        res/values-v11/styles.xml on API 14+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+        <!-- API 14 theme customizations can go here. -->
+    </style>
+
+</resources>

+ 9 - 0
BluetoothNeighbourDiscovery/res/values/strings.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <string name="app_name">BluetoothSimple</string>
+    <string name="hello_world">Hello world!</string>
+    <string name="discover">Device discovery</string>
+    <string name="discoverFooterView">Discover more devices</string>
+
+</resources>

+ 20 - 0
BluetoothNeighbourDiscovery/res/values/styles.xml

@@ -0,0 +1,20 @@
+<resources>
+
+    <!--
+        Base application theme, dependent on API level. This theme is replaced
+        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Light">
+        <!--
+            Theme customizations available in newer API levels can go in
+            res/values-vXX/styles.xml, while customizations related to
+            backward-compatibility can go here.
+        -->
+    </style>
+
+    <!-- Application theme. -->
+    <style name="AppTheme" parent="AppBaseTheme">
+        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+    </style>
+
+</resources>

+ 133 - 0
BluetoothNeighbourDiscovery/src/org/uab/android/bluetooth/simple/BluetoothNeighboursListActivity.java

@@ -0,0 +1,133 @@
+package org.uab.android.bluetooth.simple;
+
+import java.util.ArrayList;
+
+import android.app.ListActivity;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+public class BluetoothNeighboursListActivity extends ListActivity {
+
+	static final String EXTRA_DEVICES = "EXTRA_DEVICES";
+	
+	BluetoothAdapter		bluetoothAdapter;
+	
+	ListView				neighboursListView;
+	ArrayAdapter<String> 	neighboursListAdapter;
+	
+	public static Intent getCallingIntent(Context context, ArrayList<String> devices) {
+		
+		Intent listNeighboursIntent = new Intent(context, BluetoothNeighboursListActivity.class);
+		listNeighboursIntent.putStringArrayListExtra(EXTRA_DEVICES, devices);
+		return listNeighboursIntent;
+	}
+	
+	@Override
+	protected void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		
+		// Get a reference to the default BluetoothAdapter
+		bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+		
+		// Get a reference to the ListView
+		neighboursListView = getListView();
+		
+		// Create a FooterView for the ListView
+		LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+		View footerView = layoutInflater.inflate(R.layout.list_footerview, neighboursListView, false);
+		
+		neighboursListView.setFooterDividersEnabled(true);
+		
+		// Add the FooterView to the list
+		neighboursListView.addFooterView(footerView, null, true);
+		
+		// Get the list of paired devices already discovered
+		ArrayList<String> pairedDevices = getIntent().getStringArrayListExtra(EXTRA_DEVICES);
+		
+		// Initialize the list's ArrayAdapter
+		neighboursListAdapter = new ArrayAdapter<String>(
+				this, 						// Context
+				R.layout.list_item, 		// View for the list items
+				pairedDevices				// Data objects
+				);
+		neighboursListView.setAdapter(neighboursListAdapter);
+		
+		// Set the ListView OnItemClickListener
+		neighboursListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+
+			@Override
+			public void onItemClick(AdapterView<?> parent, View view, int position,
+					long id) {
+				
+				// If the user clicked on the ListView's footer start discovering neighbours
+				if ( parent.getAdapter().getItemViewType(position) == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER ) {
+					
+					bluetoothAdapter.startDiscovery();
+				}
+				else {
+					
+					// Cancel neighbours discovery
+					bluetoothAdapter.cancelDiscovery();
+					
+					// Get the device's MAC Address
+					String selectedDevice = (String) parent.getItemAtPosition(position);
+					String macAddress = selectedDevice.split("\n")[1];
+					
+					BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(macAddress);
+					
+					// Create an Intent to return the selected bluetooth device to the calling Activity
+					Intent dataIntent = new Intent();
+					dataIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, bluetoothDevice);
+					setResult(RESULT_OK, dataIntent);
+					finish();
+				}
+				
+			}
+		});
+	}
+	
+	@Override
+	protected void onResume() {
+		super.onResume();
+		
+		// Register a BroadcastReceiver for new devices discovery
+		IntentFilter discoveryFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
+		registerReceiver(neighboursDiscoveryReceiver, discoveryFilter);
+	}
+	
+	@Override
+	protected void onPause() {
+		super.onPause();
+		
+		bluetoothAdapter.cancelDiscovery();
+		unregisterReceiver(neighboursDiscoveryReceiver);
+	}
+	
+	
+	BroadcastReceiver neighboursDiscoveryReceiver = new BroadcastReceiver() {
+		
+		@Override
+		public void onReceive(Context context, Intent intent) {
+			
+			// A new Bluetooth device has been found
+			if ( intent.getAction().equals(BluetoothDevice.ACTION_FOUND) ) {
+				
+				BluetoothDevice device = intent
+						.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+				neighboursListAdapter.add(device.getName() + "\n" + device.getAddress());
+				neighboursListAdapter.notifyDataSetChanged();
+			}
+			
+		}
+	};
+}

+ 102 - 0
BluetoothNeighbourDiscovery/src/org/uab/android/bluetooth/simple/MainActivity.java

@@ -0,0 +1,102 @@
+package org.uab.android.bluetooth.simple;
+
+import java.util.ArrayList;
+import java.util.Set;
+
+import android.app.Activity;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+
+public class MainActivity extends Activity {
+	
+	static final int BLUETOOTH_ENABLE_REQ = 101;
+	static final int BLUETOOTH_CHOOSE_NEIGHBOUR = 102;
+	
+	BluetoothAdapter	bluetoothAdapter;
+	
+	Button				deviceDiscoveryButton;
+
+	@Override
+	protected void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		setContentView(R.layout.activity_main);
+		
+		deviceDiscoveryButton = (Button) findViewById(R.id.deviceDiscoveryBt);
+		deviceDiscoveryButton.setOnClickListener(new View.OnClickListener() {
+			
+			@Override
+			public void onClick(View v) {
+				
+				discoverNeighbours();
+			}
+		});
+		
+		// Get a reference to the BluetoothAdapter and exit if not available
+		bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+		if ( bluetoothAdapter == null ) finish();
+		
+		// Check if Bluetooth is enabled and launch an Intent through the system settings if not
+		if ( !bluetoothAdapter.isEnabled() ) {
+			
+			Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
+			startActivityForResult(enableBluetooth, BLUETOOTH_ENABLE_REQ);
+		}
+		else {
+			
+			setButtonsEnabled(true);
+		}
+	}
+	
+	private void discoverNeighbours() {
+		
+		// Check whether there are already paired devices
+		Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
+		
+		ArrayList<String> pairedDevicesInfo = new ArrayList<String>();
+		
+		if ( pairedDevices.size() > 0 ) { 
+			
+			for ( BluetoothDevice device : pairedDevices ) { // Loop through the paired devices
+				
+				pairedDevicesInfo.add(device.getName() + "\n" + device.getAddress());
+			}
+		}
+		
+		// Start an Activity that shows a list of possible neighbours and allows the 
+					// user to select a device to connect to.
+		Intent listNeighboursIntent = BluetoothNeighboursListActivity
+				.getCallingIntent(this, pairedDevicesInfo);
+		startActivityForResult(listNeighboursIntent, BLUETOOTH_CHOOSE_NEIGHBOUR);
+	}
+	
+	@Override
+	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+		
+		// If the user did not enable Bluetooth exit
+		if ( requestCode == BLUETOOTH_ENABLE_REQ ) {
+			
+			if (resultCode == RESULT_OK)  {
+				setButtonsEnabled(true);
+			}
+			else {
+				finish();
+			}
+		}
+		else if ( requestCode == BLUETOOTH_CHOOSE_NEIGHBOUR ) {
+			
+			if ( resultCode == RESULT_OK ) {
+				
+				// TODO Connect to the Bluetooth device
+			}
+		}
+	}
+	
+	private void setButtonsEnabled(boolean state) {
+		
+		deviceDiscoveryButton.setEnabled(state);
+	}
+}