From e45726970c547a5526d4f968b32b26ec83e612ff Mon Sep 17 00:00:00 2001
From: Kristin Muterspaw <kmmuterspaw@gmail.com>
Date: Fri, 3 Jun 2016 15:39:56 -0400
Subject: [PATCH] SensorSampleActivity nows uses SensorSampleService to do all
 communication with the sensors and writing to the database. If it's a sample
 then the Service is started, contacts the sensor, writes to the database
 once, and then the service is told to stop sampling. If it's streaming, then
 a handler is started to continuously contact and write to the database. The
 Service now uses a 'Wake Lock' which means the CPU stays on even if the
 screen is off. Can stream with screen off now.

---
 app/src/main/AndroidManifest.xml              |  19 +-
 .../edu/fieldday/BluetoothLeService.java      |  11 +-
 .../earlham/edu/fieldday/BluetoothSensor.java |  13 +-
 .../edu/fieldday/BluetoothSensorFragment.java |  22 +-
 .../edu/fieldday/SensorSampleActivity.java    | 242 ++++----
 .../edu/fieldday/SensorSampleService.java     | 552 ++++++++++++++++++
 .../cs/earlham/edu/fieldday/aSensor.java      |  46 +-
 .../main/res/layout/activity_sensorsample.xml |  21 +-
 8 files changed, 772 insertions(+), 154 deletions(-)
 create mode 100644 app/src/main/java/fieldscience/cs/earlham/edu/fieldday/SensorSampleService.java

diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ac55388..280f979 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,21 +1,25 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="fieldscience.cs.earlham.edu.fieldday" >
+    package="fieldscience.cs.earlham.edu.fieldday">
+
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
     <uses-permission android:name="android.permission.CAMERA" />
-    <uses-permission android:name="android.permission.INTERNET"/>
-    <uses-feature android:name="android.hardware.bluetooth_le"/>
-    <uses-feature android:name="android.hardware.camera2" android:required="false" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
 
+    <uses-feature android:name="android.hardware.bluetooth_le" />
+    <uses-feature
+        android:name="android.hardware.camera2"
+        android:required="false" />
     <application
         android:allowBackup="true"
         android:icon="@mipmap/ic_launcher"
         android:label="@string/app_name"
-        android:theme="@style/MainTheme" >
+        android:theme="@style/MainTheme">
         <activity
             android:name=".MainScreenActivity"
             android:label="@string/app_name"
@@ -55,9 +59,12 @@
             android:label="My Documents Viewer"
             android:theme="@style/MainTheme">
         </activity>
+
         <service
             android:name=".BluetoothLeService"
             android:enabled="true" />
+        <service
+            android:name=".SensorSampleService"
+            android:exported="false" />
     </application>
-
 </manifest>
diff --git a/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/BluetoothLeService.java b/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/BluetoothLeService.java
index d9dff8e..36ed160 100644
--- a/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/BluetoothLeService.java
+++ b/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/BluetoothLeService.java
@@ -10,8 +10,6 @@ import android.os.Binder;
 import android.os.IBinder;
 import android.util.Log;
 
