AltosDroid: Begin re-working Bluetooth code
authorMike Beattie <mike@ethernal.org>
Thu, 2 Aug 2012 10:09:24 +0000 (22:09 +1200)
committerMike Beattie <mike@ethernal.org>
Thu, 2 Aug 2012 10:09:24 +0000 (22:09 +1200)
* Move to using explicit 'magic' UUID, rather than java reflection
* Re-work UI to make it more useful for testing
* Use Insecure RFCOMM only, and remove code that differentiates.

Signed-off-by: Mike Beattie <mike@ethernal.org>
altosdroid/res/layout/main.xml
altosdroid/res/menu/option_menu.xml
altosdroid/res/values/strings.xml
altosdroid/src/org/altusmetrum/AltosDroid/AltosDroid.java
altosdroid/src/org/altusmetrum/AltosDroid/BluetoothChatService.java

index 17025f6bbd9b691cd80ab5637c1237a8e0d0a385..f2e6640caee05bd1f8f415d00e01571c6b353c41 100644 (file)
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     >
-    <ListView android:id="@+id/in"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:stackFromBottom="true"
-        android:transcriptMode="alwaysScroll"
+
+    <TextView
+        android:id="@+id/in"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
         android:layout_weight="1"
-    />
+        android:gravity="bottom"
+        android:scrollbars="vertical"
+        android:typeface="monospace" />
+
     <LinearLayout
         android:orientation="horizontal"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         >
-        <EditText android:id="@+id/edit_text_out"
+
+        <EditText
+            android:id="@+id/edit_text_out"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_weight="1"
             android:layout_gravity="bottom"
-        />
+            android:layout_weight="1"
+            android:inputType="text|textNoSuggestions" />
+
         <Button android:id="@+id/button_send"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
index 27625e9c3bda21bb8309d59ac7b585ceb9f784fc..feb5668ea0e42c58f664735cab1b30f8783b1ec7 100644 (file)
      limitations under the License.
 -->
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/connect_scan"
+          android:icon="@android:drawable/ic_menu_search"
+          android:title="@string/connect_device" />
     <item android:id="@+id/telemetry_service_control"
           android:icon="@android:drawable/ic_menu_manage"
           android:title="@string/telemetry_service_control" />
     <item android:id="@+id/telemetry_service_bind"
           android:icon="@android:drawable/ic_menu_rotate"
           android:title="@string/telemetry_service_bind" />
-    <item android:id="@+id/secure_connect_scan"
-          android:icon="@android:drawable/ic_menu_search"
-          android:title="@string/secure_connect" />
-    <item android:id="@+id/insecure_connect_scan"
-          android:icon="@android:drawable/ic_menu_search"
-          android:title="@string/insecure_connect" />
-    <item android:id="@+id/discoverable"
-          android:icon="@android:drawable/ic_menu_mylocation"
-          android:title="@string/discoverable" />
 </menu>
index 0b2f922749b26e33181d9bc78b5488e5475eab4a..249550fb7cfb32bbaa163dacafdc3f61742e6d3c 100644 (file)
     <string name="send">Send</string>
     <string name="not_connected">You are not connected to a device</string>
     <string name="bt_not_enabled_leaving">Bluetooth was not enabled. Leaving Bluetooth Chat.</string>
-    <string name="title_connecting">connecting...</string>
+    <string name="title_connecting">connecting</string>
     <string name="title_connected_to">connected: </string>
     <string name="title_not_connected">not connected</string>
 
     <!--  DeviceListActivity -->
-    <string name="scanning">scanning for devices...</string>
+    <string name="scanning">scanning for devices</string>
     <string name="select_device">select a device to connect</string>
     <string name="none_paired">No devices have been paired</string>
     <string name="none_found">No devices found</string>
@@ -35,9 +35,9 @@
     <string name="button_scan">Scan for devices</string>
 
     <!-- Options Menu -->
-    <string name="secure_connect">Connect a device - Secure</string>
-    <string name="insecure_connect">Connect a device - Insecure</string>
-    <string name="discoverable">Make discoverable</string>
+    <string name="connect_device">Connect a device</string>
+    <string name="telemetry_service_control">Control Service</string>
+    <string name="telemetry_service_bind">(Un)Bind Service</string>
 
     <!-- Service -->
     <string name="telemetry_service_label">AltOS Telemetry Service</string>
     <string name="telemetry_service_stopped">Telemetry Service Stopped</string>
 
 
