diff --git a/samples/BluetoothChat/res/menu/option_menu.xml b/samples/BluetoothChat/res/menu/option_menu.xml index 46df04367..18de725c9 100644 --- a/samples/BluetoothChat/res/menu/option_menu.xml +++ b/samples/BluetoothChat/res/menu/option_menu.xml @@ -14,9 +14,12 @@ limitations under the License. --> - + android:title="@string/secure_connect" /> + diff --git a/samples/BluetoothChat/res/values/strings.xml b/samples/BluetoothChat/res/values/strings.xml index 1c4767671..53af2a305 100644 --- a/samples/BluetoothChat/res/values/strings.xml +++ b/samples/BluetoothChat/res/values/strings.xml @@ -35,6 +35,7 @@ Scan for devices - Connect a device + Connect a device - Secure + Connect a device - Insecure Make discoverable diff --git a/samples/BluetoothChat/src/com/example/android/BluetoothChat/BluetoothChat.java b/samples/BluetoothChat/src/com/example/android/BluetoothChat/BluetoothChat.java index d05bbd611..429f2dde4 100644 --- a/samples/BluetoothChat/src/com/example/android/BluetoothChat/BluetoothChat.java +++ b/samples/BluetoothChat/src/com/example/android/BluetoothChat/BluetoothChat.java @@ -59,8 +59,9 @@ public class BluetoothChat extends Activity { public static final String TOAST = "toast"; // Intent request codes - private static final int REQUEST_CONNECT_DEVICE = 1; - private static final int REQUEST_ENABLE_BT = 2; + private static final int REQUEST_CONNECT_DEVICE_SECURE = 1; + private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2; + private static final int REQUEST_ENABLE_BT = 3; // Layout Views private TextView mTitle; @@ -287,16 +288,16 @@ public class BluetoothChat extends Activity { public void onActivityResult(int requestCode, int resultCode, Intent data) { if(D) Log.d(TAG, "onActivityResult " + resultCode); switch (requestCode) { - case REQUEST_CONNECT_DEVICE: + case REQUEST_CONNECT_DEVICE_SECURE: // When DeviceListActivity returns with a device to connect if (resultCode == Activity.RESULT_OK) { - // Get the device MAC address - String address = data.getExtras() - .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS); - // Get the BLuetoothDevice object - BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); - // Attempt to connect to the device - mChatService.connect(device); + connectDevice(data, true); + } + break; + case REQUEST_CONNECT_DEVICE_INSECURE: + // When DeviceListActivity returns with a device to connect + if (resultCode == Activity.RESULT_OK) { + connectDevice(data, false); } break; case REQUEST_ENABLE_BT: @@ -313,6 +314,16 @@ public class BluetoothChat extends Activity { } } + private void connectDevice(Intent data, boolean secure) { + // Get the device MAC address + String address = data.getExtras() + .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS); + // Get the BLuetoothDevice object + BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); + // Attempt to connect to the device + mChatService.connect(device, secure); + } + @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); @@ -322,11 +333,17 @@ public class BluetoothChat extends Activity { @Override public boolean onOptionsItemSelected(MenuItem item) { + Intent serverIntent = null; switch (item.getItemId()) { - case R.id.scan: + case R.id.secure_connect_scan: // Launch the DeviceListActivity to see devices and do scan - Intent serverIntent = new Intent(this, DeviceListActivity.class); - startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE); + serverIntent = new Intent(this, DeviceListActivity.class); + startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE); + return true; + case R.id.insecure_connect_scan: + // Launch the DeviceListActivity to see devices and do scan + serverIntent = new Intent(this, DeviceListActivity.class); + startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_INSECURE); return true; case R.id.discoverable: // Ensure this device is discoverable by others @@ -336,4 +353,4 @@ public class BluetoothChat extends Activity { return false; } -} \ No newline at end of file +} diff --git a/samples/BluetoothChat/src/com/example/android/BluetoothChat/BluetoothChatService.java b/samples/BluetoothChat/src/com/example/android/BluetoothChat/BluetoothChatService.java index d0c1d43cd..46d4bcb1c 100644 --- a/samples/BluetoothChat/src/com/example/android/BluetoothChat/BluetoothChatService.java +++ b/samples/BluetoothChat/src/com/example/android/BluetoothChat/BluetoothChatService.java @@ -43,15 +43,20 @@ public class BluetoothChatService { private static final boolean D = true; // Name for the SDP record when creating server socket - private static final String NAME = "BluetoothChat"; + private static final String NAME_SECURE = "BluetoothChatSecure"; + private static final String NAME_INSECURE = "BluetoothChatInsecure"; // Unique UUID for this application - private static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66"); + private static final UUID MY_UUID_SECURE = + UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66"); + private static final UUID MY_UUID_INSECURE = + UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66"); // Member fields private final BluetoothAdapter mAdapter; private final Handler mHandler; - private AcceptThread mAcceptThread; + private AcceptThread mSecureAcceptThread; + private AcceptThread mInsecureAcceptThread; private ConnectThread mConnectThread; private ConnectedThread mConnectedThread; private int mState; @@ -103,19 +108,25 @@ public class BluetoothChatService { // Cancel any thread currently running a connection if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;} - // Start the thread to listen on a BluetoothServerSocket - if (mAcceptThread == null) { - mAcceptThread = new AcceptThread(); - mAcceptThread.start(); - } setState(STATE_LISTEN); + + // Start the thread to listen on a BluetoothServerSocket + if (mSecureAcceptThread == null) { + mSecureAcceptThread = new AcceptThread(true); + mSecureAcceptThread.start(); + } + if (mInsecureAcceptThread == null) { + mInsecureAcceptThread = new AcceptThread(false); + mInsecureAcceptThread.start(); + } } /** * Start the ConnectThread to initiate a connection to a remote device. * @param device The BluetoothDevice to connect + * @param secure Socket Security type - Secure (true) , Insecure (false) */ - public synchronized void connect(BluetoothDevice device) { + public synchronized void connect(BluetoothDevice device, boolean secure) { if (D) Log.d(TAG, "connect to: " + device); // Cancel any thread attempting to make a connection @@ -127,7 +138,7 @@ public class BluetoothChatService { if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;} // Start the thread to connect with the given device - mConnectThread = new ConnectThread(device); + mConnectThread = new ConnectThread(device, secure); mConnectThread.start(); setState(STATE_CONNECTING); } @@ -137,8 +148,9 @@ public class BluetoothChatService { * @param socket The BluetoothSocket on which the connection was made * @param device The BluetoothDevice that has been connected */ - public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) { - if (D) Log.d(TAG, "connected"); + public synchronized void connected(BluetoothSocket socket, BluetoothDevice + device, final String socketType) { + if (D) Log.d(TAG, "connected, Socket Type:" + socketType); // Cancel the thread that completed the connection if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;} @@ -147,10 +159,17 @@ public class BluetoothChatService { if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;} // Cancel the accept thread because we only want to connect to one device - if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;} + if (mSecureAcceptThread != null) { + mSecureAcceptThread.cancel(); + mSecureAcceptThread = null; + } + if (mInsecureAcceptThread != null) { + mInsecureAcceptThread.cancel(); + mInsecureAcceptThread = null; + } // Start the thread to manage the connection and perform transmissions - mConnectedThread = new ConnectedThread(socket); + mConnectedThread = new ConnectedThread(socket, socketType); mConnectedThread.start(); // Send the name of the connected device back to the UI Activity @@ -168,9 +187,26 @@ public class BluetoothChatService { */ public synchronized void stop() { if (D) Log.d(TAG, "stop"); - if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;} - if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;} - if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;} + + if (mConnectThread != null) { + mConnectThread.cancel(); + mConnectThread = null; + } + + if (mConnectedThread != null) { + mConnectedThread.cancel(); + mConnectedThread = null; + } + + if (mSecureAcceptThread != null) { + mSecureAcceptThread.cancel(); + mSecureAcceptThread = null; + } + + if (mInsecureAcceptThread != null) { + mInsecureAcceptThread.cancel(); + mInsecureAcceptThread = null; + } setState(STATE_NONE); } @@ -195,28 +231,30 @@ public class BluetoothChatService { * Indicate that the connection attempt failed and notify the UI Activity. */ private void connectionFailed() { - setState(STATE_LISTEN); - // Send a failure message back to the Activity Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST); Bundle bundle = new Bundle(); bundle.putString(BluetoothChat.TOAST, "Unable to connect device"); msg.setData(bundle); mHandler.sendMessage(msg); + + // Start the service over to restart listening mode + BluetoothChatService.this.start(); } /** * Indicate that the connection was lost and notify the UI Activity. */ private void connectionLost() { - setState(STATE_LISTEN); - // Send a failure message back to the Activity Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST); Bundle bundle = new Bundle(); bundle.putString(BluetoothChat.TOAST, "Device connection was lost"); msg.setData(bundle); mHandler.sendMessage(msg); + + // Start the service over to restart listening mode + BluetoothChatService.this.start(); } /** @@ -227,22 +265,32 @@ public class BluetoothChatService { private class AcceptThread extends Thread { // The local server socket private final BluetoothServerSocket mmServerSocket; + private String mSocketType; - public AcceptThread() { + public AcceptThread(boolean secure) { BluetoothServerSocket tmp = null; + mSocketType = secure ? "Secure":"Insecure"; // Create a new listening server socket try { - tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID); + if (secure) { + tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE, + MY_UUID_SECURE); + } else { + tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord( + NAME_INSECURE, MY_UUID_INSECURE); + } } catch (IOException e) { - Log.e(TAG, "listen() failed", e); + Log.e(TAG, "Socket Type: " + mSocketType + "listen() failed", e); } mmServerSocket = tmp; } public void run() { - if (D) Log.d(TAG, "BEGIN mAcceptThread" + this); - setName("AcceptThread"); + if (D) Log.d(TAG, "Socket Type: " + mSocketType + + "BEGIN mAcceptThread" + this); + setName("AcceptThread" + mSocketType); + BluetoothSocket socket = null; // Listen to the server socket if we're not connected @@ -252,7 +300,7 @@ public class BluetoothChatService { // successful connection or an exception socket = mmServerSocket.accept(); } catch (IOException e) { - Log.e(TAG, "accept() failed", e); + Log.e(TAG, "Socket Type: " + mSocketType + "accept() failed", e); break; } @@ -263,7 +311,8 @@ public class BluetoothChatService { case STATE_LISTEN: case STATE_CONNECTING: // Situation normal. Start the connected thread. - connected(socket, socket.getRemoteDevice()); + connected(socket, socket.getRemoteDevice(), + mSocketType); break; case STATE_NONE: case STATE_CONNECTED: @@ -278,15 +327,16 @@ public class BluetoothChatService { } } } - if (D) Log.i(TAG, "END mAcceptThread"); + if (D) Log.i(TAG, "END mAcceptThread, socket Type: " + mSocketType); + } public void cancel() { - if (D) Log.d(TAG, "cancel " + this); + if (D) Log.d(TAG, "Socket Type" + mSocketType + "cancel " + this); try { mmServerSocket.close(); } catch (IOException e) { - Log.e(TAG, "close() of server failed", e); + Log.e(TAG, "Socket Type" + mSocketType + "close() of server failed", e); } } } @@ -300,24 +350,32 @@ public class BluetoothChatService { private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; + private String mSocketType; - public ConnectThread(BluetoothDevice device) { + public ConnectThread(BluetoothDevice device, boolean secure) { mmDevice = device; BluetoothSocket tmp = null; + mSocketType = secure ? "Secure" : "Insecure"; // Get a BluetoothSocket for a connection with the // given BluetoothDevice try { - tmp = device.createRfcommSocketToServiceRecord(MY_UUID); + if (secure) { + tmp = device.createRfcommSocketToServiceRecord( + MY_UUID_SECURE); + } else { + tmp = device.createInsecureRfcommSocketToServiceRecord( + MY_UUID_INSECURE); + } } catch (IOException e) { - Log.e(TAG, "create() failed", e); + Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e); } mmSocket = tmp; } public void run() { - Log.i(TAG, "BEGIN mConnectThread"); - setName("ConnectThread"); + Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType); + setName("ConnectThread" + mSocketType); // Always cancel discovery because it will slow down a connection mAdapter.cancelDiscovery(); @@ -328,15 +386,14 @@ public class BluetoothChatService { // successful connection or an exception mmSocket.connect(); } catch (IOException e) { - connectionFailed(); // Close the socket try { mmSocket.close(); } catch (IOException e2) { - Log.e(TAG, "unable to close() socket during connection failure", e2); + Log.e(TAG, "unable to close() " + mSocketType + + " socket during connection failure", e2); } - // Start the service over to restart listening mode - BluetoothChatService.this.start(); + connectionFailed(); return; } @@ -346,14 +403,14 @@ public class BluetoothChatService { } // Start the connected thread - connected(mmSocket, mmDevice); + connected(mmSocket, mmDevice, mSocketType); } public void cancel() { try { mmSocket.close(); } catch (IOException e) { - Log.e(TAG, "close() of connect socket failed", e); + Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e); } } } @@ -367,8 +424,8 @@ public class BluetoothChatService { private final InputStream mmInStream; private final OutputStream mmOutStream; - public ConnectedThread(BluetoothSocket socket) { - Log.d(TAG, "create ConnectedThread"); + public ConnectedThread(BluetoothSocket socket, String socketType) { + Log.d(TAG, "create ConnectedThread: " + socketType); mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null;