-import java.util.HashMap;
-import java.util.Map;
 import java.util.UUID;
 
 public class BluetoothLeService extends Service {
@@ -46,15 +44,15 @@ public class BluetoothLeService extends Service {
     public static String CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb";
 
     private BluetoothGattService gattService;
-    private Map<UUID, String> services = new HashMap<UUID, String>();
 
     private final BluetoothSensor.Listener listener = new BluetoothSensor.Listener() {
         @Override
         public void onCharacteristicRead(UUID characteristicUUID, String data) {
             broadcastUpdate(ACTION_DATA_AVAILABLE, data);
         }
+
         @Override
-        public void onServiceInformation(){
+        public void onServiceInformation() {
             for (BluetoothGattService s : btSensor.getServices()){
                  if (s.getUuid().equals(UUID_BLE_SENSOR_SERVICE)) {
                     gattService = btSensor.getService(UUID_BLE_SENSOR_SERVICE);
@@ -88,6 +86,11 @@ public class BluetoothLeService extends Service {
         }
     }
 
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        return Service.START_STICKY;
+    }
+
     @Override
     public IBinder onBind(Intent intent) {
         return mBinder;
diff --git a/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/BluetoothSensor.java b/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/BluetoothSensor.java
index c592599..eb9858f 100644
--- a/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/BluetoothSensor.java
+++ b/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/BluetoothSensor.java
@@ -78,8 +78,11 @@ public class BluetoothSensor implements Parcelable {
     public boolean connect(Context context){
         gattClient.connect(context, device);
 
-        // This listener is used when changes happen in the GattClient class. The GattClient class
-        // is used for communication with the actual bluetooth device.
+        // This listener is used when changes happen in the GattClient class. It is implemented in
+        // the GattClient class and anytime these functions are called in that class, the listener in
+        // this class are called as well. The GattClient class is used for communication with the
+        // actual bluetooth device. This is used for talking to the BluetoothService and
+        // BluetoothSensorFragment.
         GattClient.Listener listener = new GattClient.Listener() {
             @Override
             public void onMessageReceived(byte[] data, BluetoothGattCharacteristic characteristic) {
@@ -112,18 +115,18 @@ public class BluetoothSensor implements Parcelable {
         this.mListener = listener;
     }
 
-    public static interface Listener {
+    public interface Listener {
         void onCharacteristicRead(UUID characteristicUUID, String data);
         void onServiceInformation();
     }
 
-    // Required by android Parcelable class
+    // Required by Android Parcelable class
     @Override
     public int describeContents() {
         return 0;
     }
 
-    // Required by android Parcelable class
+    // Required by Android Parcelable class
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeParcelable(device, 0);
diff --git a/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/BluetoothSensorFragment.java b/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/BluetoothSensorFragment.java
index 1c302e5..7b33995 100644
--- a/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/BluetoothSensorFragment.java
+++ b/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/BluetoothSensorFragment.java
@@ -35,6 +35,8 @@ public class BluetoothSensorFragment extends ListFragment {
     private ArrayList<aSensor> ourSensors;
     SensorFragmentCommunication callback;
 
+    private static final String TAG = BluetoothSensorFragment.class.getSimpleName();
+
     private ServiceConnection btServiceConnection = new ServiceConnection() {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
@@ -44,7 +46,7 @@ public class BluetoothSensorFragment extends ListFragment {
                 getActivity().finish();
             }
             boolean connection = btService.connect(btSensor);
-            if (!connection){
+            if (!connection) {
                 Log.e("Sensor Sample Activity", "Unable to connect to device");
             }
         }
@@ -63,16 +65,22 @@ public class BluetoothSensorFragment extends ListFragment {
 
             } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
                 btService = null;
-                btHandler.removeCallbacks(btRunner);
+                btHandler.removeCallbacksAndMessages(btRunner);
             } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
                 btService.readMessage();
-                btHandler.postDelayed(btRunner, 5000);
+                if (!registered) {
+                    Log.d(TAG, "Services Discovered.");
+                    btHandler.postDelayed(btRunner, 5000);
+                }
             } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
                 if (btService != null) {
                     if (BluetoothLeService.current_request.equals(BluetoothLeService.LIST_OF_SENSORS)) {
+                        Log.d(TAG, "Receiving List of Sensors");
                         parseResponse(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
+                        btHandler.removeCallbacksAndMessages(btRunner);
                     } else if (BluetoothLeService.current_request.equals(BluetoothLeService.SENSOR_VALUES)){
                         parseResponse(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
+                        Log.d(TAG, "Receiving updated Sensor Values");
                     }
                 }
             }
@@ -108,7 +116,6 @@ public class BluetoothSensorFragment extends ListFragment {
             @Override
             public void run() {
                 getSensorValues();
-                btHandler.postDelayed(this, senseInterval);
             }
         };
 
@@ -156,7 +163,7 @@ public class BluetoothSensorFragment extends ListFragment {
     @Override
     public void onDetach(){
         super.onDetach();
-        btHandler.removeCallbacks(btRunner);
+        btHandler.removeCallbacksAndMessages(btRunner);
         if (btService != null) {
             btService.disconnect();
             btService.close();
@@ -174,8 +181,9 @@ public class BluetoothSensorFragment extends ListFragment {
         for (int i = 1; i < tmp.length + 1; i++) {
             tx[i] = tmp[i - 1];
         }
+        Log.d(TAG, "Writing message for sensor names.");
         btService.writeMessage(tx, BluetoothLeService.LIST_OF_SENSORS);
-        btHandler.removeCallbacks(btRunner);
+        btHandler.removeCallbacksAndMessages(btRunner);
     }
 
     public void getSensorValues() {
@@ -187,11 +195,13 @@ public class BluetoothSensorFragment extends ListFragment {
         for (int i = 1; i < tmp.length + 1; i++) {
             tx[i] = tmp[i - 1];
         }
+        Log.d(TAG, "Updating Sensor Values");
         btService.writeMessage(tx, BluetoothLeService.SENSOR_VALUES);
     }
 
     public void displayData() {
         String sensor = "";
+        Log.d(TAG, "Response: " + response);
         for (int i = 0; i < response.length(); i++) {
             char c = response.charAt(i);
             if (c == ';') {
diff --git a/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/SensorSampleActivity.java b/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/SensorSampleActivity.java
index 78904c3..774050a 100644
--- a/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/SensorSampleActivity.java
+++ b/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/SensorSampleActivity.java
@@ -1,9 +1,15 @@
 package fieldscience.cs.earlham.edu.fieldday;
 
 import android.app.Activity;
-import android.app.Fragment;
-import android.app.FragmentManager;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
@@ -11,7 +17,7 @@ import android.location.Location;
 import android.location.LocationListener;
 import android.location.LocationManager;
 import android.os.Bundle;
-import android.os.Handler;
+import android.os.IBinder;
 import android.preference.PreferenceManager;
 import android.text.Editable;
 import android.text.TextWatcher;
@@ -22,18 +28,16 @@ import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
 import android.widget.EditText;
 import android.widget.ImageButton;
+import android.widget.ListView;
 import android.widget.RadioGroup;
 import android.widget.Spinner;
 import android.widget.TextView;
 import android.widget.Toast;
 
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
-import java.util.Locale;
 
-public class SensorSampleActivity extends Activity implements SensorFragmentCommunication {
+public class SensorSampleActivity extends Activity {
 
     public LocationManager locationManager;
     public LocationListener locationListener;
@@ -44,13 +48,11 @@ public class SensorSampleActivity extends Activity implements SensorFragmentComm
     public static Resources res;
     public static Spinner siteSpinner, sectorSpinner;
     public static EditText spotET;
-    public static String tripName, site, sector, spot, lastFragment;
+    public static String tripName, site, sector, spot, sensor;
     public ReadingsDatabase db;
     public RadioGroup logIntervalButton;
     public long logInterval = 5000;
     public ArrayList<aSensor> listSensors;
-    private Handler dbHandler;
-    private Runnable dbRunner;
     public Boolean streaming = false, remote_db;
     public Drawable streamOn, streamOff;
     public ImageButton exportButton, streamButton, sampleButton;
@@ -58,6 +60,46 @@ public class SensorSampleActivity extends Activity implements SensorFragmentComm
     public static final String WHICH_SENSOR = "Which Sensor";
     public static final String REMOTE_DB = "Remote DB Connected";
     BluetoothSensor bluetoothSensor;
+    private SensorSampleService sampleService;
+    private Context context;
+    private ArrayAdapter<aSensor> adapter;
+
+    private ServiceConnection sampleServiceConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            sampleService = ((SensorSampleService.LocalBinder) service).getService();
+            sampleService.connectSensor(sensor, bluetoothSensor);
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+
+        }
+    };
+
+    private final BroadcastReceiver sampleServiceReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (SensorSampleService.ACTION_CONNECTED.equals(intent.getAction())){
+                Log.d("SensorSampleActivity", "Received Connected Message!");
+                enableButtons();
+                ArrayList<aSensor> sensors = intent.getParcelableArrayListExtra(SensorSampleService.SENSOR_LIST);
+                for (aSensor s: sensors) {
+                    Log.d("SensorSampleActivity", "Sensor: " + s.getName());
+                    Log.d("SensorSampleActivity", "Sensor Value: " + s.getLastValueString());
+                }
+                adapter.clear();
+                adapter.addAll(sensors);
+                adapter.notifyDataSetChanged();
+            } else if (SensorSampleService.ACTION_UPDATED_LIST.equals(intent.getAction())) {
+                Log.d("SensorSampleActivity", "Received Updated List Message!");
+                ArrayList<aSensor> sensors = intent.getParcelableArrayListExtra(SensorSampleService.SENSOR_LIST);
+                adapter.clear();
+                adapter.addAll(sensors);
+                adapter.notifyDataSetChanged();
+            }
+        }
+    };
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -65,8 +107,14 @@ public class SensorSampleActivity extends Activity implements SensorFragmentComm
         setContentView(R.layout.activity_sensorsample);
         remote_db = getIntent().getBooleanExtra(REMOTE_DB, false);
         initializeVariables();
+        context = this;
+        listSensors = new ArrayList<aSensor>();
 
-        String sensor = getIntent().getStringExtra(WHICH_SENSOR);
+        Intent sensorServiceIntent = new Intent(this, SensorSampleService.class);
+        bindService(sensorServiceIntent, sampleServiceConnection, Context.BIND_AUTO_CREATE);
+        registerReceiver(sampleServiceReceiver, makeSensorUpdateFilter());
+
+        sensor = getIntent().getStringExtra(WHICH_SENSOR);
         if (sensor.equals("bluetooth")){
             bluetoothSensor = getIntent().getParcelableExtra(DEVICE);
             streamButton.setImageDrawable(res.getDrawable(R.drawable.stream_unavailable, null));
@@ -74,17 +122,11 @@ public class SensorSampleActivity extends Activity implements SensorFragmentComm
             sampleButton.setClickable(false);
             streamButton.setClickable(false);
         }
-        lastFragment = sensor;
-        displaySensor(sensor);
 
-        dbHandler = new Handler();
-        dbRunner = new Runnable() {
-            @Override
-            public void run() {
-                writeToDB();
-                dbHandler.postDelayed(this, logInterval);
-            }
-        };
+        ListView mSensors = (ListView) findViewById(android.R.id.list);
+        adapter = new SensorListAdapter(this, listSensors);
+        mSensors.setAdapter(adapter);
+        Intent i = new Intent(context, SensorSampleService.class);
 
         logIntervalButton.setOnClickListener(new View.OnClickListener() {
             @Override
@@ -99,22 +141,20 @@ public class SensorSampleActivity extends Activity implements SensorFragmentComm
                 if (!streaming) {
                     streamButton.setImageDrawable(streamOn);
                     streaming = true;
-                    writeToDB();
-                    if (lastFragment.equals("bluetooth")){
-                        BluetoothSensorFragment bt = (BluetoothSensorFragment)
-                                getFragmentManager().findFragmentByTag("bluetooth");
-                        bt.sensingControl(true, logInterval);
-                    }
-                    dbHandler.postDelayed(dbRunner, logInterval);
+
+                    // Start the SensorSampleService supplying the type of sensor connected --
+                    // bluetooth or built-in and the logging interval to use.
+                    Intent i = new Intent(context, SensorSampleService.class);
+                    i.putExtra(SensorSampleService.LOG_INTERVAL, logInterval);
+                    i.putExtra(SensorSampleService.SAMPLE_ONCE, false);
+                    i.putExtra(SensorSampleService.TRIP_NAME, tripName);
+                    startService(i);
                 } else {
                     streamButton.setImageDrawable(streamOff);
-                    dbHandler.removeCallbacks(dbRunner);
                     streaming = false;
-                    if (lastFragment.equals("bluetooth")){
-                        BluetoothSensorFragment bt = (BluetoothSensorFragment)
-                                getFragmentManager().findFragmentByTag("bluetooth");
-                        bt.sensingControl(false, 0);
-                    }
+                    sampleService.stopSampling();
+                    Intent i = new Intent(context, SensorSampleService.class);
+                    stopService(i);
                 }
             }
         });
@@ -138,11 +178,34 @@ public class SensorSampleActivity extends Activity implements SensorFragmentComm
                     t.setGravity(Gravity.CENTER, 0, 0);
                     t.show();
                 } else if (!db.addSpot(tripName, site, sector, spot)) {
-                    Toast t = Toast.makeText(SensorSampleActivity.this, "The Spot number breaks the primary keys of the database. Please insert a new spot.", Toast.LENGTH_LONG);
-                    t.setGravity(Gravity.CENTER, 0, 0);
-                    t.show();
+                    Dialog d = new AlertDialog.Builder(SensorSampleActivity.this, AlertDialog.THEME_HOLO_LIGHT)
+                            .setTitle("Are you sure?")
+                            .setMessage("There's already a spot with this trip, site, and sector. Make sure you are at the same geolocation that is " +
+                                    "associated with this spot.")
+                            .setNegativeButton("Change Spot", null)
+                            .setPositiveButton("I'm sure.", new DialogInterface.OnClickListener() {
+                                @Override
+                                public void onClick(DialogInterface dialog, int which) {
+                                    Intent i = new Intent(context, SensorSampleService.class);
+                                    i.putExtra(SensorSampleService.LOG_INTERVAL, logInterval);
+                                    i.putExtra(SensorSampleService.SAMPLE_ONCE, true);
+                                    i.putExtra(SensorSampleService.TRIP_NAME, tripName);
+                                    i.putExtra(SensorSampleService.SITE, site);
+                                    i.putExtra(SensorSampleService.SECTOR, sector);
+                                    i.putExtra(SensorSampleService.SPOT, spot);
+                                    startService(i);
+                                }
+                            }).create();
+                    d.show();
                 } else {
-                    writeToDB();
+                    Intent i = new Intent(context, SensorSampleService.class);
+                    i.putExtra(SensorSampleService.LOG_INTERVAL, logInterval);
+                    i.putExtra(SensorSampleService.SAMPLE_ONCE, true);
+                    i.putExtra(SensorSampleService.TRIP_NAME, tripName);
+                    i.putExtra(SensorSampleService.SITE, site);
+                    i.putExtra(SensorSampleService.SECTOR, sector);
+                    i.putExtra(SensorSampleService.SPOT, spot);
+                    startService(i);
                 }
             }
         });
@@ -161,102 +224,43 @@ public class SensorSampleActivity extends Activity implements SensorFragmentComm
     }
 
     @Override
-    protected void onPause(){
+    protected void onPause() {
         super.onPause();
     }
 
     @Override
-    protected void onStop(){
+    protected void onStop() {
         super.onStop();
-        dbHandler.removeCallbacks(dbRunner);
     }
 
     @Override
-    protected void onDestroy(){
+    protected void onDestroy() {
         super.onDestroy();
         locationManager.removeUpdates(locationListener);
-        dbHandler.removeCallbacks(dbRunner);
-    }
-
-    public void displaySensor(String sensor) {
-        FragmentManager fragMan = getFragmentManager();
-        Fragment frag = fragMan.findFragmentById(R.id.sensor_container);
-        switch (sensor) {
-            case "built-in":
-                frag = new BuiltInSensorsFragment();
-                fragMan.beginTransaction()
-                        .add(R.id.sensor_container, frag, sensor)
-                        .addToBackStack(null)
-                        .commit();
-                break;
-            case "bluetooth":
-                BluetoothSensorFragment btf = BluetoothSensorFragment.newInstance(bluetoothSensor);
-                fragMan.beginTransaction()
-                        .add(R.id.sensor_container, btf, sensor)
-                        .addToBackStack(null)
-                        .commit();
-                break;
+        if (sampleService != null) {
+            sampleService.stopSelf();
         }
-        lastFragment = sensor;
-    }
-
-    public String getTimestamp(){
-        long seconds = System.currentTimeMillis() / 1000;
-        //return seconds;
-
-        SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss", Locale.ENGLISH);
-        return s.format(new Date());
-    }
-
-    public void writeToDB() {
-        double[] geoInfo = {lastLatitude, lastLongitude, lastElevation};
-        boolean success = false;
-        String message = "";
-        // The user has connected and downloaded data from a remote database
-        if (remote_db) {
-            for (aSensor sensor : listSensors) {
-                if (sensor.getLastValues() != null) {
-                    String table = "";
-                    if (streaming) {
-                        table = "fieldday_streaming";
-                        db.addReading(sensor, sensor.getLastValues()[0], sensor.getLastValueQuality(), getTimestamp(),
-                                site, sector, spot, geoInfo, tripName, lastAccuracy, lastSatellites, "", "", table);
-                    } else {
-                        table = "fieldday_reading";
-                        success = db.addReading(sensor, sensor.getLastValues()[0], sensor.getLastValueQuality(), getTimestamp(),
-                                site, sector, spot, geoInfo, tripName, lastAccuracy, lastSatellites, "", "", table);
-                        message = "";
-                        if (success) {
-                            message = "Successfully took a sample";
-                        } else {
-                            message = "Could not write to the database. Try again.";
-                        }
-                    }
-                }
-            }
-            if (success){
-                Toast t = Toast.makeText(SensorSampleActivity.this, message, Toast.LENGTH_SHORT);
-                t.setGravity(Gravity.CENTER, 0, 0);
-                t.show();
-            }
-        } else {
-            Toast t = Toast.makeText(SensorSampleActivity.this, "You can't write to the database without connecting a remote schema", Toast.LENGTH_SHORT);
-            t.setGravity(Gravity.CENTER, 0, 0);
-            t.show();
+        if (sampleServiceConnection != null){
+            unregisterReceiver(sampleServiceReceiver);
+            unbindService(sampleServiceConnection);
         }
     }
 
-    public void setSensorList(ArrayList<aSensor> sensorList){
-        listSensors = sensorList;
-    }
-
-    public void enableButtons(){
+    public void enableButtons() {
         streamButton.setClickable(true);
         sampleButton.setClickable(true);
         streamButton.setImageDrawable(res.getDrawable(R.drawable.stream_button, null));
         sampleButton.setImageDrawable(res.getDrawable(R.drawable.sample_button, null));
     }
 
+    private static IntentFilter makeSensorUpdateFilter() {
+        final IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(SensorSampleService.ACTION_UPDATED_LIST);
+        intentFilter.addAction(SensorSampleService.ACTION_CONNECTED);
+        intentFilter.addAction(SensorSampleService.ACTION_DISCONNECTED);
+        return intentFilter;
+    }
+
     public class myLocationListener implements LocationListener {
         @Override
         public void onLocationChanged(Location location) {
@@ -294,14 +298,10 @@ public class SensorSampleActivity extends Activity implements SensorFragmentComm
                 logInterval = 1000 * 60;
                 break;
         }
-        dbHandler.removeCallbacks(dbRunner);
-        if (streaming) {
-            dbHandler.postDelayed(dbRunner, logInterval);
-        }
         Log.d("Changing Interval", "New Interval Time: " + String.valueOf(logInterval));
     }
 
-    public void exportDatabase(){
+    public void exportDatabase() {
         boolean success = db.copyDatabase("");
         if (success){
             Toast.makeText(this, "Successfully copied the database", Toast.LENGTH_LONG).show();
@@ -310,7 +310,7 @@ public class SensorSampleActivity extends Activity implements SensorFragmentComm
         }
     }
 
-    public void setLocation(Location location){
+    public void setLocation(Location location) {
         if (location != null) {
             lastLongitude = location.getLongitude();
             lastLatitude = location.getLatitude();
@@ -324,7 +324,7 @@ public class SensorSampleActivity extends Activity implements SensorFragmentComm
         }
     }
 
-    private void initializeVariables(){
+    private void initializeVariables() {
         res = getResources();
         longAndLat = (TextView) findViewById(R.id.longandlat);
         satellites = (TextView) findViewById(R.id.satellites);
diff --git a/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/SensorSampleService.java b/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/SensorSampleService.java
new file mode 100644
index 0000000..5d09997
--- /dev/null
+++ b/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/SensorSampleService.java
@@ -0,0 +1,552 @@
+package fieldscience.cs.earlham.edu.fieldday;
+
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.util.Log;
+import android.view.Gravity;
+import android.widget.Toast;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+public class SensorSampleService extends Service implements SensorEventListener {
+
+    private BluetoothLeService btService;
+    private String sensorType, response;
+    private boolean sampleOnce, registered = false, writingToDB = false;
+    private long loggingInterval;
+    private Handler dbHandler, btHandler;
+    private Runnable dbRunner, btRunNames, builtinListRunner;
+    private BluetoothSensor bluetoothSensor;
+    private ArrayList<aSensor> sensorList;
+    public ReadingsDatabase db;
+    private SensorManager mSensorManager;
+    private LocationManager locationManager;
+    private LocationListener locationListener;
+    private List<Sensor> builtinList;
+    public static double lastLongitude, lastLatitude, lastElevation;
+    public static int lastSatellites;
+    public static float lastAccuracy;
+    public static String tripName, site, sector, spot;
+    private PowerManager.WakeLock mWakeLock;
+
+    // These are used in the Intent that SensorSampleActivity creates to start the Service.
+    public static final String SENSOR_TYPE = "Sensor Type";
+    public static final String LOG_INTERVAL = "Logging Interval";
+    public static final String SAMPLE_ONCE = "Sample or Streaming";
+    public static final String SENSOR_LIST = "List of Sensors";
+    public static final String TRIP_NAME = "Name of Trip";
+    public static final String SITE = "Name of Site";
+    public static final String SECTOR = "Name of Sector";
+    public static final String SPOT = "Spot Number";
+    public static final String BT_SENSOR = "Bluetooth Sensor";
+
+    public static final String ACTION_CONNECTED = "Connected.";
+    public static final String ACTION_UPDATED_LIST = "Updated Sensor List.";
+    public static final String ACTION_DISCONNECTED = "Disconnect";
+
+    private static final String TAG = "SensorSampleService";
+
+    private ServiceConnection btServiceConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            btService = ((BluetoothLeService.LocalBinder) service).getService();
+            if (!btService.initialize()) {
+                Log.e(TAG, "Bluetooth Stopped Running");
+                stopSelf();
+            }
+            btService.connect(bluetoothSensor);
+            Log.d(TAG, "Bound to Bluetooth Service");
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            btService = null;
+            dbHandler.removeCallbacks(dbRunner);
+        }
+    };
+
+
+    private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
+            } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
+                btService = null;
+                dbHandler.removeCallbacksAndMessages(dbRunner);
+            } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
+                btService.readMessage();
+                btHandler.postDelayed(btRunNames, 5000);
+                btHandler.removeCallbacksAndMessages(btRunNames);
+            } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {
+                if (btService != null) {
+                    if (BluetoothLeService.current_request.equals(BluetoothLeService.LIST_OF_SENSORS)) {
+                        Log.d(TAG, "List of Sensors from device.");
+                        parseResponse(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
+                    } else if (BluetoothLeService.current_request.equals(BluetoothLeService.SENSOR_VALUES)){
+                        Log.d(TAG, "Receiving Message");
+                        parseResponse(intent.getStringExtra(BluetoothLeService.EXTRA_DATA));
+                    }
+                }
+            }
+        }
+    };
+
+    // Broadcasting updated to SensorSampleActivity
+    private void broadcastUpdate(final String action) {
+        final Intent intent = new Intent(action);
+        intent.putParcelableArrayListExtra(SENSOR_LIST, sensorList);
+        sendBroadcast(intent);
+        Log.d(TAG, "Sending Message Back to Activity.");
+    }
+
+    public class LocalBinder extends Binder {
+            public SensorSampleService getService() { return SensorSampleService.this; }
+    }
+
+    @Override
+    public void onCreate() {
+
+        btHandler = new Handler();
+        btRunNames = new Runnable() {
+            @Override
+            public void run() {
+                getSensorNames();
+            }
+        };
+
+        builtinList = new ArrayList<Sensor>();
+
+        dbHandler = new Handler();
+        dbRunner = new Runnable() {
+            @Override
+            public void run() {
+                getSensorValues();
+                dbHandler.postDelayed(this, loggingInterval);
+            }
+        };
+
+        builtinListRunner = new Runnable() {
+            @Override
+            public void run() {
+                writeToDB();
+                dbHandler.postDelayed(this, loggingInterval);
+            }
+        };
+
+        response = "";
+
+        sensorList = new ArrayList<aSensor>();
+
+        db = ReadingsDatabase.getInstance(this);
+        locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
+        locationListener = new myLocationListener();
+        setLocation(locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER));
+        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, locationListener);
+    }
+
+    public class myLocationListener implements LocationListener {
+        @Override
+        public void onLocationChanged(Location location) {
+            setLocation(location);
+        }
+
+        @Override
+        public void onStatusChanged(String provider, int status, Bundle extras) {
+        }
+
+        @Override
+        public void onProviderEnabled(String provider) {
+        }
+
+        @Override
+        public void onProviderDisabled(String provider) {
+        }
+    }
+
+    public void setLocation(Location location){
+        if (location != null) {
+            lastLongitude = location.getLongitude();
+            lastLatitude = location.getLatitude();
+            lastElevation = location.getAltitude();
+            lastAccuracy = location.getAccuracy();
+            lastSatellites = location.getExtras().getInt("satellites");
+        }
+    }
+
+    // This is called when another activity or component called startService with the class as the
+    // intent
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        super.onStartCommand(intent, flags, startId);
+        Log.d(TAG, "Starting service.");
+
+        // Set the sensor type and the logging interval from the activity that started the service
+        loggingInterval = intent.getExtras().getLong(LOG_INTERVAL);
+        sampleOnce = intent.getExtras().getBoolean(SAMPLE_ONCE);
+        tripName = intent.getExtras().getString(TRIP_NAME);
+        site = intent.getExtras().getString(SITE);
+        sector = intent.getExtras().getString(SECTOR);
+        spot = intent.getExtras().getString(SPOT);
+        dbHandler = new Handler();
+
+        writingToDB = true;
+        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
+        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Sampling wake lock");
+        mWakeLock.acquire();
+
+        switch (sensorType){
+            case "bluetooth":
+                if (sampleOnce){
+                    getSensorValues();
+                } else {
+                    dbHandler.postDelayed(dbRunner, loggingInterval);
+                }
+                break;
+            case "built-in":
+                if (sampleOnce){
+                    writeToDB();
+                } else {
+                    dbHandler.postDelayed(builtinListRunner, loggingInterval);
+                }
+                break;
+        }
+
+        // START_STICKY means that the service continues running until something outside tells it
+        // to stop. START_NOT_STICKY the service would stop when there's no more work to do.
+        return Service.START_STICKY;
+    }
+
+    private static IntentFilter makeGattUpdateIntentFilter() {
+        final IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
+        intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
+        intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
+        intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
+        return intentFilter;
+    }
+
+   @Override
+    public IBinder onBind(Intent intent){ return mBinder; }
+
+    @Override
+    public boolean onUnbind(Intent intent){
+        return super.onUnbind(intent);
+    }
+
+    @Override
+    public void onDestroy() {
+        if (btService != null) {
+            unregisterReceiver(mGattUpdateReceiver);
+            btService.disconnect();
+            btHandler.removeCallbacksAndMessages(btRunNames);
+            btService.close();
+            unbindService(btServiceConnection);
+        }
+        if (dbHandler != null) {
+            dbHandler.removeCallbacksAndMessages(dbRunner);
+        }
+        for (Sensor s : builtinList) {
+            mSensorManager.unregisterListener(this, s);
+        }
+    }
+
+    public void stopSampling() {
+        dbHandler.removeMessages(0);
+        dbHandler.removeCallbacksAndMessages(dbRunner);
+        dbHandler = null;
+        mWakeLock.release();
+    }
+
+    private final IBinder mBinder = new LocalBinder();
+
+    public void parseResponse(String d){
+        response += d;
+        if (response.endsWith("done")) {
+            if (BluetoothLeService.current_request.equals(BluetoothLeService.LIST_OF_SENSORS)) {
+                updateSensorList();
+            } else {
+                updateSensorValues();
+            }
+        }
+    }
+
+    public void updateSensorList() {
+        String sensor = "";
+        if (!registered) {
+            for (int i = 0; i < response.length(); i++) {
+                char c = response.charAt(i);
+                if (c == ';') {
+                    String delims = "[,]";
+                    String[] tokens = sensor.split(delims);
+                    aSensor sens = new aSensor(tokens[1], tokens[0]);
+                    sens.setPlatform(bluetoothSensor.getDeviceName());
+                    Log.d(TAG, sens.getName());
+                    sensorList.add(sens);
+                    sensor = "";
+                } else {
+                    sensor += c;
+                }
+            }
+            btHandler.removeCallbacksAndMessages(btRunNames);
+            getSensorValues();
+        }
+        response = "";
+    }
+
+    public void updateSensorValues() {
+        String sensor = "";
+        for (int i = 0; i < response.length(); i++) {
+            char c = response.charAt(i);
+            if (c == ';') {
+                String delims = "[,]";
+                String[] tokens = sensor.split(delims);
+                aSensor sens = getSensor(tokens[1], null);
+                float[] value = {0, 0};
+                value[0] = Float.parseFloat(tokens[2]);
+                sens.setLastValue(value, 1);
+                sens.setLastValueQuality(0);
+                Log.d(TAG, "Sensor Value: " + sens.getLastValueString());
+                Log.d(TAG, "Sensor Name: " + sens.getName());
+                sensor = "";
+            } else {
+                sensor += c;
+            }
+        }
+        if (registered){
+            if (writingToDB) {
+                writeToDB();
+            }
+            broadcastUpdate(ACTION_UPDATED_LIST);
+        } else {
+            registered = true;
+            broadcastUpdate(ACTION_CONNECTED);
+        }
+        response = "";
+    }
+
+    public void connectSensor(String sensor, BluetoothSensor btSensor) {
+        sensorType = sensor;
+        if (sensor.equals("bluetooth")){
+            bluetoothSensor = btSensor;
+            Intent i = new Intent(this, BluetoothLeService.class);
+            bindService(i, btServiceConnection, Context.BIND_AUTO_CREATE);
+            registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter());
+            Log.d(TAG, "Starting Bluetooth Service");
+        } else {
+            mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
+            builtinList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
+
+            for (Sensor s : builtinList){
+                mSensorManager.registerListener(this, s, 100000000);
+            }
+
+            for (int i=0; i<builtinList.size(); i++) {
+                aSensor sens = new aSensor(builtinList.get(i));
+                // This is to figure out which sensors are uncalibrated
+                String delims = "[ .]+";
+                String[] tokens = sens.getStringType().split(delims);
+                sens.setName(tokens[2]);
+                sensorList.add(sens);
+            }
+        }
+    }
+
+    public void getSensorNames() {
+        String getSensors = "00";
+        byte b = 0x00;
+        byte[] tmp = getSensors.getBytes();
+        byte[] tx = new byte[tmp.length + 1];
+        tx[0] = b;
+        for (int i = 1; i < tmp.length + 1; i++) {
+            tx[i] = tmp[i - 1];
+        }
+        Log.d(TAG, "Writing message for sensor names.");
+        btService.writeMessage(tx, BluetoothLeService.LIST_OF_SENSORS);
+        btHandler.removeCallbacksAndMessages(btRunNames);
+    }
+
+    public aSensor getSensor(String sensorID, Sensor sensor) {
+        for (aSensor s : sensorList) {
+            if (sensorType.equals("bluetooth")) {
+                String aSensorID = s.getID();
+                if (sensorID.equals(aSensorID)) {
+                    return s;
+                }
+            } else {
+                String sensorType = sensor.getStringType();
+                String aSensorType = s.getStringType();
+                if (sensorType.equals(aSensorType)) {
+                    return s;
+                }
+            }
+        }
+        return null;
+    }
+
+    public void writeToDB(){
+        double[] geoInfo = {lastLatitude, lastLongitude, lastElevation};
+        boolean success = false;
+        String message = "";
+        // The user has connected and downloaded data from a remote database
+        for (aSensor sensor : sensorList) {
+            if (sensor.getLastValues() != null) {
+                String table = "";
+                if (!sampleOnce) {
+                    table = "fieldday_streaming";
+                    db.addReading(sensor, sensor.getLastValues()[0], sensor.getLastValueQuality(), getTimestamp(),
+                            site, sector, spot, geoInfo, tripName, lastAccuracy, lastSatellites, "", "", table);
+                } else {
+                    table = "fieldday_reading";
+                    success = db.addReading(sensor, sensor.getLastValues()[0], sensor.getLastValueQuality(), getTimestamp(),
+                            site, sector, spot, geoInfo, tripName, lastAccuracy, lastSatellites, "", "", table);
+                    message = "";
+                    if (success) {
+                        message = "Successfully took a sample";
+                    } else {
+                        message = "Could not write to the database. Try again.";
+                    }
+                    stopSelf();
+                    dbHandler.removeCallbacksAndMessages(dbRunner);
+                }
+            }
+            if (success) {
+                Toast t = Toast.makeText(SensorSampleService.this, message, Toast.LENGTH_SHORT);
+                t.setGravity(Gravity.CENTER, 0, 0);
+                t.show();
+            }
+        }
+    }
+
+    public String getTimestamp(){
+        SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss", Locale.ENGLISH);
+        return s.format(new Date());
+    }
+
+    public void getSensorValues() {
+        String getSensors = "vals";
+        byte b = 0x00;
+        byte[] tmp = getSensors.getBytes();
+        byte[] tx = new byte[tmp.length + 1];
+        tx[0] = b;
+        for (int i = 1; i < tmp.length + 1; i++) {
+            tx[i] = tmp[i - 1];
+        }
+        btService.writeMessage(tx, BluetoothLeService.SENSOR_VALUES);
+        Log.d(TAG, "Writing Sensor Values");
+    }
+
+    @Override
+    public final void onAccuracyChanged(Sensor sensor, int accuracy) {
+        // Do something here if sensor accuracy changes.
+    }
+
+    @Override
+    public final void onSensorChanged(SensorEvent event) {
+        Sensor sensor = event.sensor;
+        aSensor sens = getSensor(null, sensor);
+        float[] values = event.values;
+        switch (sensor.getType()) {
+            case Sensor.TYPE_ACCELEROMETER:
+                sens.setLastValue(values, 3);
+                sens.setID("and1");
+                break;
+            case Sensor.TYPE_AMBIENT_TEMPERATURE:
+                sens.setLastValue(values, 3);
+                sens.setID("and2");
+                break;
+            case Sensor.TYPE_GAME_ROTATION_VECTOR:
+                sens.setLastValue(values, 3);
+                sens.setID("and3");
+                break;
+            case Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR:
+                sens.setLastValue(values, 3);
+                sens.setID("and4");
+                break;
+            case Sensor.TYPE_GRAVITY:
+                sens.setLastValue(values, 3);
+                sens.setUnits("r");
+                sens.setID("and5");
+                break;
+            case Sensor.TYPE_GYROSCOPE:
+                sens.setLastValue(values, 3);
+                sens.setID("and6");
+                break;
+            case Sensor.TYPE_GYROSCOPE_UNCALIBRATED:
+                sens.setLastValue(values, 3);
+                sens.setID("and7");
+                break;
+            case Sensor.TYPE_HEART_RATE:
+                sens.setLastValue(values, 3);
+                sens.setID("and8");
+                break;
+            case Sensor.TYPE_LIGHT:
+                sens.setLastValue(values, 1);
+                sens.setID("and9");
+                break;
+            case Sensor.TYPE_LINEAR_ACCELERATION:
+                sens.setLastValue(values, 3);
+                sens.setID("and10");
+                break;
+            case Sensor.TYPE_MAGNETIC_FIELD:
+                sens.setLastValue(values, 3);
+                sens.setID("and11");
+                break;
+            case Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED:
+                sens.setLastValue(values, 3);
+                sens.setID("and12");
+                break;
+            case Sensor.TYPE_PRESSURE:
+                sens.setLastValue(values, 3);
+                sens.setID("and13");
+                break;
+            case Sensor.TYPE_PROXIMITY:
+                sens.setLastValue(values, 3);
+                sens.setID("and14");
+                break;
+            case Sensor.TYPE_RELATIVE_HUMIDITY:
+                sens.setLastValue(values, 3);
+                sens.setID("and15");
+                break;
+            case Sensor.TYPE_ROTATION_VECTOR:
+                sens.setLastValue(values, 3);
+                sens.setID("and16");
+                break;
+            case Sensor.TYPE_SIGNIFICANT_MOTION:
+                sens.setLastValue(values, 3);
+                sens.setID("and17");
+                break;
+            case Sensor.TYPE_STEP_COUNTER:
+                sens.setLastValue(values, 3);
+                sens.setID("and18");
+                break;
+            case Sensor.TYPE_STEP_DETECTOR:
+                sens.setLastValue(values, 3);
+                sens.setID("and19");
+                break;
+        }
+        sens.setLastValueQuality(0);
+        broadcastUpdate(ACTION_UPDATED_LIST);
+    }
+}
diff --git a/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/aSensor.java b/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/aSensor.java
index ace716b..305b643 100644
--- a/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/aSensor.java
+++ b/app/src/main/java/fieldscience/cs/earlham/edu/fieldday/aSensor.java
@@ -1,15 +1,16 @@
 package fieldscience.cs.earlham.edu.fieldday;
 
 import android.hardware.Sensor;
+import android.os.Parcel;
+import android.os.Parcelable;
 
-public class aSensor {
+public class aSensor implements Parcelable {
 
     private float[] lastValues;
     private float quality;
     private Integer numberValues;
     private String type, platform, name, id, units;
     private Sensor sensor;
-    private ReadingsDatabase db;
 
     // Using Built In sensors
     public aSensor(Sensor s) {
@@ -30,6 +31,17 @@ public class aSensor {
         numberValues = 1;
     }
 
+    // Created from Parcel
+    public aSensor(String sensorID, String name, float[] values, float quality, String platform){
+        id = sensorID;
+        this.name = name;
+        type = name;
+        lastValues = values;
+        this.quality = quality;
+        numberValues = 1;
+        this.platform = platform;
+    }
+
     public String toString() {
         return sensor.toString();
     }
@@ -90,5 +102,35 @@ public class aSensor {
         name = sensorName;
     }
 
+    // Required by Android Parcelable class
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    // Required by Android Parcelable class
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(id);
+        dest.writeString(name);
+        dest.writeFloatArray(lastValues);
+        dest.writeFloat(quality);
+        dest.writeString(platform);
+    }
+
+    public static final Parcelable.Creator<aSensor> CREATOR = new Parcelable.Creator<aSensor>() {
+        public aSensor createFromParcel(Parcel in) {
+            String sensorID = in.readString();
+            String sensorName = in.readString();
+            float[] values = in.createFloatArray();
+            float quality = in.readFloat();
+            String platform = in.readString();
+            return new aSensor(sensorID, sensorName, values, quality, platform);
+        }
+        public aSensor[] newArray(int size) {
+            return new aSensor[size];
+        }
+    };
+
 }
 
diff --git a/app/src/main/res/layout/activity_sensorsample.xml b/app/src/main/res/layout/activity_sensorsample.xml
index 81dabcc..bf375ee 100644
--- a/app/src/main/res/layout/activity_sensorsample.xml
+++ b/app/src/main/res/layout/activity_sensorsample.xml
@@ -133,15 +133,16 @@
             android:text="@string/sixtySeconds" />
     </RadioGroup>
 
-    <FrameLayout
-        android:layout_width="match_parent"
-        android:id="@+id/sensor_container"
-        android:paddingTop="10dp"
-        android:layout_height="550dp"
-        android:layout_marginTop="65dp"
-        android:layout_alignParentStart="true"
-        android:layout_below="@id/site">
-    </FrameLayout>
+    <ListView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="330dp"
+        android:layout_marginStart="4dp"
+        android:layout_height="match_parent"
+        android:id="@android:id/list"
+        android:layout_weight="0.90"
+        android:layout_gravity="start"
+        android:layout_below="@+id/interval"
+        android:layout_above="@+id/streamButton">
+    </ListView>
 
     <ImageButton
         android:id="@+id/exportDbButton"
@@ -151,7 +152,7 @@
         android:contentDescription="@string/export"
         android:src="@drawable/export_button"
         android:layout_marginTop="48dp"
-        android:layout_below="@+id/sensor_container"
+        android:layout_below="@android:id/list"
         android:layout_alignEnd="@+id/accuracy" />
 
     <ImageButton
-- 
GitLab