-
-    <string name="telemetry_service_control">Start/Stop Service</string>
-    <string name="telemetry_service_bind">Bind/Unbind Service</string>
-
     <string name="activity_telemetry_service_controller">App/Service/Local Service Controller</string>
     <string name="telemetry_service_controller">This demonstrates how you can implement persistent services that
         may be started and stopped as desired.</string>
index b4a3227cde7664d4e4b8d1a99f1c9edf84ec8352..b4725e220c41d27a4a3ce90f4467ae25f6a2f199 100644 (file)
@@ -23,6 +23,7 @@ import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.text.method.ScrollingMovementMethod;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.Menu;
@@ -32,10 +33,8 @@ import android.view.View;
 import android.view.Window;
 import android.view.View.OnClickListener;
 import android.view.inputmethod.EditorInfo;
-import android.widget.ArrayAdapter;
 import android.widget.Button;
 import android.widget.EditText;
-import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.Toast;
 import org.altusmetrum.AltosDroid.R;
@@ -46,11 +45,9 @@ import org.altusmetrum.AltosLib.*;
  */
 public class AltosDroid extends Activity {
     // Debugging
-    private static final String TAG = "BluetoothChat";
+    private static final String TAG = "AltosDroid";
     private static final boolean D = true;
 
-    private static final AltosLine q = new AltosLine();
-
     // Message types sent from the BluetoothChatService Handler
     public static final int MESSAGE_STATE_CHANGE = 1;
     public static final int MESSAGE_READ = 2;
@@ -63,20 +60,17 @@ public class AltosDroid extends Activity {
     public static final String TOAST = "toast";
 
     // Intent request codes
-    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;
+    private static final int REQUEST_CONNECT_DEVICE = 1;
+    private static final int REQUEST_ENABLE_BT      = 2;
 
     // Layout Views
     private TextView mTitle;
-    private ListView mConversationView;
+    private TextView mSerialView;
     private EditText mOutEditText;
     private Button mSendButton;
 
     // Name of the connected device
     private String mConnectedDeviceName = null;
-    // Array adapter for the conversation thread
-    private ArrayAdapter<String> mConversationArrayAdapter;
     // String buffer for outgoing messages
     private StringBuffer mOutStringBuffer;
     // Local Bluetooth adapter
@@ -144,13 +138,35 @@ public class AltosDroid extends Activity {
         }
     }
 
+    @Override
+    public synchronized void onPause() {
+        super.onPause();
+        if(D) Log.e(TAG, "- ON PAUSE -");
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+        if(D) Log.e(TAG, "-- ON STOP --");
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        // Stop the Bluetooth chat services
+        if (mChatService != null) mChatService.stop();
+        if(D) Log.e(TAG, "--- ON DESTROY ---");
+    }
+
+
+
     private void setupChat() {
         Log.d(TAG, "setupChat()");
 
-        // Initialize the array adapter for the conversation thread
-        mConversationArrayAdapter = new ArrayAdapter<String>(this, R.layout.message);
-        mConversationView = (ListView) findViewById(R.id.in);
-        mConversationView.setAdapter(mConversationArrayAdapter);
+        mSerialView = (TextView) findViewById(R.id.in);
+        mSerialView.setMovementMethod(new ScrollingMovementMethod());
+        mSerialView.setClickable(false);
+        mSerialView.setLongClickable(false);
 
         // Initialize the compose field with a listener for the return key
         mOutEditText = (EditText) findViewById(R.id.edit_text_out);
@@ -174,36 +190,6 @@ public class AltosDroid extends Activity {
         mOutStringBuffer = new StringBuffer("");
     }
 
-    @Override
-    public synchronized void onPause() {
-        super.onPause();
-        if(D) Log.e(TAG, "- ON PAUSE -");
-    }
-
-    @Override
-    public void onStop() {
-        super.onStop();
-        if(D) Log.e(TAG, "-- ON STOP --");
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        // Stop the Bluetooth chat services
-        if (mChatService != null) mChatService.stop();
-        if(D) Log.e(TAG, "--- ON DESTROY ---");
-    }
-
-    private void ensureDiscoverable() {
-        if(D) Log.d(TAG, "ensure discoverable");
-        if (mBluetoothAdapter.getScanMode() !=
-            BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
-            Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
-            discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
-            startActivity(discoverableIntent);
-        }
-    }
-
     /**
      * Sends a message.
      * @param message  A string of text to send.
@@ -252,7 +238,7 @@ public class AltosDroid extends Activity {
                 case BluetoothChatService.STATE_CONNECTED:
                     mTitle.setText(R.string.title_connected_to);
                     mTitle.append(mConnectedDeviceName);
-                    mConversationArrayAdapter.clear();
+                    mSerialView.setText("");
                     break;
                 case BluetoothChatService.STATE_CONNECTING:
                     mTitle.setText(R.string.title_connecting);
@@ -267,13 +253,13 @@ public class AltosDroid extends Activity {
                 byte[] writeBuf = (byte[]) msg.obj;
                 // construct a string from the buffer
                 String writeMessage = new String(writeBuf);
-                mConversationArrayAdapter.add("Me:  " + writeMessage);
+                mSerialView.append(writeMessage + '\n');
                 break;
             case MESSAGE_READ:
                 byte[] readBuf = (byte[]) msg.obj;
                 // construct a string from the valid bytes in the buffer
                 String readMessage = new String(readBuf, 0, msg.arg1);
-                mConversationArrayAdapter.add(mConnectedDeviceName+":  " + readMessage);
+                mSerialView.append(readMessage);
                 break;
             case MESSAGE_DEVICE_NAME:
                 // save the connected device's name
@@ -292,16 +278,10 @@ public class AltosDroid extends Activity {
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         if(D) Log.d(TAG, "onActivityResult " + resultCode);
         switch (requestCode) {
-        case REQUEST_CONNECT_DEVICE_SECURE:
-            // When DeviceListActivity returns with a device to connect
+        case REQUEST_CONNECT_DEVICE:
+            // When DeviceListActivity returns with a device to connect to
             if (resultCode == Activity.RESULT_OK) {
-                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);
+                connectDevice(data);
             }
             break;
         case REQUEST_ENABLE_BT:
@@ -318,14 +298,14 @@ public class AltosDroid extends Activity {
         }
     }
 
-    private void connectDevice(Intent data, boolean secure) {
+    private void connectDevice(Intent data) {
         // 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);
+        mChatService.connect(device);
     }
 
     @Override
@@ -347,19 +327,10 @@ public class AltosDroid extends Activity {
             serverIntent = new Intent(this, TelemetryServiceActivities.Binding.class);
             startActivity(serverIntent);
             return true;
-        case R.id.secure_connect_scan:
-            // Launch the DeviceListActivity to see devices and do scan
-            serverIntent = new Intent(this, DeviceListActivity.class);
-            startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);
-            return true;
-        case R.id.insecure_connect_scan:
+        case R.id.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
-            ensureDiscoverable();
+            startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
             return true;
         }
         return false;
index 93cb75de8b6e9092899f61e14b54e904b612851d..a93c08d6efac8a5f4e074cfedfa6dcc5e298bfd9 100644 (file)
@@ -19,9 +19,7 @@ package org.altusmetrum.AltosDroid;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-//import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
+import java.util.UUID;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothSocket;
@@ -103,9 +101,8 @@ public class BluetoothChatService {
     /**
      * 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, boolean secure) {
+    public synchronized void connect(BluetoothDevice device) {
         if (D) Log.d(TAG, "connect to: " + device);
 
         // Cancel any thread attempting to make a connection
@@ -117,7 +114,7 @@ public class BluetoothChatService {
         if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
 
         // Start the thread to connect with the given device
-        mConnectThread = new ConnectThread(device, secure);
+        mConnectThread = new ConnectThread(device);
         mConnectThread.start();
         setState(STATE_CONNECTING);
     }
@@ -127,9 +124,8 @@ 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, final String socketType) {
-        if (D) Log.d(TAG, "connected, Socket Type:" + socketType);
+    public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
+        if (D) Log.d(TAG, "connected");
 
         // Cancel the thread that completed the connection
         if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
@@ -138,7 +134,7 @@ public class BluetoothChatService {
         if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
 
         // Start the thread to manage the connection and perform transmissions
-        mConnectedThread = new ConnectedThread(socket, socketType);
+        mConnectedThread = new ConnectedThread(socket);
         mConnectedThread.start();
 
         // Send the name of the connected device back to the UI Activity
@@ -224,37 +220,25 @@ public class BluetoothChatService {
      * succeeds or fails.
      */
     private class ConnectThread extends Thread {
+        private final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
         private final BluetoothSocket mmSocket;
         private final BluetoothDevice mmDevice;
-        private String mSocketType;
 
-        public ConnectThread(BluetoothDevice device, boolean secure) {
+               public ConnectThread(BluetoothDevice device) {
             mmDevice = device;
             BluetoothSocket tmp = null;
-            mSocketType = secure ? "Secure" : "Insecure";
 
-            // Get a BluetoothSocket for a connection with the
-            // given BluetoothDevice
             try {
-                if (secure) {
-                       Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
-                       tmp = (BluetoothSocket) m.invoke(device, 2);
-//                    tmp = device.createRfcommSocket(1);
-                } else {
-                       Method m = device.getClass().getMethod("createInsecureRfcommSocket", new Class[] {int.class});
-                       tmp = (BluetoothSocket) m.invoke(device, 2);
-//                    tmp = device.createInsecureRfcommSocket(1);
-                }
-            } catch (Exception e) {
-                Log.e(TAG, "Socket Type: " + mSocketType + "create() failed", e);
+                               tmp = mmDevice.createInsecureRfcommSocketToServiceRecord(SPP_UUID);
+                       } catch (IOException e) {
                                e.printStackTrace();
                        }
             mmSocket = tmp;
         }
 
         public void run() {
-            Log.i(TAG, "BEGIN mConnectThread SocketType:" + mSocketType);
-            setName("ConnectThread" + mSocketType);
+            Log.i(TAG, "BEGIN mConnectThread");
+            setName("ConnectThread");
 
             // Always cancel discovery because it will slow down a connection
             mAdapter.cancelDiscovery();
@@ -269,8 +253,7 @@ public class BluetoothChatService {
                 try {
                     mmSocket.close();
                 } catch (IOException e2) {
-                    Log.e(TAG, "unable to close() " + mSocketType +
-                            " socket during connection failure", e2);
+                    Log.e(TAG, "unable to close() socket during connection failure", e2);
                 }
                 connectionFailed();
                 return;
@@ -282,14 +265,14 @@ public class BluetoothChatService {
             }
 
             // Start the connected thread
-            connected(mmSocket, mmDevice, mSocketType);
+            connected(mmSocket, mmDevice);
         }
 
         public void cancel() {
             try {
                 mmSocket.close();
             } catch (IOException e) {
-                Log.e(TAG, "close() of connect " + mSocketType + " socket failed", e);
+                Log.e(TAG, "close() of connect socket failed", e);
             }
         }
     }
@@ -303,8 +286,8 @@ public class BluetoothChatService {
         private final InputStream mmInStream;
         private final OutputStream mmOutStream;
 
-        public ConnectedThread(BluetoothSocket socket, String socketType) {
-            Log.d(TAG, "create ConnectedThread: " + socketType);
+        public ConnectedThread(BluetoothSocket socket) {
+            Log.d(TAG, "create ConnectedThread");
             mmSocket = socket;
             InputStream tmpIn = null;
             OutputStream tmpOut = null;
@@ -333,7 +316,7 @@ public class BluetoothChatService {
                     bytes = mmInStream.read(buffer);
 
                     // Send the obtained bytes to the UI Activity
-                    mHandler.obtainMessage(AltosDroid.MESSAGE_READ, bytes, -1, buffer)
+                    mHandler.obtainMessage(AltosDroid.MESSAGE_READ, bytes, -1, buffer.clone())
                             .sendToTarget();
                 } catch (IOException e) {
                     Log.e(TAG, "disconnected", e);
@@ -350,6 +333,7 @@ public class BluetoothChatService {
         public void write(byte[] buffer) {
             try {
                 mmOutStream.write(buffer);
+                mmOutStream.write('\n');
 
                 // Share the sent message back to the UI Activity
                 mHandler.obtainMessage(AltosDroid.MESSAGE_WRITE, -1, -1, buffer)