diff --git a/.idea/assetWizardSettings.xml b/.idea/assetWizardSettings.xml new file mode 100644 index 0000000..80f880e --- /dev/null +++ b/.idea/assetWizardSettings.xml @@ -0,0 +1,46 @@ + + + + + + \ No newline at end of file diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser new file mode 100644 index 0000000..c0a1d75 Binary files /dev/null and b/.idea/caches/build_file_checksums.ser differ diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..15a15b2 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index cfe4315..ee635a3 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -3,9 +3,11 @@ diff --git a/.idea/misc.xml b/.idea/misc.xml index ba7052b..37a7509 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,30 +1,6 @@ - - - - - + diff --git a/.idea/modules.xml b/.idea/modules.xml index 9a8c334..cd6d7b7 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,7 +2,7 @@ - + diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index df965fe..cab69e3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,7 +1,8 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 28 + compileSdkVersion 29 + buildToolsVersion '29.0.2' defaultConfig { applicationId "de.fhws.indoor.sensorreadout" @@ -20,10 +21,13 @@ android { } dependencies { + implementation 'com.android.support:design:23.4.0' compile fileTree(include: ['*.jar'], dir: 'libs') testCompile 'junit:junit:4.12' - compile 'com.android.support:appcompat-v7:23.4.0' - compile 'com.google.android.gms:play-services:10.2.0' + implementation 'com.android.support:appcompat-v7:23.4.0' + implementation 'com.google.android.gms:play-services:10.2.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' + implementation 'org.apmem.tools:layouts:1.10@aar' //compile 'com.google.android.support:wearable:1.3.0' //compile 'com.google.android.gms:play-services-wearable:8.4.0' //provided 'com.google.android.wearable:wearable:1.0.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6c5724c..de7f3dc 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,10 +1,7 @@ - > - - @@ -13,8 +10,7 @@ - - + @@ -24,6 +20,8 @@ android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@style/AppTheme"> + + diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/MainActivity.java b/app/src/main/java/de/fhws/indoor/sensorreadout/MainActivity.java index 85d8e34..e8e6cb5 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/MainActivity.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/MainActivity.java @@ -4,59 +4,64 @@ import android.Manifest; import android.app.Activity; import android.app.ActivityManager; import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; import android.content.res.Configuration; -import android.graphics.Color; import android.media.MediaPlayer; import android.os.Build; import android.os.Bundle; +import android.os.SystemClock; +import android.preference.PreferenceManager; import android.support.v4.app.ActivityCompat; -import android.support.v4.content.pm.ActivityInfoCompat; //import android.support.wearable.activity.WearableActivity; import android.util.Log; import android.view.View; import android.widget.ArrayAdapter; import android.widget.Button; -import android.widget.LinearLayout; import android.widget.Spinner; +import android.widget.TableLayout; +import android.widget.TableRow; import android.widget.TextView; import android.widget.Toast; import android.view.ViewGroup.LayoutParams; -import com.google.android.gms.vision.text.Line; - import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Set; -import de.fhws.indoor.sensorreadout.sensors.Gps; import de.fhws.indoor.sensorreadout.sensors.GpsNew; import de.fhws.indoor.sensorreadout.sensors.GroundTruth; import de.fhws.indoor.sensorreadout.sensors.Logger; +import de.fhws.indoor.sensorreadout.sensors.LoggerRAM; import de.fhws.indoor.sensorreadout.sensors.PedestrianActivity; import de.fhws.indoor.sensorreadout.sensors.PedestrianActivityButton; import de.fhws.indoor.sensorreadout.sensors.PhoneSensors; import de.fhws.indoor.sensorreadout.sensors.WiFi; -import de.fhws.indoor.sensorreadout.sensors.WiFiRTT; import de.fhws.indoor.sensorreadout.sensors.iBeacon; -import de.fhws.indoor.sensorreadout.sensors.iBeaconOld; import de.fhws.indoor.sensorreadout.sensors.mySensor; import de.fhws.indoor.sensorreadout.sensors.SensorType; public class MainActivity extends Activity { + MediaPlayer mpStart; + MediaPlayer mpStop; + MediaPlayer mpGround; + MediaPlayer mpFailure; + private final ArrayList sensors = new ArrayList(); - private final Logger logger = new Logger(this); + //private final Logger logger = new Logger(this); + private final LoggerRAM logger = new LoggerRAM(this); private Button btnStart; private Button btnStop; private Button btnGround; - private PedestrianActivityButton btnWalk; - private PedestrianActivityButton btnStand; - private PedestrianActivityButton btnStairsUp; - private PedestrianActivityButton btnStairsDown; - private PedestrianActivityButton btnElevatorUp; - private PedestrianActivityButton btnElevatorDown; - private PedestrianActivity currentPedestrianActivity; - private PedestrianActivity pastPedestrianActivity; + private Button btnSettings; + private TableLayout activityButtonContainer; + private HashMap activityButtons = new HashMap<>(); + private PedestrianActivity currentPedestrianActivity = PedestrianActivity.STANDING; private int groundTruthCounter = 0; private boolean isInitialized = false; @@ -71,10 +76,18 @@ public class MainActivity extends Activity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + // This static call will reset default values for preferences only on the first ever read + PreferenceManager.setDefaultValues(getBaseContext(), R.xml.preferences, false); // context access MainActivity.context = getApplicationContext(); + // setup sound-effects + mpStart = MediaPlayer.create(this, R.raw.go); + mpStop = MediaPlayer.create(this, R.raw.go); + mpGround = MediaPlayer.create(this, R.raw.go); + mpFailure = MediaPlayer.create(this, R.raw.error); + //init Path spinner final Spinner pathSpinner = (Spinner) findViewById(R.id.pathspinner); List pathList = new ArrayList(); @@ -101,31 +114,15 @@ public class MainActivity extends Activity { btnStart = (Button) findViewById(R.id.btnStart); btnStop = (Button) findViewById(R.id.btnStop); btnGround = (Button) findViewById(R.id.btnGround); - - //get activity Buttons - btnWalk = new PedestrianActivityButton((LinearLayout) findViewById(R.id.btnWalk), PedestrianActivity.WALK); - btnStand = new PedestrianActivityButton((LinearLayout) findViewById(R.id.btnStanding), PedestrianActivity.STANDING); - btnStairsUp = new PedestrianActivityButton((LinearLayout) findViewById(R.id.btnStairsUp), PedestrianActivity.STAIRS_UP); - btnStairsDown = new PedestrianActivityButton((LinearLayout) findViewById(R.id.btnStairsDown), PedestrianActivity.STAIRS_DOWN); - btnElevatorUp = new PedestrianActivityButton((LinearLayout) findViewById(R.id.btnElevatorUp), PedestrianActivity.ELEVATOR_UP); - btnElevatorDown = new PedestrianActivityButton((LinearLayout) findViewById(R.id.btnElevatorDown), PedestrianActivity.ELEVATOR_DOWN); - - //set current activity - btnStand.toggleActivity(); //first activity is standing! - currentPedestrianActivity = PedestrianActivity.STANDING; - - //Click Sound - final MediaPlayer mpStart = MediaPlayer.create(this, R.raw.go); - final MediaPlayer mpStop = MediaPlayer.create(this, R.raw.go); - final MediaPlayer mpGround = MediaPlayer.create(this, R.raw.go); - final MediaPlayer mpFailure = MediaPlayer.create(this, R.raw.error); + btnSettings = (Button) findViewById(R.id.btnSettings); + activityButtonContainer = (TableLayout) findViewById(R.id.pedestrianActivityButtonContainer); // log GroundTruth ButtonClicks using sensor number 99 final GroundTruth grndTruth = new GroundTruth(this); sensors.add(grndTruth); grndTruth.setListener(new mySensor.SensorListener() { - @Override public void onData(final String csv) { return; } - @Override public void onData(SensorType id, final String csv) {add(id, csv); } + @Override public void onData(final long timestamp, final String csv) { return; } + @Override public void onData(SensorType id, final long timestamp, final String csv) {add(id, csv, timestamp); } }); @@ -145,7 +142,7 @@ public class MainActivity extends Activity { grndTruth.writeGroundTruth(groundTruthCounter); //Write first activity - add(SensorType.PEDESTRIAN_ACTIVITY, PedestrianActivity.STANDING.toString() + ";" + PedestrianActivity.STANDING.ordinal()); + add(SensorType.PEDESTRIAN_ACTIVITY, PedestrianActivity.STANDING.toString() + ";" + PedestrianActivity.STANDING.ordinal(), Logger.BEGINNING_TS); //Disable the spinners groundSpinner.setEnabled(false); @@ -154,7 +151,6 @@ public class MainActivity extends Activity { else{ mpFailure.start(); } - } }); @@ -175,7 +171,7 @@ public class MainActivity extends Activity { pathSpinner.setEnabled(true); //reset activity buttons - setActivityBtn(PedestrianActivity.STANDING); + setActivityBtn(PedestrianActivity.STANDING, false); } else{ mpFailure.start(); @@ -202,174 +198,28 @@ public class MainActivity extends Activity { } }); - - btnWalk.getLayout().setOnClickListener(new View.OnClickListener() { - @Override public void onClick(View v) { - if(isInitialized) { - setActivityBtn(PedestrianActivity.WALK); - } - else{ + btnSettings.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if(!isInitialized) { // Only allow when not currently running + startActivity(new Intent(context, SettingsActivity.class)); + } else { mpFailure.start(); } } }); - - btnStand.getLayout().setOnClickListener(new View.OnClickListener() { - @Override public void onClick(View v) { - if(isInitialized) { - setActivityBtn(PedestrianActivity.STANDING); - } - else{ - mpFailure.start(); - } - } - }); - - btnStairsUp.getLayout().setOnClickListener(new View.OnClickListener() { - @Override public void onClick(View v) { - if(isInitialized) { - setActivityBtn(PedestrianActivity.STAIRS_UP); - } - else{ - mpFailure.start(); - } - } - }); - - btnStairsDown.getLayout().setOnClickListener(new View.OnClickListener() { - @Override public void onClick(View v) { - if(isInitialized) { - setActivityBtn(PedestrianActivity.STAIRS_DOWN); - } - else{ - mpFailure.start(); - } - } - }); - - btnElevatorUp.getLayout().setOnClickListener(new View.OnClickListener() { - @Override public void onClick(View v) { - if(isInitialized) { - setActivityBtn(PedestrianActivity.ELEVATOR_UP); - } - else{ - mpFailure.start(); - } - } - }); - - btnElevatorDown.getLayout().setOnClickListener(new View.OnClickListener() { - @Override public void onClick(View v) { - if(isInitialized) { - setActivityBtn(PedestrianActivity.ELEVATOR_DOWN); - } - else{ - mpFailure.start(); - } - } - }); - - //all Sensors - final PhoneSensors phoneSensors = new PhoneSensors(this); - sensors.add(phoneSensors); - phoneSensors.setListener(new mySensor.SensorListener(){ - @Override public void onData(final String csv) { return; } - @Override public void onData(final SensorType id, final String csv) {add(id, csv); } - }); - - // logo wifi using sensor number 8 -// final WiFi wifi = new WiFi(this); -// sensors.add(wifi); -// wifi.setListener(new mySensor.SensorListener() { -// @Override public void onData(final String csv) { add(SensorType.WIFI, csv); } -// @Override public void onData(final SensorType id, final String csv) {return; } -// }); - - // log wifi RTT using sensor number 17 - final WiFiRTT wifirtt = new WiFiRTT(this); - sensors.add(wifirtt); - wifirtt.setListener(new mySensor.SensorListener() { - @Override public void onData(final String csv) { add(SensorType.WIFIRTT, csv); } - @Override public void onData(final SensorType id, final String csv) {add(id, csv); } - }); - - //log gps using sensor number 16 - final GpsNew gps = new GpsNew(this); - sensors.add(gps); - gps.setListener(new mySensor.SensorListener(){ - @Override public void onData(final String csv) { add(SensorType.GPS, csv); } - @Override public void onData(final SensorType id, final String csv) {return; } - }); - - // log iBeacons using sensor number 9 - final mySensor beacon; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - beacon = new iBeacon(this); - } else{ - beacon = new iBeaconOld(this); - } - - sensors.add(beacon); - beacon.setListener(new mySensor.SensorListener() { - @Override public void onData(final String csv) { add(SensorType.IBEACON, csv); } - @Override public void onData(final SensorType id, final String csv) {return; } - }); - - - // bluetooth permission - if(ActivityCompat.shouldShowRequestPermissionRationale(this, - Manifest.permission.ACCESS_FINE_LOCATION)) { - } else { - ActivityCompat.requestPermissions(this, - new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, - MY_PERMISSIONS_REQUEST_READ_BT); - } - - // heartbeat permission -/* if(ActivityCompat.shouldShowRequestPermissionRationale(this, - Manifest.permission.BODY_SENSORS)) { - } else { - ActivityCompat.requestPermissions(this, - new String[]{Manifest.permission.BODY_SENSORS}, - MY_PERMISSIONS_REQUEST_READ_HEART); - }*/ - } - private void setActivityBtn(PedestrianActivity act){ - - // set and write new activity - if(currentPedestrianActivity != act){ - - // toggle past and current activity - PedestrianActivity[] tmpActArray = new PedestrianActivity[] {currentPedestrianActivity, act}; - - for(PedestrianActivity a : tmpActArray){ - switch (a) { - case WALK: btnWalk.toggleActivity(); - break; - case STANDING: btnStand.toggleActivity(); - break; - case STAIRS_UP: btnStairsUp.toggleActivity(); - break; - case STAIRS_DOWN: btnStairsDown.toggleActivity(); - break; - case ELEVATOR_UP: btnElevatorUp.toggleActivity(); - break; - case ELEVATOR_DOWN: btnElevatorDown.toggleActivity(); - break; - default: - break; - } - } - - currentPedestrianActivity = act; - add(SensorType.PEDESTRIAN_ACTIVITY, act.toString() + ";" + act.ordinal()); - } else { - //do nothin + private void setActivityBtn(PedestrianActivity newActivity, boolean logChange){ + if(activityButtons.containsKey(currentPedestrianActivity)) { + activityButtons.get(currentPedestrianActivity).setActivity(false); + } + currentPedestrianActivity = newActivity; + activityButtons.get(newActivity).setActivity(true); + if(logChange) { + add(SensorType.PEDESTRIAN_ACTIVITY, newActivity.toString() + ";" + newActivity.ordinal()); } - } private void start() { @@ -395,31 +245,45 @@ public class MainActivity extends Activity { private int loadCounterGPS = 0; private int loadCounterAny = 0; private void add(final SensorType id, final String csv) { + add(id, csv, SystemClock.elapsedRealtimeNanos()); + } + private void add(final SensorType id, final String csv, final long timestamp) { - logger.addCSV(id, csv); + logger.addCSV(id, timestamp, csv); - runOnUiThread(new Runnable() { - @Override public void run() { - if (id == SensorType.WIFI) { - final TextView txt = (TextView) findViewById(R.id.txtWifi); - txt.setText( ((++loadCounterWifi % 2) == 0) ? "wi" : "WI"); - } else if (id == SensorType.IBEACON){ - final TextView txt = (TextView) findViewById(R.id.txtBeacon); - txt.setText( ((++loadCounterBeacon % 2) == 0) ? "ib" : "IB"); - } else if (id == SensorType.GPS){ - final TextView txt = (TextView) findViewById(R.id.txtGPS); - txt.setText( ((++loadCounterGPS % 2) == 0) ? "gps" : "GPS");} + // update UI for WIFI/BEACON/GPS + if (id == SensorType.WIFI || id == SensorType.IBEACON || id == SensorType.GPS) { + runOnUiThread(new Runnable() { + @Override + public void run() { - // dump buffer stats every x entries - if (++loadCounterAny % 250 == 0) { - final TextView txt = (TextView) findViewById(R.id.txtBuffer); - final int kbPerMin = (int) (logger.getTotalSize() / 1024 * 1000 * 60 / (System.currentTimeMillis() - logger.getStartTS())); - txt.setText( (logger.getCurrentSize() / 1024) + "k, " + logger.getNumEntries() + ", " + kbPerMin + "k/m"); + if (id == SensorType.WIFI) { + final TextView txt = (TextView) findViewById(R.id.txtWifi); + txt.setText(((++loadCounterWifi % 2) == 0) ? "wi" : "WI"); + } else if (id == SensorType.IBEACON) { + final TextView txt = (TextView) findViewById(R.id.txtBeacon); + txt.setText(((++loadCounterBeacon % 2) == 0) ? "ib" : "IB"); + } else if (id == SensorType.GPS) { + final TextView txt = (TextView) findViewById(R.id.txtGPS); + txt.setText(((++loadCounterGPS % 2) == 0) ? "gps" : "GPS"); + } } + }); + } - } - }); + // dump buffer stats every x entries + if (++loadCounterAny % 250 == 0) { + runOnUiThread(new Runnable() { + @Override + public void run() { + final TextView txt = (TextView) findViewById(R.id.txtBuffer); + final float elapsedMinutes = (timestamp - logger.getStartTS()) / 1000.0f / 1000.0f / 1000.0f / 60.0f; + final int kBPerMin = (int) (logger.getTotalSize() / 1024.0f / elapsedMinutes); + txt.setText((logger.getCurrentBufferSize() / 1024) + "k, " + logger.getNumEntries() + ", " + kBPerMin + "kB/m"); + } + }); + } } @@ -429,11 +293,20 @@ public class MainActivity extends Activity { super.onPause(); } + protected void onStart() { + super.onStart(); + if(!isInitialized) { + // Do not apply new settings when recording is currently running, since we can't have come + // from the SettingsActivity, then. + setupActivityButtons(); + setupSensors(); + } + } + /** resume activity */ protected void onResume() { super.onResume(); - //print memory info ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo(); ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); @@ -468,4 +341,151 @@ public class MainActivity extends Activity { return MainActivity.context; } + + + + + + protected void setupActivityButtons() { + // cleanup before recreation + for(int i = 0; i < activityButtonContainer.getChildCount(); ++i) { + TableRow buttonRow = (TableRow)activityButtonContainer.getChildAt(i); + buttonRow.removeAllViews(); + } + activityButtonContainer.removeAllViews(); + activityButtons.clear(); + + // setup activity buttons + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + Set activeActivities = preferences.getStringSet("prefActiveActions", new HashSet()); + + activityButtons.put(PedestrianActivity.STANDING, new PedestrianActivityButton(this, PedestrianActivity.STANDING, R.drawable.ic_standing)); + if(activeActivities.contains("WALK")) { + activityButtons.put(PedestrianActivity.WALK, new PedestrianActivityButton(this, PedestrianActivity.WALK, R.drawable.ic_walk)); + } + if(activeActivities.contains("ELEVATOR")) { + activityButtons.put(PedestrianActivity.ELEVATOR_UP, new PedestrianActivityButton(this, PedestrianActivity.ELEVATOR_UP, R.drawable.ic_elevator_up)); + activityButtons.put(PedestrianActivity.ELEVATOR_DOWN, new PedestrianActivityButton(this, PedestrianActivity.ELEVATOR_DOWN, R.drawable.ic_elevator_down)); + } + if(activeActivities.contains("STAIRS")) { + activityButtons.put(PedestrianActivity.STAIRS_UP, new PedestrianActivityButton(this, PedestrianActivity.STAIRS_UP, R.drawable.ic_stairs_up)); + activityButtons.put(PedestrianActivity.STAIRS_DOWN, new PedestrianActivityButton(this, PedestrianActivity.STAIRS_DOWN, R.drawable.ic_stairs_down)); + } + if(activeActivities.contains("MESS_AROUND")) { + activityButtons.put(PedestrianActivity.MESS_AROUND, new PedestrianActivityButton(this, PedestrianActivity.MESS_AROUND, R.drawable.ic_mess_around)); + } + int activityButtonColumns = 1; + if(activityButtons.size() > 6) { activityButtonColumns = 4; } + else if(activityButtons.size() > 4) { activityButtonColumns = 3; } + else if(activityButtons.size() > 2) { activityButtonColumns = 2; } + + TableLayout.LayoutParams rowLayout = new TableLayout.LayoutParams(); + rowLayout.width = LayoutParams.MATCH_PARENT; + rowLayout.height = LayoutParams.WRAP_CONTENT; + rowLayout.weight = 1.0f; + TableRow.LayoutParams columnLayout = new TableRow.LayoutParams(); + columnLayout.height = LayoutParams.MATCH_PARENT; + columnLayout.width = 1; // set minWidth to 1, because this will be stretched, and the images adjust in size + columnLayout.weight = 1.0f; + PedestrianActivity[] activeActiviesArray = activityButtons.keySet().toArray(new PedestrianActivity[activityButtons.size()]); + Arrays.sort(activeActiviesArray); + TableRow currentButtonRow = null; + for(int i = 0; i < activeActiviesArray.length; ++i) { + final PedestrianActivityButton button = activityButtons.get(activeActiviesArray[i]); + if(i % activityButtonColumns == 0) { + currentButtonRow = new TableRow(this); + currentButtonRow.setWeightSum(1.0f * activityButtonColumns); + activityButtonContainer.addView(currentButtonRow, rowLayout); + } + currentButtonRow.addView(button, columnLayout); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if(isInitialized) { + setActivityBtn(button.getPedestrianActivity(), true); + } + else{ + mpFailure.start(); + } + } + }); + } + + //set current activity + setActivityBtn(PedestrianActivity.STANDING, false); + } + + protected void setupSensors() { + //cleanup first + sensors.clear(); + + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + Set activeSensors = preferences.getStringSet("prefActiveSensors", new HashSet()); + + if(activeSensors.contains("PHONE")) { + // heartbeat permission + if(ActivityCompat.shouldShowRequestPermissionRationale(this, + Manifest.permission.BODY_SENSORS)) { + } else { + ActivityCompat.requestPermissions(this, + new String[]{Manifest.permission.BODY_SENSORS}, + MY_PERMISSIONS_REQUEST_READ_HEART); + } + + //all Phone-Sensors (Accel, Gyro, Magnet, ...) + final PhoneSensors phoneSensors = new PhoneSensors(this); + sensors.add(phoneSensors); + phoneSensors.setListener(new mySensor.SensorListener(){ + @Override public void onData(final long timestamp, final String csv) { return; } + @Override public void onData(final SensorType id, final long timestamp, final String csv) {add(id, csv, timestamp); } + }); + } + if(activeSensors.contains("GPS")) { + //log gps using sensor number 16 + final GpsNew gps = new GpsNew(this); + sensors.add(gps); + gps.setListener(new mySensor.SensorListener(){ + @Override public void onData(final long timestamp, final String csv) { add(SensorType.GPS, csv, timestamp); } + @Override public void onData(final SensorType id, final long timestamp, final String csv) {return; } + }); + } + if(activeSensors.contains("WIFI")) { + // log wifi using sensor number 8 + final WiFi wifi = new WiFi(this); + sensors.add(wifi); + wifi.setListener(new mySensor.SensorListener() { + @Override public void onData(final long timestamp, final String csv) { add(SensorType.WIFI, csv, timestamp); } + @Override public void onData(final SensorType id, final long timestamp, final String csv) {return; } + }); + } + if(activeSensors.contains("BLUETOOTH")) { + // bluetooth permission + if(ActivityCompat.shouldShowRequestPermissionRationale(this, + Manifest.permission.ACCESS_FINE_LOCATION)) { + } else { + ActivityCompat.requestPermissions(this, + new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, + MY_PERMISSIONS_REQUEST_READ_BT); + } + + // log iBeacons using sensor number 9 + final mySensor beacon; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + beacon = new iBeacon(this); + } else { + beacon = null; + //beacon = new iBeaconOld(this); + } + + if (beacon != null) { + sensors.add(beacon); + beacon.setListener(new mySensor.SensorListener() { + @Override public void onData(final long timestamp, final String csv) { add(SensorType.IBEACON, csv, timestamp); } + @Override public void onData(final SensorType id, final long timestamp, final String csv) {return; } + }); + } + } + } + + } diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/SettingsActivity.java b/app/src/main/java/de/fhws/indoor/sensorreadout/SettingsActivity.java new file mode 100644 index 0000000..4bcc46f --- /dev/null +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/SettingsActivity.java @@ -0,0 +1,14 @@ +package de.fhws.indoor.sensorreadout; + +import android.preference.PreferenceManager; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; + +public class SettingsActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit(); + } +} diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/SettingsFragment.java b/app/src/main/java/de/fhws/indoor/sensorreadout/SettingsFragment.java new file mode 100644 index 0000000..18f185c --- /dev/null +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/SettingsFragment.java @@ -0,0 +1,16 @@ +package de.fhws.indoor.sensorreadout; + +import android.os.Bundle; +import android.preference.PreferenceFragment; +import android.support.annotation.Nullable; + +public class SettingsFragment extends PreferenceFragment { + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + addPreferencesFromResource(R.xml.preferences); + } + +} diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/Gps.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/Gps.java index eec513f..63b71d7 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/Gps.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/Gps.java @@ -85,7 +85,7 @@ public class Gps extends mySensor implements LocationListener { // inform listeners if (listener != null){ - listener.onData(SensorType.GRAVITY, + listener.onData(SensorType.GRAVITY, location.getElapsedRealtimeNanos(), //TODO: Is this correct? SystemClock.elapsedRealtimeNanos() otherwise.. Double.toString(location.getLatitude()) + ";" + Double.toString(location.getLongitude()) + ";" + Double.toString(location.getAltitude()) + ";" + diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/GpsNew.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/GpsNew.java index f969c03..bf085de 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/GpsNew.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/GpsNew.java @@ -169,7 +169,7 @@ public class GpsNew extends mySensor implements ConnectionCallbacks, OnConnectio // inform listeners if (listener != null){ - listener.onData(SensorType.GRAVITY, + listener.onData(SensorType.GRAVITY, location.getElapsedRealtimeNanos(), //TODO: Is this correct? SystemClock.elapsedRealtimeNanos() otherwise.. Double.toString(location.getLatitude()) + ";" + Double.toString(location.getLongitude()) + ";" + Double.toString(location.getAltitude()) + ";" + diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/GroundTruth.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/GroundTruth.java index e1e7143..97c1ef8 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/GroundTruth.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/GroundTruth.java @@ -1,6 +1,7 @@ package de.fhws.indoor.sensorreadout.sensors; import android.app.Activity; +import android.os.SystemClock; /** * Created by Toni on 02.06.2015. @@ -12,14 +13,14 @@ public class GroundTruth extends mySensor { } public void writeGroundTruth(final int groundTruthCounter){ - if (listener != null){listener.onData(SensorType.GROUND_TRUTH, + if (listener != null){listener.onData(SensorType.GROUND_TRUTH, SystemClock.elapsedRealtimeNanos(), Integer.toString(groundTruthCounter) );} } public void writeInitData(int pathID, int numGroundTruthPoints){ - if (listener != null){listener.onData(SensorType.GROUND_TRUTH_PATH, + if (listener != null){listener.onData(SensorType.GROUND_TRUTH_PATH, SystemClock.elapsedRealtimeNanos(), Integer.toString(pathID) + ";" + Integer.toString(numGroundTruthPoints) );} diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/Logger.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/Logger.java index 4b363ae..264f1a8 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/Logger.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/Logger.java @@ -2,27 +2,41 @@ package de.fhws.indoor.sensorreadout.sensors; import android.content.Context; import android.os.AsyncTask; +import android.os.SystemClock; +import android.support.annotation.NonNull; import android.util.Log; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; +import java.util.PriorityQueue; +import java.util.concurrent.Semaphore; /** * log sensor data to file * Created by Frank on 25.03.2015. + * Re-Written by Markus on 20.06.2019. */ public final class Logger { - private static final int FLUSH_LIMIT = 2*1024*1024; + public static final long BEGINNING_TS = -1; - private StringBuilder sb = new StringBuilder(); + private static final int CACHED_ENTRIES = 1000; + private static final int FLUSH_BATCH_SIZE = 100; + + private StringBuilder stringBuilder = new StringBuilder(); private File file; private FileOutputStream fos; private Context context; private int entries = 0; - private int sizeCurrent = 0; private int sizeTotal = 0; + private int currentSize = 0; + + private volatile boolean addingStopped = false; // Just to be sure + private PriorityQueue reorderBuffer = new PriorityQueue<>(2 * CACHED_ENTRIES + FLUSH_BATCH_SIZE); + private Semaphore flushSemaphore = new Semaphore(0); + private WriteBackWorker writeBackWorker; /** timestamp of logging start. all entries are relative to this one */ private long startTS = 0; @@ -35,13 +49,15 @@ public final class Logger { public final void start() { // start empty - sb.setLength(0); + stringBuilder.setLength(0); entries = 0; sizeTotal = 0; - sizeCurrent = 0; + addingStopped = false; + flushSemaphore.drainPermits(); + writeBackWorker = new WriteBackWorker(); // starting timestamp - startTS = System.currentTimeMillis(); + startTS = SystemClock.elapsedRealtimeNanos(); // open the output-file immeditaly (to get permission errors) // but do NOT yet write anything to the file @@ -54,88 +70,68 @@ public final class Logger { } catch (final Exception e) { throw new MyException("error while opening log-file", e); } - + writeBackWorker.start(); } /** stop logging and flush RAM-data to the flash-chip */ public final void stop() { - synchronized (this) { - flush(true); - close(); + debug(true); + synchronized (reorderBuffer) { + addingStopped = true; + // Unblock WriteBackThread for all remaining log-lines (+1) + // some elements in reorderBuffer could already have been released for flushing -> this might release more than necessary. + flushSemaphore.release(reorderBuffer.size() + 1); } + // wait for flushing to succeed + try { + writeBackWorker.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + debug(true); + close(); } public File getFile() { return file; } - public int getCurrentSize() {return sizeCurrent;} + public int getCurrentBufferSize() {return currentSize;} public int getTotalSize() {return sizeTotal;} public int getNumEntries() {return entries;} /** add a new CSV entry for the given sensor number to the internal buffer */ - public final void addCSV(final SensorType sensorNr, final String csv) { - synchronized (this) { - final long relTS = System.currentTimeMillis() - startTS; - sb.append(relTS); // relative timestamp (uses less space) - sb.append(';'); - sb.append(sensorNr.id()); - sb.append(';'); - sb.append(csv); - sb.append('\n'); - ++entries; - sizeTotal += csv.length() + 10; // approx! - sizeCurrent = sb.length(); - if (sb.length() > FLUSH_LIMIT) {flush(false);} + public final void addCSV(final SensorType sensorNr, final long timestamp, final String csv) { + final long relTS = (timestamp == BEGINNING_TS) ? 0 : (timestamp - startTS); + if(relTS >= 0) { // drop pre startTS logs (at the beginning, sensors sometimes deliver old values) + synchronized (reorderBuffer) { + if(addingStopped) { + // addCSV was called after calling stop(); + return; + } + + stringBuilder.append(relTS); // relative timestamp (uses less space) + stringBuilder.append(';'); + stringBuilder.append(sensorNr.id()); + stringBuilder.append(';'); + stringBuilder.append(csv); + stringBuilder.append('\n'); + ++entries; + LogEntry logEntry = new LogEntry(relTS, stringBuilder.toString()); + sizeTotal += logEntry.csv.length(); + currentSize += logEntry.csv.length(); + stringBuilder.setLength(0); + + // commit to reorder-buffer and start flush (if necessary) + reorderBuffer.add(logEntry); + if(flushSemaphore.availablePermits() == 0 && reorderBuffer.size() > (CACHED_ENTRIES + FLUSH_BATCH_SIZE)) { + // Unblock WriteBackThread and allow it to flush FLUSH_BATCH_SIZE csv-lines. + flushSemaphore.release(reorderBuffer.size() - CACHED_ENTRIES); + } + } } - - debug(); - } - - - - /** helper method for exception-less writing. DO NOT CALL DIRECTLY! */ - private final void _write(final byte[] data) { - try { - fos.write(data); - Log.d("logger", "flushed " + data.length + " bytes to disk"); - } catch (final Exception e) { - throw new RuntimeException("error while writing log-file", e); - } - } - - /** helper-class for background writing */ - class FlushAsync extends AsyncTask { - @Override - protected final Integer doInBackground(byte[][] data) { - _write(data[0]); - return null; - } - }; - - /** flush current buffer-contents to disk */ - private final void flush(boolean sync) { - - // fetch current buffer contents to write and hereafter empty the buffer - // this action MUST be atomic, just like the add-method - byte[] data = null; - synchronized (this) { - data = sb.toString().getBytes(); // fetch data to write - sb.setLength(0); // reset the buffer - sizeCurrent = 0; - } - - // write - if (sync) { - // write to disk using the current thread - _write(data); - } else { - // write to disk using a background-thread - new FlushAsync().execute(new byte[][] {data}); - } - - + debug(false); } private final void close() { @@ -151,10 +147,67 @@ public final class Logger { } int cnt = 0; - private final void debug() { - if (++cnt % 1000 == 0) { - Log.d("buffer", "size: " + sizeCurrent); + private final void debug(boolean force) { + if (++cnt % 1000 == 0 || force) { + Log.d("buffer", "size: " + reorderBuffer.size() + " lines"); } } + + + private static class LogEntry implements Comparable { + public long timestamp; + public String csv; + + public LogEntry(long timestamp, String csv) { + this.timestamp = timestamp; + this.csv = csv; + } + + @Override + public int compareTo(@NonNull LogEntry another) { + return (timestamp < another.timestamp) ? (-1) : (+1); + } + } + + private class WriteBackWorker extends Thread { + + public WriteBackWorker() { + setName("WriteBackWorker"); + setPriority(Thread.MIN_PRIORITY); + } + + @Override + public void run() { + try { + boolean stop = false; + while(!stop) { + flushSemaphore.acquireUninterruptibly(); + + LogEntry[] entriesToFlush = null; + synchronized (reorderBuffer) { + int flushBatchSize = 1 + flushSemaphore.drainPermits(); // might contain extra-permit for stop-unblocking + if(flushBatchSize > reorderBuffer.size()) { // We were unblocked more than there are available lines to fush -> request to flush all & stop + stop = true; + flushBatchSize = reorderBuffer.size(); + } + entriesToFlush = new LogEntry[flushBatchSize]; + + for(int i = 0; i < flushBatchSize; ++i) { + entriesToFlush[i] = reorderBuffer.poll(); + currentSize -= entriesToFlush[i].csv.length(); + } + } + + for(int i = 0; i < entriesToFlush.length; ++i) { + fos.write(entriesToFlush[i].csv.getBytes()); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + } diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/LoggerRAM.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/LoggerRAM.java new file mode 100644 index 0000000..417b298 --- /dev/null +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/LoggerRAM.java @@ -0,0 +1,171 @@ +package de.fhws.indoor.sensorreadout.sensors; + +import android.content.Context; +import android.os.SystemClock; +import android.support.annotation.NonNull; +import android.util.Log; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.ArrayList; +import java.util.Collections; + +/** + * log sensor data to RAM + * only flush to file when finished + */ +public final class LoggerRAM { + + public static final long BEGINNING_TS = -1; + + + private StringBuilder stringBuilder = new StringBuilder(); + private File file; + private FileOutputStream fos; + private Context context; + + private boolean addingStopped = false; + private int entries = 0; + private int sizeTotal = 0; + private int currentSize = 0; + + private ArrayList buffer = new ArrayList<>(); + + /** timestamp of logging start. all entries are relative to this one */ + private long startTS = 0; + + public LoggerRAM(Context context) { + this.context = context; + } + + /** start logging (into RAM) */ + public final void start() { + + // start empty + stringBuilder.setLength(0); + entries = 0; + sizeTotal = 0; + currentSize = 0; + buffer.clear(); + addingStopped = false; + + // starting timestamp + startTS = SystemClock.elapsedRealtimeNanos(); + + // open the output-file immeditaly (to get permission errors) + // but do NOT yet write anything to the file + final DataFolder folder = new DataFolder(context, "sensorOutFiles"); + file = new File(folder.getFolder(), startTS + ".csv"); + + try { + fos = new FileOutputStream(file); + Log.d("logger", "will write to: " + file.toString()); + } catch (final Exception e) { + throw new MyException("error while opening log-file", e); + } + + } + + /** stop logging and flush RAM-data to the flash-chip */ + public final void stop() { + + addingStopped = true; + + synchronized (buffer) { + + // sort by TS (ensure strict ordering) + Collections.sort(buffer); + + // export each entry + for (LogEntry e : buffer) { + try { + fos.write(e.csv.getBytes()); + } catch (final Exception ex) { + ex.printStackTrace();; + } + } + + // done + buffer.clear(); + + } + + // done + close(); + + } + + public File getFile() { + return file; + } + + public int getCurrentBufferSize() {return currentSize;} + public int getTotalSize() {return sizeTotal;} + + public int getNumEntries() {return entries;} + + /** add a new CSV entry for the given sensor number to the internal buffer */ + public final void addCSV(final SensorType sensorNr, final long timestamp, final String csv) { + + if (addingStopped) {return;} + + final long relTS = (timestamp == BEGINNING_TS) ? 0 : (timestamp - startTS); + if(relTS >= 0) { // drop pre startTS logs (at the beginning, sensors sometimes deliver old values) + + stringBuilder.setLength(0); + stringBuilder.append(relTS); // relative timestamp (uses less space) + stringBuilder.append(';'); + stringBuilder.append(sensorNr.id()); + stringBuilder.append(';'); + stringBuilder.append(csv); + stringBuilder.append('\n'); + ++entries; + LogEntry logEntry = new LogEntry(relTS, stringBuilder.toString()); + sizeTotal += logEntry.csv.length(); + currentSize += logEntry.csv.length(); + + synchronized (buffer) { + buffer.add(logEntry); + } + + } + + } + + private final void close() { + try { + fos.close(); + } catch (final Exception e) { + throw new MyException("error while writing log-file", e); + } + } + + public final long getStartTS() { + return startTS; + } + + int cnt = 0; + private final void debug(boolean force) { + if (++cnt % 1000 == 0 || force) { + Log.d("buffer", "size: " + buffer.size() + " lines"); + } + } + + + + private static class LogEntry implements Comparable { + public long timestamp; + public String csv; + + public LogEntry(long timestamp, String csv) { + this.timestamp = timestamp; + this.csv = csv; + } + + @Override + public int compareTo(@NonNull LogEntry another) { + return (timestamp < another.timestamp) ? (-1) : (+1); + } + } + +} diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/PedestrianActivity.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/PedestrianActivity.java index 1e7042b..0fc4291 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/PedestrianActivity.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/PedestrianActivity.java @@ -12,6 +12,7 @@ public enum PedestrianActivity { STAIRS_DOWN(3), ELEVATOR_UP(4), ELEVATOR_DOWN(5), + MESS_AROUND(6), ; private int id; diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/PedestrianActivityButton.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/PedestrianActivityButton.java index 288732f..7d13aab 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/PedestrianActivityButton.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/PedestrianActivityButton.java @@ -1,35 +1,45 @@ package de.fhws.indoor.sensorreadout.sensors; +import android.content.Context; import android.graphics.Color; +import android.support.annotation.DrawableRes; import android.view.View; +import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.TextView; + +import de.fhws.indoor.sensorreadout.R; /** * Created by toni on 10/01/18. + * Extended by Markus on 19/06/19 */ -public class PedestrianActivityButton { +public class PedestrianActivityButton extends LinearLayout { - private LinearLayout btn; - private boolean isActivated = false; - private PedestrianActivity whatActivity; + private LinearLayout innerBtn; + private boolean isActive = false; + private PedestrianActivity activity; - public PedestrianActivityButton(LinearLayout btn, PedestrianActivity act){ - this.btn = btn; - this.whatActivity = act; + public PedestrianActivityButton(Context context, PedestrianActivity activity, @DrawableRes int imageId) { + super(context); + inflate(getContext(), R.layout.pedestrian_activity_button, this); + this.activity = activity; + // setup ui + ImageView imageView = (ImageView)this.findViewById(R.id.activityButtonImage); + imageView.setImageResource(imageId); + TextView textView = (TextView)this.findViewById(R.id.activityButtonText); + textView.setText(activity.toString()); + innerBtn = (LinearLayout)getChildAt(0); + setActivity(false); } - public void toggleActivity(){ - isActivated = !isActivated; - - if(isActivated){ - btn.setBackgroundColor(Color.parseColor("#F9D737")); - } else { - btn.setBackgroundColor(Color.parseColor("#B2B2B2")); - } + public void setActivity(boolean active) { + this.isActive = active; + innerBtn.setBackgroundColor(Color.parseColor( + (isActive) ? "#F9D737" : "#B2B2B2" + )); } - public LinearLayout getLayout(){ - return btn; - } + public PedestrianActivity getPedestrianActivity() { return this.activity; } } diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/PhoneSensors.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/PhoneSensors.java index 0103455..ebd04e9 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/PhoneSensors.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/PhoneSensors.java @@ -39,6 +39,7 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ private Sensor rotationVector; private Sensor light; private Sensor temperature; + private Sensor gameRotationVector; /** local gravity copy (needed for orientation matrix) */ private float[] mGravity = new float[3]; @@ -65,6 +66,7 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ rotationVector = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); light = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); temperature = sensorManager.getDefaultSensor(Sensor.TYPE_AMBIENT_TEMPERATURE); + gameRotationVector = sensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR); // dump sensor-vendor info to file dumpVendors(act); @@ -102,6 +104,7 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ dumpSensor(sb, SensorType.LIGHT, light); dumpSensor(sb, SensorType.AMBIENT_TEMPERATURE, temperature); dumpSensor(sb, SensorType.HEART_RATE, heart); + dumpSensor(sb, SensorType.GAME_ROTATION_VECTOR, gameRotationVector); // write fos.write(sb.toString().getBytes()); @@ -139,13 +142,12 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ @Override public void onSensorChanged(SensorEvent event) { - /* // to compare with the other orientation if(event.sensor.getType() == Sensor.TYPE_ORIENTATION) { // inform listeners if (listener != null){ - listener.onData(SensorType.ORIENTATION_OLD, + listener.onData(SensorType.ORIENTATION_OLD, event.timestamp, Float.toString(event.values[0]) + ";" + Float.toString(event.values[1]) + ";" + Float.toString(event.values[2]) @@ -153,13 +155,12 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ } } - */ if(event.sensor.getType() == Sensor.TYPE_HEART_RATE) { // inform listeners if (listener != null){ - listener.onData(SensorType.HEART_RATE, + listener.onData(SensorType.HEART_RATE, event.timestamp, Float.toString(event.values[0]) ); } @@ -170,7 +171,7 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ // inform listeners if (listener != null){ - listener.onData(SensorType.LIGHT, + listener.onData(SensorType.LIGHT, event.timestamp, Float.toString(event.values[0]) ); } @@ -181,7 +182,7 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ // inform listeners if (listener != null){ - listener.onData(SensorType.AMBIENT_TEMPERATURE, + listener.onData(SensorType.AMBIENT_TEMPERATURE, event.timestamp, Float.toString(event.values[0]) ); } @@ -192,7 +193,7 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ // inform listeners if (listener != null){ - listener.onData(SensorType.RELATIVE_HUMIDITY, + listener.onData(SensorType.RELATIVE_HUMIDITY, event.timestamp, Float.toString(event.values[0]) ); } @@ -205,14 +206,14 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ if (listener != null){ if(event.values.length > 3){ - listener.onData(SensorType.ROTATION_VECTOR, + listener.onData(SensorType.ROTATION_VECTOR, event.timestamp, Float.toString(event.values[0]) + ";" + Float.toString(event.values[1]) + ";" + Float.toString(event.values[2]) + ";" + Float.toString(event.values[3]) ); } else { - listener.onData(SensorType.ROTATION_VECTOR, + listener.onData(SensorType.ROTATION_VECTOR, event.timestamp, Float.toString(event.values[0]) + ";" + Float.toString(event.values[1]) + ";" + Float.toString(event.values[2]) @@ -227,7 +228,7 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ // inform listeners if (listener != null){ - listener.onData(SensorType.GYROSCOPE, + listener.onData(SensorType.GYROSCOPE, event.timestamp, Float.toString(event.values[0]) + ";" + Float.toString(event.values[1]) + ";" + Float.toString(event.values[2]) @@ -240,7 +241,7 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ // inform listeners if (listener != null){ - listener.onData(SensorType.PRESSURE, + listener.onData(SensorType.PRESSURE, event.timestamp, Float.toString(event.values[0]) ); } @@ -251,10 +252,10 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ // inform listeners if (listener != null){ - listener.onData(SensorType.LINEAR_ACCELERATION, + listener.onData(SensorType.LINEAR_ACCELERATION, event.timestamp, Float.toString(event.values[0]) + ";" + Float.toString(event.values[1]) + ";" + - Float.toString(event.values[2]) + ";" + Float.toString(event.values[2]) ); } @@ -264,7 +265,7 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ // inform listeners if (listener != null){ - listener.onData(SensorType.GRAVITY, + listener.onData(SensorType.GRAVITY, event.timestamp, Float.toString(event.values[0]) + ";" + Float.toString(event.values[1]) + ";" + Float.toString(event.values[2]) @@ -277,7 +278,7 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ // inform listeners if (listener != null){ - listener.onData(SensorType.ACCELEROMETER, + listener.onData(SensorType.ACCELEROMETER, event.timestamp, Float.toString(event.values[0]) + ";" + Float.toString(event.values[1]) + ";" + Float.toString(event.values[2]) @@ -297,7 +298,7 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ // inform listeners if (listener != null){ - listener.onData(SensorType.MAGNETIC_FIELD, + listener.onData(SensorType.MAGNETIC_FIELD, event.timestamp, Float.toString(event.values[0]) + ";" + Float.toString(event.values[1]) + ";" + Float.toString(event.values[2]) @@ -310,14 +311,25 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ // NOTE // @see TYPE_ACCELEROMETER // only MAG updates the current orientation as MAG is usually slower than ACC and this reduces the file-footprint - updateOrientation(); + updateOrientation(event.timestamp); } + else if(event.sensor.getType() == Sensor.TYPE_GAME_ROTATION_VECTOR) { + // inform listeners + if (listener != null) { + listener.onData(SensorType.GAME_ROTATION_VECTOR, event.timestamp, + Float.toString(event.values[0]) + ";" + + Float.toString(event.values[1]) + ";" + + Float.toString(event.values[2]) + ); + } + } + } /** calculate orientation from acc and mag */ - private void updateOrientation() { + private void updateOrientation(long timestamp) { // skip orientation update if either grav or geo is missing if (mGravity == null) {return;} @@ -339,7 +351,7 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ if (listener != null) { // orientation vector - listener.onData(SensorType.ORIENTATION_NEW, + listener.onData(SensorType.ORIENTATION_NEW, timestamp, Float.toString(orientationNew[0]) + ";" + Float.toString(orientationNew[1]) + ";" + Float.toString(orientationNew[2]) @@ -358,7 +370,7 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ sb.append(R[8]); //Write the whole rotationMatrix R into the Listener. - listener.onData(SensorType.ROTATION_MATRIX, sb.toString()); + listener.onData(SensorType.ROTATION_MATRIX, timestamp, sb.toString()); // Float.toString(R[0]) + ";" + // Float.toString(R[1]) + ";" + @@ -403,6 +415,7 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ registerIfPresent(rotationVector, SensorManager.SENSOR_DELAY_FASTEST); registerIfPresent(light, SensorManager.SENSOR_DELAY_FASTEST); registerIfPresent(temperature, SensorManager.SENSOR_DELAY_FASTEST); + registerIfPresent(gameRotationVector, SensorManager.SENSOR_DELAY_FASTEST); } diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/SensorType.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/SensorType.java index d458d90..4a7830b 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/SensorType.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/SensorType.java @@ -23,6 +23,7 @@ public enum SensorType { HEART_RATE(15), GPS(16), WIFIRTT(17), + GAME_ROTATION_VECTOR(18), PEDESTRIAN_ACTIVITY(50), GROUND_TRUTH(99), diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/WiFi.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/WiFi.java index cce8c67..e0d57d1 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/WiFi.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/WiFi.java @@ -23,6 +23,7 @@ public class WiFi extends mySensor { private final WifiManager wifi; private BroadcastReceiver receiver; private boolean isReceiverRegistered; + private boolean isFirstMeasurement = true; public WiFi(final Activity act) { @@ -40,15 +41,29 @@ public class WiFi extends mySensor { this.receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - final StringBuilder sb = new StringBuilder(1024); - final List res = wifi.getScanResults(); - for (final ScanResult sr : res) { - sb.append(Helper.stripMAC(sr.BSSID)).append(';'); - sb.append(sr.frequency).append(';'); - sb.append(sr.level).append(';'); - } - if (listener != null && isReceiverRegistered) { - listener.onData(sb.toString()); + + // ignore the first measurement + if (isFirstMeasurement) { + isFirstMeasurement = false; + } else { + final StringBuilder sb = new StringBuilder(1024); + final List res = wifi.getScanResults(); + long timestamp = 0; + for (final ScanResult sr : res) { + sb.append(Helper.stripMAC(sr.BSSID)).append(';'); + sb.append(sr.frequency).append(';'); + sb.append(sr.level).append(';'); + + // export with oldest timestamp among all contained measurements + final long nanos = sr.timestamp * 1000; + if (nanos > timestamp) { + timestamp = nanos; + } + + } + if (listener != null && isReceiverRegistered) { + listener.onData(timestamp, sb.toString()); + } } startScan(); //Log.d("wifi", sb.toString()); diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/WiFiRTT.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/WiFiRTT.java index ea57e86..c6b2a1c 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/WiFiRTT.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/WiFiRTT.java @@ -152,7 +152,7 @@ public class WiFiRTT extends mySensor { sb.append(numSuccessfulMeas); - listener.onData(SensorType.WIFIRTT, sb.toString()); + listener.onData(SensorType.WIFIRTT,res.getRangingTimestampMillis()*1000, sb.toString()); } } } diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/iBeacon.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/iBeacon.java index 3cc2017..9b78cdf 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/iBeacon.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/iBeacon.java @@ -20,7 +20,7 @@ public class iBeacon extends mySensor { private static final int REQUEST_ENABLE_BT = 1; private ScanCallback mLeScanCallback; - /** ctor */ + // ctor public iBeacon(final Activity act) { // sanity check @@ -48,7 +48,7 @@ public class iBeacon extends mySensor { @Override public void onScanResult(int callbackType, android.bluetooth.le.ScanResult result) { //Log.d("BT", device + " " + rssi); if (listener != null) { - listener.onData(Helper.stripMAC(result.getDevice().getAddress()) + ";" + result.getRssi() + ";" + result.getScanRecord().getTxPowerLevel()); + listener.onData(result.getTimestampNanos(), Helper.stripMAC(result.getDevice().getAddress()) + ";" + result.getRssi() + ";" + result.getScanRecord().getTxPowerLevel()); } } }; diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/iBeaconOld.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/iBeaconOld.java index 725c9fd..b190e7a 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/iBeaconOld.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/iBeaconOld.java @@ -8,19 +8,20 @@ import android.bluetooth.BluetoothManager; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.os.SystemClock; import android.widget.Toast; /** * Created by toni on 02/06/16. */ - +/* public class iBeaconOld extends mySensor { private BluetoothAdapter bt = null; private static final int REQUEST_ENABLE_BT = 1; private BluetoothAdapter.LeScanCallback mLeScanCallback; - /** ctor */ + // ctor public iBeaconOld(final Activity act) { // sanity check @@ -45,7 +46,7 @@ public class iBeaconOld extends mySensor { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { //Log.d("BT", device + " " + rssi); if (listener != null) { - listener.onData(Helper.stripMAC(device.getAddress()) + ";" + rssi); + listener.onData(SystemClock.elapsedRealtimeNanos(), Helper.stripMAC(device.getAddress()) + ";" + rssi); } } }; @@ -69,3 +70,4 @@ public class iBeaconOld extends mySensor { } } +*/ diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/mySensor.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/mySensor.java index f3c8381..015eb39 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/mySensor.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/mySensor.java @@ -12,10 +12,10 @@ public abstract class mySensor { /** listen for sensor events */ public interface SensorListener { - public void onData(final String csv); + public void onData(final long timestamp, final String csv); /** received data from the given sensor */ - public void onData(final SensorType id, final String csv); + public void onData(final SensorType id, final long timestamp, final String csv); } diff --git a/app/src/main/res/drawable/ic_mess_around.xml b/app/src/main/res/drawable/ic_mess_around.xml new file mode 100644 index 0000000..8e0a806 --- /dev/null +++ b/app/src/main/res/drawable/ic_mess_around.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 83f3a3f..d1a9090 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,6 +1,7 @@ - - + - - android:layout_marginTop="10dip" - android:layout_weight="1" - android:orientation="horizontal" - android:weightSum="3"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +