diff --git a/README.md b/README.md index 53990de68..7591dfec5 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,13 @@ Please join us on the following channels: + + + + + + +
## Video Demo - [PSLab Android App Overview](https://www.youtube.com/watch?v=JJfsF0b8M8k) @@ -60,14 +67,14 @@ Please join us on the following channels: ## Features | **Feature** | **Description** | **Status** | |------------------|-------------------------------------------------------|-----------------| -| Home Screen | Show status and version of PSLab device | Established | -| Instruments | Exposes PSLab instruments like Oscilloscope, etc | Established | -| Oscilloscope | Shows variation of analog signals | Established | -| Multimeter | Measures voltage, current, resistance and capacitance | Established | -| Logical Analyzer | Captures and displays signals from digital system | In Progress | -| Wave Generator | Generates arbitrary analog and digital waveforms | In Progress | -| Power Source | Generates programmable voltage and currents | Established | -| Lux Meter | Measures the ambient light intensity | Established | +| Home Screen | Show status and version of PSLab device | ✓ | +| Instruments | Exposes PSLab instruments like Oscilloscope, etc | ✓ | +| Oscilloscope | Shows variation of analog signals | ✓ | +| Multimeter | Measures voltage, current, resistance and capacitance | ✓ | +| Logical Analyzer | Captures and displays signals from digital system | ✓ | +| Wave Generator | Generates arbitrary analog and digital waveforms | ✓ | +| Power Source | Generates programmable voltage and currents | ✓ | +| Lux Meter | Measures the ambient light intensity | ✓ | ## How to set up the Android app in your development environment @@ -122,6 +129,39 @@ Please help us follow the best practice to make it easy for the reviewer as well * The pull request will not get merged until and unless the commits are squashed. In case there are multiple commits on the PR, the commit author needs to squash them and not the maintainers cherrypicking and merging squashes. * If the PR is related to any front end change, please attach relevant screenshots in the pull request description. +#### How to `git squash`? + +As a tip for new developers those who struggle with squashing commits into one, multiple commits may appear in your pull request mostly due to following reasons. + + * Intentionally adding multiple commit messages after each change without just `git add`ing. + * Updating the current branch with the remote so a merge commit takes place. + +Despite any reason, follow the steps given below to squash all commits into one adhering to our best practices. + + * Setup remote to upstream branch if not set before; + +`$ git remote add upstream https://github.com/fossasia/pslab-android.git` + + * Check into the branch related to the pull request + +`$ git checkout ` + + * Perform a soft reset to retain the changes while removing all the commit details + +`$ git reset --soft upstream/development` + + * Add files to the staging area + +`$ git add ` + + * Create a new commit with a proper message following commit message guidelines + +`$ git commit -m "tag: commit message"` + + * If you have already made a pull request, + +`$ git push -f origin ` + ### Branch Policy We have the following branches @@ -152,11 +192,19 @@ This project is currently licensed under the Apache License 2.0. A copy of [LICE ## Maintainers The project is maintained by -- Praveen Patil ([@wavicles](https://github.com/wavicles)) +- Padmal ([@CloudyPadmal](https://github.com/CloudyPadmal)) - Mario Behling ([@mariobehling](http://github.com/mariobehling)) - Lorenz Gerber ([@lorenzgerber](https://github.com/lorenzgerber)) - Wei Tat ([@cweitat](https://github.com/cweitat)) - Wai Gie ([@woshikie](https://github.com/woshikie)) + +## Alumni +- Praveen Patil ([@wavicles](https://github.com/wavicles)) - Jithin ([@jithinbp](https://github.com/jithinbp)) -- Akarshan Gandotra ([@akarshan96](https://github.com/akarshan96)), Asitava Sarkar ([@asitava1998](https://github.com/asitava1998)), Padmal ([@CloudyPadmal](https://github.com/CloudyPadmal)), Vivek Singh Bhadauria ([@viveksb007](https://github.com/viveksb007)) -- Avjeet ([@Avjeet](https://github.com/Avjeet)), Abhinav ([@abhinavraj23](https://github.com/abhinavraj23)), Harsh ([@harsh-2711](https://github.com/harsh-2711)), Yatri ([@yatri1609](https://github.com/yatri1609)) +- Akarshan Gandotra ([@akarshan96](https://github.com/akarshan96)) +- Asitava Sarkar ([@asitava1998](https://github.com/asitava1998)) +- Vivek Singh Bhadauria ([@viveksb007](https://github.com/viveksb007)) +- Avjeet ([@Avjeet](https://github.com/Avjeet)) +- Abhinav ([@abhinavraj23](https://github.com/abhinavraj23)) +- Harsh ([@harsh-2711](https://github.com/harsh-2711)) +- Yatri ([@yatri1609](https://github.com/yatri1609)) diff --git a/app/build.gradle b/app/build.gradle index 222cadaf1..32192962a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ android { applicationId "io.pslab" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 7 - versionName "2.0.6" + versionCode 8 + versionName "2.0.7" multiDexEnabled true testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/io/pslab/activity/AccelerometerActivity.java b/app/src/main/java/io/pslab/activity/AccelerometerActivity.java index b34074429..0b783534b 100644 --- a/app/src/main/java/io/pslab/activity/AccelerometerActivity.java +++ b/app/src/main/java/io/pslab/activity/AccelerometerActivity.java @@ -15,8 +15,10 @@ import android.support.annotation.NonNull; import android.support.design.widget.BottomSheetBehavior; import android.support.design.widget.CoordinatorLayout; +import android.support.design.widget.Snackbar; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; +import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; @@ -100,6 +102,8 @@ public void onClick(View v) { } }); setSupportActionBar(mToolbar); + ActionBar actionBar = getSupportActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); adapter = new AccelerometerAdapter(new String[]{"X axis", "Y axis", "Z axis"}, getApplicationContext()); RecyclerView recyclerView = this.findViewById(R.id.accelerometer_recycler_view); @@ -131,7 +135,7 @@ public boolean onOptionsItemSelected(MenuItem item) { item.setIcon(R.drawable.ic_record_white); adapter.setRecordingStatus(false); recordData = false; - CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.data_recording_paused), null, null); + CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.data_recording_paused), null, null, Snackbar.LENGTH_LONG); } else { isDataRecorded = true; item.setIcon(R.drawable.pause_icon); @@ -146,14 +150,14 @@ public boolean onOptionsItemSelected(MenuItem item) { gpsLogger = new GPSLogger(this, (LocationManager) getSystemService(Context.LOCATION_SERVICE)); if (gpsLogger.isGPSEnabled()) { recordData = true; - CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.data_recording_start) + "\n" + getString(R.string.location_enabled), null, null); + CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.data_recording_start) + "\n" + getString(R.string.location_enabled), null, null, Snackbar.LENGTH_LONG); } else { checkGpsOnResume = true; } gpsLogger.startCaptureLocation(); } else { recordData = true; - CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.data_recording_start) + "\n" + getString(R.string.location_disabled), null, null); + CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.data_recording_start) + "\n" + getString(R.string.location_disabled), null, null, Snackbar.LENGTH_LONG); } } break; @@ -200,12 +204,12 @@ public void onClick(DialogInterface dialogInterface, int i) { .create() .show(); } - }); + }, Snackbar.LENGTH_LONG); adapter.setRecordingStatus(false); isRecordingStarted = false; recordData = false; } else { - CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.nothing_to_export), null, null); + CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.nothing_to_export), null, null, Snackbar.LENGTH_LONG); } break; case R.id.delete_csv_data: @@ -217,9 +221,9 @@ public void onClick(DialogInterface dialogInterface, int i) { isRecordingStarted = false; isDataRecorded = false; accLogger.deleteFile(); - CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.data_deleted), null, null); + CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.data_deleted), null, null, Snackbar.LENGTH_LONG); } else - CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.nothing_to_delete), null, null); + CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.nothing_to_delete), null, null, Snackbar.LENGTH_LONG); break; case R.id.show_map: if (ContextCompat.checkSelfPermission(this, @@ -237,6 +241,9 @@ public void onClick(DialogInterface dialogInterface, int i) { settingIntent.putExtra("title", getResources().getString(R.string.accelerometer_configurations)); startActivity(settingIntent); break; + case android.R.id.home: + this.finish(); + break; default: break; } diff --git a/app/src/main/java/io/pslab/activity/BarometerActivity.java b/app/src/main/java/io/pslab/activity/BarometerActivity.java index 657da8079..dc4e5d02a 100644 --- a/app/src/main/java/io/pslab/activity/BarometerActivity.java +++ b/app/src/main/java/io/pslab/activity/BarometerActivity.java @@ -1,403 +1,122 @@ package io.pslab.activity; -import android.annotation.SuppressLint; -import android.content.DialogInterface; import android.content.SharedPreferences; -import android.graphics.Color; -import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; -import android.hardware.SensorManager; -import android.os.AsyncTask; -import android.os.Bundle; -import android.os.Handler; -import android.support.annotation.NonNull; -import android.support.design.widget.BottomSheetBehavior; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; -import android.view.GestureDetector; -import android.view.MotionEvent; -import android.view.View; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; +import android.support.v4.app.Fragment; +import android.support.v7.preference.PreferenceManager; -import com.github.anastr.speedviewlib.PointerSpeedometer; -import com.github.mikephil.charting.charts.LineChart; -import com.github.mikephil.charting.components.Legend; -import com.github.mikephil.charting.components.XAxis; -import com.github.mikephil.charting.components.YAxis; -import com.github.mikephil.charting.data.Entry; -import com.github.mikephil.charting.data.LineData; -import com.github.mikephil.charting.data.LineDataSet; +import io.pslab.R; +import io.pslab.fragment.BaroMeterDataFragment; +import io.pslab.fragment.BaroMeterSettingsFragment; +import io.pslab.models.BaroData; +import io.pslab.models.PSLabSensor; +import io.pslab.models.SensorDataBlock; +import io.pslab.others.LocalDataLog; +import io.realm.RealmObject; +import io.realm.RealmResults; -import java.io.IOException; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Arrays; +/** + * Created by Padmal on 12/13/18. + */ -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.Unbinder; -import io.pslab.R; -import io.pslab.communication.ScienceLab; -import io.pslab.communication.sensors.BMP180; -import io.pslab.others.MathUtils; -import io.pslab.others.ScienceLabCommon; -import io.pslab.others.SwipeGestureDetector; +public class BarometerActivity extends PSLabSensor { -public class BarometerActivity extends AppCompatActivity { private static final String PREF_NAME = "customDialogPreference"; - private static int sensorType = 0; - private static int highLimit = 20; - private static int updatePeriod = 100; - private final Object lock = new Object(); - BottomSheetBehavior bottomSheetBehavior; - GestureDetector gestureDetector; - @BindView(R.id.barometer_max) - TextView statMax; - @BindView(R.id.barometer_min) - TextView statMin; - @BindView(R.id.barometer_mean) - TextView statMean; - @BindView(R.id.chart_barometer) - LineChart mChart; - @BindView(R.id.barometer) - PointerSpeedometer barometer; - //bottomSheet - @BindView(R.id.bottom_sheet) - LinearLayout bottomSheet; - @BindView(R.id.shadow) - View tvShadow; - @BindView(R.id.img_arrow) - ImageView arrowUpDown; - @BindView(R.id.sheet_slide_text) - TextView bottomSheetSlideText; - @BindView(R.id.guide_title) - TextView bottomSheetGuideTitle; - @BindView(R.id.custom_dialog_text) - TextView bottomSheetText; - @BindView(R.id.custom_dialog_schematic) - ImageView bottomSheetSchematic; - @BindView(R.id.custom_dialog_desc) - TextView bottomSheetDesc; - private BarometerActivity.SensorDataFetch sensorDataFetch; - private BMP180 sensorBMP180 = null; - private SensorManager sensorManager; - private Sensor sensor; - private ScienceLab scienceLab; - private long startTime; - private int flag; - private ArrayList entries; - private float currentMin; - private float currentMax; - private YAxis y; - private volatile boolean monitor = true; - private Unbinder unbinder; + public final String BAROMETER_LIMIT = "barometer_limit"; + public RealmResults recordedBaroData; - public static BarometerActivity newInstance() { - return new BarometerActivity(); + @Override + public int getMenu() { + return R.menu.sensor_data_log_menu; } - @SuppressLint("ResourceType") @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_barometer_main); - ButterKnife.bind(this); - - setUpBottomSheet(); - - currentMin = 10000; - entries = new ArrayList<>(); - switch (sensorType) { - case 0: - sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); - sensor = sensorManager != null ? sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) : null; - if (sensor == null) { - runOnUiThread(new Runnable() { - @Override - public void run() { - if (!isFinishing()) { - new AlertDialog.Builder(BarometerActivity.this) - .setTitle(R.string.barometer_alert_title) - .setMessage(R.string.barometer_alert_description) - .setCancelable(false) - .setPositiveButton("ok", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }).show(); - } - } - }); - } - break; - case 1: - scienceLab = ScienceLabCommon.scienceLab; - break; - default: - break; - } - - Runnable runnable = new Runnable() { - @Override - public void run() { - if (flag == 0) { - startTime = System.currentTimeMillis(); - flag = 1; - switch (sensorType) { - case 0: - while (monitor) { - if (sensor != null) { - sensorDataFetch = new SensorDataFetch(); - sensorDataFetch.execute(); - synchronized (lock) { - try { - lock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - try { - Thread.sleep(updatePeriod); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - break; - case 1: - while (monitor) { - if (scienceLab.isConnected()) { - sensorDataFetch = new SensorDataFetch(); - sensorDataFetch.execute(); - synchronized (lock) { - try { - lock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - try { - Thread.sleep(updatePeriod); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - break; - default: - break; - } - } - } - }; - Thread dataThread = new Thread(runnable); - dataThread.start(); - - barometer.setMaxSpeed(100); - - XAxis x = mChart.getXAxis(); - this.y = mChart.getAxisLeft(); - YAxis y2 = mChart.getAxisRight(); - - mChart.setTouchEnabled(true); - mChart.setHighlightPerDragEnabled(true); - mChart.setDragEnabled(true); - mChart.setScaleEnabled(true); - mChart.setDrawGridBackground(false); - mChart.setPinchZoom(true); - mChart.setScaleYEnabled(false); - mChart.setBackgroundColor(Color.BLACK); - mChart.getDescription().setEnabled(false); - - LineData data = new LineData(); - mChart.setData(data); - - Legend l = mChart.getLegend(); - l.setForm(Legend.LegendForm.LINE); - l.setTextColor(Color.WHITE); - - x.setTextColor(Color.WHITE); - x.setDrawGridLines(true); - x.setAvoidFirstLastClipping(true); - - y.setTextColor(Color.WHITE); - y.setAxisMaximum(currentMax); - y.setAxisMinimum(currentMin); - y.setDrawGridLines(true); - y.setLabelCount(10); - - y2.setDrawGridLines(false); + public SharedPreferences getStateSettings() { + return this.getSharedPreferences(PREF_NAME, MODE_PRIVATE); } @Override - protected void onDestroy() { - super.onDestroy(); - monitor = false; - if (sensor != null && sensorDataFetch != null) { - sensorManager.unregisterListener(sensorDataFetch); - sensorDataFetch.cancel(true); - } + public String getFirstTimeSettingID() { + return "BaroMeterFirstTime"; } - private void setUpBottomSheet() { - bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet); - - final SharedPreferences settings = this.getSharedPreferences(PREF_NAME, MODE_PRIVATE); - Boolean isFirstTime = settings.getBoolean("BarometerFirstTime", true); - - bottomSheetGuideTitle.setText(R.string.barometer); - bottomSheetDesc.setText(R.string.barometer_intro); - bottomSheetSchematic.setImageResource(R.drawable.bmp180_schematic); - bottomSheetDesc.setText(R.string.barometer_desc); - - if (isFirstTime) { - bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); - tvShadow.setVisibility(View.VISIBLE); - tvShadow.setAlpha(0.8f); - arrowUpDown.setRotation(180); - bottomSheetSlideText.setText(R.string.hide_guide_text); - SharedPreferences.Editor editor = settings.edit(); - editor.putBoolean("BarometerFirstTime", false); - editor.apply(); - } else { - bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); - } - - bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { - private Handler handler = new Handler(); - private Runnable runnable = new Runnable() { - @Override - public void run() { - bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); - } - }; - - @Override - public void onStateChanged(@NonNull final View bottomSheet, int newState) { - switch (newState) { - case BottomSheetBehavior.STATE_EXPANDED: - handler.removeCallbacks(runnable); - bottomSheetSlideText.setText(R.string.hide_guide_text); - break; - - case BottomSheetBehavior.STATE_COLLAPSED: - handler.postDelayed(runnable, 2000); - break; - - default: - handler.removeCallbacks(runnable); - bottomSheetSlideText.setText(R.string.show_guide_text); - break; - } - } - - @Override - public void onSlide(@NonNull View bottomSheet, float slideOffset) { - Float value = (float) MathUtils.map((double) slideOffset, 0.0, 1.0, 0.0, 0.8); - tvShadow.setVisibility(View.VISIBLE); - tvShadow.setAlpha(value); - arrowUpDown.setRotation(slideOffset * 180); - } - }); - gestureDetector = new GestureDetector(this, new SwipeGestureDetector(bottomSheetBehavior)); + @Override + public String getSensorName() { + return getResources().getString(R.string.baro_meter); } @Override - public boolean onTouchEvent(MotionEvent event) { - gestureDetector.onTouchEvent(event); - return super.onTouchEvent(event); + public int getGuideTitle() { + return R.string.baro_meter; } - private class SensorDataFetch extends AsyncTask implements SensorEventListener { - - private float data; - private long timeElapsed; - private int count = 0; - private float sum = 0; - private DecimalFormat df = new DecimalFormat("#.##"); - - @Override - protected Void doInBackground(Void... params) { - try { - if (sensorBMP180 != null) { - data = Float.valueOf(Arrays.toString(sensorBMP180.getRaw())); - sensorManager.unregisterListener(this); - } else if (sensor != null) { - sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL); - } - } catch (IOException e) { - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return null; - } + @Override + public int getGuideAbstract() { + return R.string.baro_meter_intro; + } - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - visualizeData(); - synchronized (lock) { - lock.notify(); - } - } + @Override + public int getGuideSchematics() { + return R.drawable.bmp180_schematic; + } - @Override - public void onSensorChanged(SensorEvent event) { - data = Float.valueOf(df.format(event.values[0])); - data = data * 101325; // Convert hPa to atm unit - visualizeData(); - unRegisterListener(); - } + @Override + public int getGuideDescription() { + return R.string.baro_meter_desc; + } - @SuppressLint("SetTextI18n") - private void visualizeData() { - if (currentMax < data) { - currentMax = data; - statMax.setText(String.valueOf(data)); - } else if (currentMin > data) { - currentMin = data; - statMin.setText(String.valueOf(data)); - } + @Override + public int getGuideExtraContent() { + return 0; + } - y.setAxisMaximum(currentMax); - y.setAxisMinimum(currentMin); - y.setLabelCount(10); - barometer.setSpeedAt(data); + @Override + public void recordSensorDataBlockID(SensorDataBlock block) { + realm.beginTransaction(); + realm.copyToRealm(block); + realm.commitTransaction(); + } - if (data > highLimit) barometer.setIndicatorColor(Color.RED); - else barometer.setIndicatorColor(Color.WHITE); - timeElapsed = (System.currentTimeMillis() - startTime) / 1000; - entries.add(new Entry((float) timeElapsed, data)); + @Override + public void recordSensorData(RealmObject sensorData) { + realm.beginTransaction(); + realm.copyToRealm((BaroData) sensorData); + realm.commitTransaction(); + } - for (Entry item : entries) { - count++; - sum += item.getY(); - } - statMax.setText(String.valueOf(currentMax)); - statMin.setText(String.valueOf(currentMin)); - statMean.setText(Float.toString(Float.valueOf(df.format(sum / count)))); + @Override + public void stopRecordSensorData() { + LocalDataLog.with().refresh(); + } - LineDataSet dataSet = new LineDataSet(entries, getString(R.string.barometer)); - LineData data = new LineData(dataSet); - dataSet.setDrawCircles(false); + @Override + public Fragment getSensorFragment() { + return BaroMeterDataFragment.newInstance(); + } - mChart.setData(data); - mChart.notifyDataSetChanged(); - mChart.invalidate(); + @Override + public void getDataFromDataLogger() { + if (getIntent().getExtras() != null && getIntent().getExtras().getBoolean(KEY_LOG)) { + viewingData = true; + recordedBaroData = LocalDataLog.with() + .getBlockOfBaroRecords(getIntent().getExtras().getLong(DATA_BLOCK)); + String title = titleFormat.format(recordedBaroData.get(0).getTime()); + getSupportActionBar().setTitle(title); } + } + @Override + protected void onResume() { + super.onResume(); + reinstateConfigurations(); + } - @Override - public void onAccuracyChanged(Sensor sensor, int accuracy) { - //do nothing - } - - private void unRegisterListener() { - sensorManager.unregisterListener(this); - } + private void reinstateConfigurations() { + SharedPreferences luxMeterConfigurations; + luxMeterConfigurations = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); + locationEnabled = luxMeterConfigurations.getBoolean(BaroMeterSettingsFragment.KEY_INCLUDE_LOCATION, true); + BaroMeterDataFragment.setParameters( + Float.valueOf(luxMeterConfigurations.getString(BaroMeterSettingsFragment.KEY_HIGH_LIMIT, "1.1")), + Integer.valueOf(luxMeterConfigurations.getString(BaroMeterSettingsFragment.KEY_UPDATE_PERIOD, "1000")), + luxMeterConfigurations.getString(BaroMeterSettingsFragment.KEY_BARO_SENSOR_TYPE, "0")); } } diff --git a/app/src/main/java/io/pslab/activity/CompassActivity.java b/app/src/main/java/io/pslab/activity/CompassActivity.java index 8f67e83fe..21b1d1e15 100644 --- a/app/src/main/java/io/pslab/activity/CompassActivity.java +++ b/app/src/main/java/io/pslab/activity/CompassActivity.java @@ -9,6 +9,7 @@ import android.os.Handler; import android.support.annotation.NonNull; import android.support.design.widget.BottomSheetBehavior; +import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.GestureDetector; @@ -56,7 +57,7 @@ public class CompassActivity extends AppCompatActivity implements SensorEventLis @BindView(R.id.tv_sensor_hmc5883l_by) TextView yAxisMagneticField; @BindView(R.id.tv_sensor_hmc5883l_bz) - TextView zAxismagneticField; + TextView zAxisMagneticField; @BindView(R.id.compass_toolbar) Toolbar mToolbar; @@ -92,6 +93,8 @@ protected void onCreate(Bundle savedInstanceState) { ButterKnife.bind(this); setSupportActionBar(mToolbar); + ActionBar actionBar = getSupportActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); compassPreference = getSharedPreferences(PREFS_NAME, MODE_PRIVATE); setUpBottomSheet(); @@ -160,20 +163,22 @@ public void onSensorChanged(SensorEvent event) { float degree; switch (direction) { case 0: - degree = Math.round(event.values[1]); + degree = Math.round(event.values[0]); if (degree < 0) degree += 360; break; case 1: - degree = Math.round(event.values[2]); + degree = Math.round(event.values[1]); if (degree < 0) degree += 360; break; case 2: - degree = Math.round(event.values[0]); + degree = Math.round(event.values[2]); + if (degree < 0) + degree += 360; break; default: - degree = Math.round(event.values[1]); + degree = Math.round(event.values[0]); break; } @@ -181,6 +186,21 @@ public void onSensorChanged(SensorEvent event) { degreeIndicator.setText(String.valueOf(degree)); currentDegree = -degree; + + degree = Math.round(event.values[0]); + if (degree < 0) + degree += 360; + xAxisMagneticField.setText(String.valueOf(degree)); + + degree = Math.round(event.values[1]); + if (degree < 0) + degree += 360; + yAxisMagneticField.setText(String.valueOf(degree)); + + degree = Math.round(event.values[2]); + if (degree < 0) + degree += 360; + zAxisMagneticField.setText(String.valueOf(degree)); } @Override @@ -295,6 +315,9 @@ public boolean onOptionsItemSelected(MenuItem item) { bottomSheetBehavior.setState(bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_HIDDEN ? BottomSheetBehavior.STATE_EXPANDED : BottomSheetBehavior.STATE_HIDDEN); break; + case android.R.id.home: + this.finish(); + break; default: break; } diff --git a/app/src/main/java/io/pslab/activity/DataLoggerActivity.java b/app/src/main/java/io/pslab/activity/DataLoggerActivity.java index 7c3e9fd7e..b8b2eaace 100644 --- a/app/src/main/java/io/pslab/activity/DataLoggerActivity.java +++ b/app/src/main/java/io/pslab/activity/DataLoggerActivity.java @@ -48,11 +48,14 @@ protected void onCreate(Bundle savedInstanceState) { switch (caller) { case "Lux Meter": getSupportActionBar().setTitle(caller); - categoryData = LocalDataLog.with().getTypeOfSensorBlocks("Lux Meter"); + categoryData = LocalDataLog.with().getTypeOfSensorBlocks(getString(R.string.lux_meter)); + break; + case "Baro Meter": + getSupportActionBar().setTitle(caller); + categoryData = LocalDataLog.with().getTypeOfSensorBlocks(getString(R.string.baro_meter)); break; default: - // TODO: Fetch all - categoryData = LocalDataLog.with().getTypeOfSensorBlocks("Lux Meter"); + categoryData = LocalDataLog.with().getAllSensorBlocks(); getSupportActionBar().setTitle(getString(R.string.logged_data)); } diff --git a/app/src/main/java/io/pslab/activity/LuxMeterActivity.java b/app/src/main/java/io/pslab/activity/LuxMeterActivity.java index 1b8ded58e..6f939664f 100644 --- a/app/src/main/java/io/pslab/activity/LuxMeterActivity.java +++ b/app/src/main/java/io/pslab/activity/LuxMeterActivity.java @@ -17,16 +17,12 @@ public class LuxMeterActivity extends PSLabSensor { private static final String PREF_NAME = "customDialogPreference"; + public final String LUXMETER_LIMIT = "luxmeter_limit"; public RealmResults recordedLuxData; - @Override - public int getLayout() { - return R.layout.activity_generic_sensor; - } - @Override public int getMenu() { - return R.menu.lux_data_log_menu; + return R.menu.sensor_data_log_menu; } @Override @@ -96,7 +92,8 @@ public Fragment getSensorFragment() { @Override public void getDataFromDataLogger() { if (getIntent().getExtras() != null && getIntent().getExtras().getBoolean(KEY_LOG)) { - playingData = true; + //playingData = true; + viewingData = true; recordedLuxData = LocalDataLog.with() .getBlockOfLuxRecords(getIntent().getExtras().getLong(DATA_BLOCK)); String title = titleFormat.format(recordedLuxData.get(0).getTime()); @@ -106,6 +103,7 @@ public void getDataFromDataLogger() { /** * Once settings have been changed, those changes can be captured from onResume method. + * reinstateConfigurations() will update the logs with new settings */ @Override protected void onResume() { diff --git a/app/src/main/java/io/pslab/activity/MultimeterActivity.java b/app/src/main/java/io/pslab/activity/MultimeterActivity.java index 69dbbb073..fa60ea528 100644 --- a/app/src/main/java/io/pslab/activity/MultimeterActivity.java +++ b/app/src/main/java/io/pslab/activity/MultimeterActivity.java @@ -2,21 +2,20 @@ import android.Manifest; import android.app.AlertDialog; -import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.graphics.Typeface; -import android.location.Location; -import android.location.LocationManager; import android.os.Bundle; import android.os.Handler; import android.support.annotation.NonNull; import android.support.design.widget.BottomSheetBehavior; import android.support.design.widget.CoordinatorLayout; +import android.support.design.widget.Snackbar; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; +import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.SwitchCompat; import android.support.v7.widget.Toolbar; @@ -30,26 +29,20 @@ import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.LinearLayout; - import android.widget.TextView; -import com.github.mikephil.charting.data.Entry; +import java.text.DecimalFormat; +import java.util.Locale; +import butterknife.BindView; +import butterknife.ButterKnife; import io.pslab.R; import io.pslab.communication.ScienceLab; import io.pslab.others.CSVLogger; import io.pslab.others.CustomSnackBar; -import io.pslab.others.GPSLogger; import io.pslab.others.MathUtils; import io.pslab.others.ScienceLabCommon; import io.pslab.others.SwipeGestureDetector; - -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Locale; - -import butterknife.BindView; -import butterknife.ButterKnife; import it.beppi.knoblibrary.Knob; /** @@ -117,6 +110,8 @@ protected void onCreate(final Bundle savedInstanceState) { scienceLab = ScienceLabCommon.scienceLab; knobMarker = getResources().getStringArray(io.pslab.R.array.multimeter_knob_states); setSupportActionBar(mToolbar); + ActionBar actionBar = getSupportActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); setUpBottomSheet(); tvShadow.setOnClickListener(new View.OnClickListener() { @@ -408,7 +403,7 @@ public boolean onOptionsItemSelected(MenuItem item) { if (recordData) { item.setIcon(R.drawable.ic_record_white); recordData = false; - CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.data_recording_paused), null, null); + CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.data_recording_paused), null, null, Snackbar.LENGTH_LONG); } else { isDataRecorded = true; item.setIcon(R.drawable.pause_icon); @@ -416,7 +411,7 @@ public boolean onOptionsItemSelected(MenuItem item) { multimeterLogger = new CSVLogger(getString(R.string.multimeter)); isRecordingStarted = true; recordData = true; - CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.data_recording_start), null, null); + CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.data_recording_start), null, null, Snackbar.LENGTH_LONG); } } break; @@ -446,11 +441,11 @@ public void onClick(DialogInterface dialogInterface, int i) { .create() .show(); } - }); + }, Snackbar.LENGTH_LONG); isRecordingStarted = false; recordData = false; } else { - CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.nothing_to_export), null, null); + CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.nothing_to_export), null, null, Snackbar.LENGTH_LONG); } break; case R.id.delete_csv_data: @@ -461,15 +456,18 @@ public void onClick(DialogInterface dialogInterface, int i) { isRecordingStarted = false; isDataRecorded = false; multimeterLogger.deleteFile(); - CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.data_deleted), null, null); + CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.data_deleted), null, null, Snackbar.LENGTH_LONG); } else - CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.nothing_to_delete), null, null); + CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.nothing_to_delete), null, null, Snackbar.LENGTH_LONG); break; case R.id.settings: Intent settingIntent = new Intent(this, SettingsActivity.class); settingIntent.putExtra("title", getResources().getString(R.string.multimeter_configurations)); startActivity(settingIntent); break; + case android.R.id.home: + this.finish(); + break; default: break; } diff --git a/app/src/main/java/io/pslab/activity/PowerSourceActivity.java b/app/src/main/java/io/pslab/activity/PowerSourceActivity.java index d8abc788b..ca1dc6f9d 100644 --- a/app/src/main/java/io/pslab/activity/PowerSourceActivity.java +++ b/app/src/main/java/io/pslab/activity/PowerSourceActivity.java @@ -7,6 +7,7 @@ import android.support.annotation.NonNull; import android.support.design.widget.BottomSheetBehavior; import android.support.v4.widget.TextViewCompat; +import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.GestureDetector; @@ -125,6 +126,8 @@ protected void onCreate(Bundle savedInstanceState) { ButterKnife.bind(this); setSupportActionBar(toolbar); + ActionBar actionBar = getSupportActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); powerPreferences = getSharedPreferences(POWER_PREFERENCES, MODE_PRIVATE); @@ -263,6 +266,9 @@ public boolean onOptionsItemSelected(MenuItem item) { bottomSheetBehavior.setState(bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_HIDDEN ? BottomSheetBehavior.STATE_EXPANDED : BottomSheetBehavior.STATE_HIDDEN); break; + case android.R.id.home: + this.finish(); + break; default: break; } diff --git a/app/src/main/java/io/pslab/activity/SensorGraphViewActivity.java b/app/src/main/java/io/pslab/activity/SensorGraphViewActivity.java index 49b931f86..503243689 100644 --- a/app/src/main/java/io/pslab/activity/SensorGraphViewActivity.java +++ b/app/src/main/java/io/pslab/activity/SensorGraphViewActivity.java @@ -9,6 +9,7 @@ import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.CoordinatorLayout; +import android.support.design.widget.Snackbar; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; @@ -253,7 +254,7 @@ private void exportData() { } luxLogger.writeCSVFile(data); } - CustomSnackBar.showSnackBar(cl, getResources().getString(R.string.csv_store_text) + luxLogger.getCurrentFilePath(), null, null); + CustomSnackBar.showSnackBar(cl, getResources().getString(R.string.csv_store_text) + luxLogger.getCurrentFilePath(), null, null, Snackbar.LENGTH_LONG); } private void simulateData() { diff --git a/app/src/main/java/io/pslab/activity/SettingsActivity.java b/app/src/main/java/io/pslab/activity/SettingsActivity.java index b05e6fedf..5f8aa80d8 100644 --- a/app/src/main/java/io/pslab/activity/SettingsActivity.java +++ b/app/src/main/java/io/pslab/activity/SettingsActivity.java @@ -17,8 +17,10 @@ import butterknife.ButterKnife; import butterknife.Unbinder; import io.pslab.R; +import io.pslab.fragment.BaroMeterSettingsFragment; import io.pslab.fragment.LuxMeterSettingFragment; import io.pslab.fragment.SettingsFragment; +import io.pslab.models.PSLabSensor; import io.pslab.others.GPSLogger; /** @@ -52,9 +54,12 @@ protected void onCreate(Bundle savedInstanceState) { Fragment fragment; switch (title) { - case "Lux Meter": + case PSLabSensor.LUXMETER: fragment = new LuxMeterSettingFragment(); break; + case PSLabSensor.BAROMETER: + fragment = new BaroMeterSettingsFragment(); + break; default: fragment = new SettingsFragment(); break; diff --git a/app/src/main/java/io/pslab/activity/SplashActivity.java b/app/src/main/java/io/pslab/activity/SplashActivity.java index 048f94b65..091c2762e 100644 --- a/app/src/main/java/io/pslab/activity/SplashActivity.java +++ b/app/src/main/java/io/pslab/activity/SplashActivity.java @@ -6,6 +6,7 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; +import android.widget.ImageView; import butterknife.ButterKnife; import io.pslab.R; @@ -19,12 +20,18 @@ public class SplashActivity extends AppCompatActivity { private Handler handler; private Runnable runnable; + private ImageView logo; + private ImageView text; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.splash_screen); ButterKnife.bind(this); + logo = findViewById(R.id.imageView); + text = findViewById(R.id.PSLabText); + logo.animate().alpha(1f).setDuration(2500); + text.animate().alpha(1f).setDuration(2500); PSLabPermission psLabPermission = PSLabPermission.getInstance(); if (psLabPermission.checkPermissions(SplashActivity.this, PSLabPermission.ALL_PERMISSION)) { diff --git a/app/src/main/java/io/pslab/adapters/SensorLoggerListAdapter.java b/app/src/main/java/io/pslab/adapters/SensorLoggerListAdapter.java index 8134eff01..06f58e26f 100644 --- a/app/src/main/java/io/pslab/adapters/SensorLoggerListAdapter.java +++ b/app/src/main/java/io/pslab/adapters/SensorLoggerListAdapter.java @@ -1,8 +1,11 @@ package io.pslab.adapters; import android.app.Activity; +import android.content.DialogInterface; import android.content.Intent; +import android.os.Environment; import android.support.annotation.NonNull; +import android.support.v7.app.AlertDialog; import android.support.v7.widget.CardView; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; @@ -16,15 +19,18 @@ import org.json.JSONException; import org.json.JSONObject; -import java.text.SimpleDateFormat; +import java.io.File; import java.util.Date; -import java.util.Locale; import io.pslab.R; +import io.pslab.activity.BarometerActivity; import io.pslab.activity.LuxMeterActivity; import io.pslab.activity.MapsActivity; +import io.pslab.models.BaroData; import io.pslab.models.LuxData; +import io.pslab.models.PSLabSensor; import io.pslab.models.SensorDataBlock; +import io.pslab.others.CSVLogger; import io.pslab.others.LocalDataLog; import io.realm.RealmRecyclerViewAdapter; import io.realm.RealmResults; @@ -37,7 +43,6 @@ public class SensorLoggerListAdapter extends RealmRecyclerViewAdapter data = LocalDataLog.with().getBlockOfLuxRecords(block.getBlock()); - JSONArray array = new JSONArray(); - for (LuxData d : data) { - try { - JSONObject i = new JSONObject(); - i.put("date", sdf.format(d.getTime())); - i.put("data", d.getLux()); - i.put("lon", d.getLon()); - i.put("lat", d.getLat()); - if (d.getLat() != 0.0 && d.getLon() != 0.0) array.put(i); - } catch (JSONException e) { - e.printStackTrace(); + populateMapData(block); + } + }); + } + + private void handleCardViewClick(SensorDataBlock block) { + if (block.getSensorType().equalsIgnoreCase(context.getResources().getString(R.string.lux_meter))) { + Intent LuxMeter = new Intent(context, LuxMeterActivity.class); + LuxMeter.putExtra(KEY_LOG, true); + LuxMeter.putExtra(DATA_BLOCK, block.getBlock()); + context.startActivity(LuxMeter); + } else if (block.getSensorType().equalsIgnoreCase(context.getResources().getString(R.string.baro_meter))) { + Intent BaroMeter = new Intent(context, BarometerActivity.class); + BaroMeter.putExtra(KEY_LOG, true); + BaroMeter.putExtra(DATA_BLOCK, block.getBlock()); + context.startActivity(BaroMeter); + } + } + + private void handleDeleteItem(final SensorDataBlock block) { + new AlertDialog.Builder(context) + .setTitle(context.getString(R.string.delete)) + .setMessage(context.getString(R.string.delete_confirmation) + " " + + CSVLogger.FILE_NAME_FORMAT.format(block.getBlock()) + "?") + .setPositiveButton(context.getString(R.string.delete), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + File logDirectory = new File( + Environment.getExternalStorageDirectory().getAbsolutePath() + + File.separator + CSVLogger.CSV_DIRECTORY + + File.separator + block.getSensorType() + + File.separator + CSVLogger.FILE_NAME_FORMAT.format(block.getBlock()) + ".csv"); + Toast.makeText(context, logDirectory.delete() + ? context.getString(R.string.log_deleted) + : context.getString(R.string.nothing_to_delete), + Toast.LENGTH_LONG).show(); + if (block.getSensorType().equalsIgnoreCase(PSLabSensor.LUXMETER)) { + LocalDataLog.with().clearBlockOfLuxRecords(block.getBlock()); + } else if (block.getSensorType().equalsIgnoreCase(PSLabSensor.BAROMETER)) { + LocalDataLog.with().clearBlockOfBaroRecords(block.getBlock()); } + LocalDataLog.with().clearSensorBlock(block.getBlock()); + dialog.dismiss(); } - Intent map = new Intent(context, MapsActivity.class); - if (array.length() > 0) { - map.putExtra("hasMarkers", true); - map.putExtra("markers", array.toString()); - context.startActivity(map); - } else { - map.putExtra("hasMarkers", false); - Toast.makeText(context, context.getResources().getString(R.string.no_location_data), Toast.LENGTH_LONG).show(); + }) + .setNegativeButton(context.getString(R.string.cancel), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); } + }) + .create().show(); + } + private void populateMapData(SensorDataBlock block) { + if (block.getSensorType().equalsIgnoreCase(PSLabSensor.LUXMETER)) { + RealmResults data = LocalDataLog.with().getBlockOfLuxRecords(block.getBlock()); + JSONArray array = new JSONArray(); + for (LuxData d : data) { + try { + JSONObject i = new JSONObject(); + i.put("date", CSVLogger.FILE_NAME_FORMAT.format(d.getTime())); + i.put("data", d.getLux()); + i.put("lon", d.getLon()); + i.put("lat", d.getLat()); + if (d.getLat() != 0.0 && d.getLon() != 0.0) array.put(i); + } catch (JSONException e) { + e.printStackTrace(); } } - }); + setMapDataToIntent(array); + } else if (block.getSensorType().equalsIgnoreCase(PSLabSensor.BAROMETER)) { + RealmResults data = LocalDataLog.with().getBlockOfBaroRecords(block.getBlock()); + JSONArray array = new JSONArray(); + for (BaroData d : data) { + try { + JSONObject i = new JSONObject(); + i.put("date", CSVLogger.FILE_NAME_FORMAT.format(d.getTime())); + i.put("data", d.getBaro()); + i.put("lon", d.getLon()); + i.put("lat", d.getLat()); + if (d.getLat() != 0.0 && d.getLon() != 0.0) array.put(i); + } catch (JSONException e) { + e.printStackTrace(); + } + } + setMapDataToIntent(array); + } + } + + private void setMapDataToIntent(JSONArray array) { + Intent map = new Intent(context, MapsActivity.class); + if (array.length() > 0) { + map.putExtra("hasMarkers", true); + map.putExtra("markers", array.toString()); + context.startActivity(map); + } else { + map.putExtra("hasMarkers", false); + Toast.makeText(context, context.getResources().getString(R.string.no_location_data), Toast.LENGTH_LONG).show(); + } } public class ViewHolder extends RecyclerView.ViewHolder { private TextView sensor, dateTime; - private ImageView deleteIcon, mapIcon; + private ImageView deleteIcon, mapIcon, tileIcon; private CardView cardView; public ViewHolder(View itemView) { @@ -125,6 +202,7 @@ public ViewHolder(View itemView) { sensor = itemView.findViewById(R.id.sensor_name); deleteIcon = itemView.findViewById(R.id.delete_item); mapIcon = itemView.findViewById(R.id.map_item); + tileIcon = itemView.findViewById(R.id.sensor_tile_icon); cardView = itemView.findViewById(R.id.data_item_card); } } diff --git a/app/src/main/java/io/pslab/fragment/BaroMeterDataFragment.java b/app/src/main/java/io/pslab/fragment/BaroMeterDataFragment.java new file mode 100644 index 000000000..edf34cd63 --- /dev/null +++ b/app/src/main/java/io/pslab/fragment/BaroMeterDataFragment.java @@ -0,0 +1,541 @@ +package io.pslab.fragment; + +import android.graphics.Color; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.location.Location; +import android.os.Bundle; +import android.os.Handler; +import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; +import android.support.v7.preference.PreferenceManager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import android.widget.Toast; + +import com.github.anastr.speedviewlib.PointerSpeedometer; +import com.github.mikephil.charting.charts.LineChart; +import com.github.mikephil.charting.components.Legend; +import com.github.mikephil.charting.components.XAxis; +import com.github.mikephil.charting.components.YAxis; +import com.github.mikephil.charting.data.Entry; +import com.github.mikephil.charting.data.LineData; +import com.github.mikephil.charting.data.LineDataSet; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.Locale; +import java.util.Timer; +import java.util.TimerTask; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; +import io.pslab.R; +import io.pslab.activity.BarometerActivity; +import io.pslab.communication.ScienceLab; +import io.pslab.communication.peripherals.I2C; +import io.pslab.communication.sensors.BMP180; +import io.pslab.models.BaroData; +import io.pslab.models.PSLabSensor; +import io.pslab.models.SensorDataBlock; +import io.pslab.others.CSVLogger; +import io.pslab.others.ScienceLabCommon; + +import static android.content.Context.SENSOR_SERVICE; + +/** + * Created by Padmal on 12/13/18. + */ + +public class BaroMeterDataFragment extends Fragment { + + private static int sensorType = 0; + private static float highLimit = 1.2f; + private static int updatePeriod = 1000; + private long timeElapsed; + private int count = 0, turns = 0; + private float sum = 0; + private boolean returningFromPause = false; + + private float baroValue = -1; + + private enum BARO_SENSOR {INBUILT_SENSOR, BMP180_SENSOR} + + @BindView(R.id.baro_max) + TextView statMax; + @BindView(R.id.baro_min) + TextView statMin; + @BindView(R.id.baro_avg) + TextView statMean; + @BindView(R.id.label_baro_sensor) + TextView sensorLabel; + @BindView(R.id.chart_baro_meter) + LineChart mChart; + @BindView(R.id.baro_meter) + PointerSpeedometer baroMeter; + + private Timer graphTimer; + private SensorManager sensorManager; + private Sensor sensor; + private long startTime, block; + private ArrayList entries; + private ArrayList recordedBaroArray; + private BaroData sensorData; + private float currentMin = 2; + private float currentMax = 0.5f; + private YAxis y; + private Unbinder unbinder; + private long previousTimeElapsed = (System.currentTimeMillis() - startTime) / updatePeriod; + private BarometerActivity baroSensor; + + public static BaroMeterDataFragment newInstance() { + return new BaroMeterDataFragment(); + } + + public static void setParameters(float highLimit, int updatePeriod, String type) { + BaroMeterDataFragment.highLimit = highLimit; + BaroMeterDataFragment.updatePeriod = updatePeriod; + BaroMeterDataFragment.sensorType = Integer.valueOf(type); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + startTime = System.currentTimeMillis(); + entries = new ArrayList<>(); + baroSensor = (BarometerActivity) getActivity(); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_barometer_data, container, false); + unbinder = ButterKnife.bind(this, view); + setupInstruments(); + return view; + } + + @Override + public void onResume() { + super.onResume(); + if (baroSensor.playingData) { + sensorLabel.setText(getResources().getString(R.string.baro_meter)); + recordedBaroArray = new ArrayList<>(); + resetInstrumentData(); + playRecordedData(); + } else if (baroSensor.viewingData) { + sensorLabel.setText(getResources().getString(R.string.baro_meter)); + recordedBaroArray = new ArrayList<>(); + resetInstrumentData(); + plotAllRecordedData(); + } else if (!baroSensor.isRecording) { + updateGraphs(); + sum = 0; + count = 0; + currentMin = 2; + currentMax = 0.5f; + entries.clear(); + mChart.clear(); + mChart.invalidate(); + initiateBaroSensor(sensorType); + } else if (returningFromPause) { + updateGraphs(); + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + if (graphTimer != null) { + graphTimer.cancel(); + } + if (sensorManager != null) { + sensorManager.unregisterListener(baroSensorEventListener); + } + unbinder.unbind(); + } + + private void plotAllRecordedData() { + recordedBaroArray.addAll(baroSensor.recordedBaroData); + if (recordedBaroArray.size() != 0) { + for (BaroData d : recordedBaroArray) { + if (currentMax < d.getBaro()) { + currentMax = d.getBaro(); + } + if (currentMin > d.getBaro()) { + currentMin = d.getBaro(); + } + Entry entry = new Entry((float) (d.getTime() - d.getBlock()) / 1000, d.getBaro()); + entries.add(entry); + baroMeter.setWithTremble(false); + baroMeter.setSpeedAt(d.getBaro()); + sum += entry.getY(); + } + y.setAxisMaximum(currentMax); + y.setAxisMinimum(currentMin); + y.setLabelCount(10); + statMax.setText(String.valueOf(currentMax)); + statMin.setText(String.valueOf(currentMin)); + statMean.setText(String.format(Locale.getDefault(), PSLabSensor.BAROMETER_DATA_FORMAT, (sum / recordedBaroArray.size()))); + + LineDataSet dataSet = new LineDataSet(entries, getString(R.string.baro_unit)); + dataSet.setDrawCircles(false); + dataSet.setDrawValues(false); + dataSet.setLineWidth(2); + LineData data = new LineData(dataSet); + + mChart.setData(data); + mChart.notifyDataSetChanged(); + mChart.setVisibleXRangeMaximum(80); + mChart.moveViewToX(data.getEntryCount()); + mChart.invalidate(); + } + } + + private void playRecordedData() { + recordedBaroArray.addAll(baroSensor.recordedBaroData); + try { + if (recordedBaroArray.size() > 1) { + BaroData i = recordedBaroArray.get(1); + long timeGap = i.getTime() - i.getBlock(); + processRecordedData(timeGap); + } else { + processRecordedData(0); + } + } catch (IllegalArgumentException e) { + Toast.makeText(getActivity(), + getActivity().getResources().getString(R.string.no_data_fetched), Toast.LENGTH_SHORT).show(); + } + } + + private void processRecordedData(long timeGap) { + final Handler handler = new Handler(); + if (graphTimer != null) { + graphTimer.cancel(); + } else { + graphTimer = new Timer(); + } + graphTimer.schedule(new TimerTask() { + @Override + public void run() { + handler.post(new Runnable() { + @Override + public void run() { + if (baroSensor.playingData) { + try { + BaroData d = recordedBaroArray.get(turns); + turns++; + if (currentMax < d.getBaro()) { + currentMax = d.getBaro(); + statMax.setText(String.valueOf(d.getBaro())); + } + if (currentMin > d.getBaro()) { + currentMin = d.getBaro(); + statMin.setText(String.valueOf(d.getBaro())); + } + y.setAxisMaximum(currentMax); + y.setAxisMinimum(currentMin); + y.setLabelCount(10); + baroMeter.setWithTremble(false); + baroMeter.setSpeedAt(d.getBaro()); + + Entry entry = new Entry((float) (d.getTime() - d.getBlock()) / 1000, d.getBaro()); + entries.add(entry); + count++; + sum += entry.getY(); + statMean.setText(String.format(Locale.getDefault(), PSLabSensor.BAROMETER_DATA_FORMAT, (sum / count))); + + LineDataSet dataSet = new LineDataSet(entries, getString(R.string.baro_unit)); + dataSet.setDrawCircles(false); + dataSet.setDrawValues(false); + dataSet.setLineWidth(2); + LineData data = new LineData(dataSet); + + mChart.setData(data); + mChart.notifyDataSetChanged(); + mChart.setVisibleXRangeMaximum(80); + mChart.moveViewToX(data.getEntryCount()); + mChart.invalidate(); + } catch (IndexOutOfBoundsException e) { + graphTimer.cancel(); + graphTimer = null; + turns = 0; + baroSensor.playingData = false; + baroSensor.startedPlay = false; + baroSensor.invalidateOptionsMenu(); + } + } + } + }); + } + }, 0, timeGap); + } + + public void playData() { + resetInstrumentData(); + baroSensor.startedPlay = true; + try { + if (recordedBaroArray.size() > 1) { + BaroData i = recordedBaroArray.get(1); + long timeGap = i.getTime() - i.getBlock(); + processRecordedData(timeGap); + } else { + processRecordedData(0); + } + } catch (IllegalArgumentException e) { + Toast.makeText(getActivity(), + getActivity().getResources().getString(R.string.no_data_fetched), Toast.LENGTH_SHORT).show(); + } + } + + public void stopData() { + if (graphTimer != null) { + graphTimer.cancel(); + graphTimer = null; + } + recordedBaroArray.clear(); + entries.clear(); + plotAllRecordedData(); + baroSensor.startedPlay = false; + baroSensor.playingData = false; + turns = 0; + baroSensor.invalidateOptionsMenu(); + } + + public void saveGraph() { + // Todo: Save graph view to gallery + } + + private void setupInstruments() { + baroMeter.setMaxSpeed(PreferenceManager.getDefaultSharedPreferences(getActivity()).getFloat(baroSensor.BAROMETER_LIMIT, 2)); + XAxis x = mChart.getXAxis(); + this.y = mChart.getAxisLeft(); + YAxis y2 = mChart.getAxisRight(); + + mChart.setTouchEnabled(true); + mChart.setHighlightPerDragEnabled(true); + mChart.setDragEnabled(true); + mChart.setScaleEnabled(true); + mChart.setDrawGridBackground(false); + mChart.setPinchZoom(true); + mChart.setScaleYEnabled(true); + mChart.setBackgroundColor(Color.BLACK); + mChart.getDescription().setEnabled(false); + + LineData data = new LineData(); + mChart.setData(data); + + Legend l = mChart.getLegend(); + l.setForm(Legend.LegendForm.LINE); + l.setTextColor(Color.WHITE); + + x.setTextColor(Color.WHITE); + x.setDrawGridLines(true); + x.setAvoidFirstLastClipping(true); + + y.setTextColor(Color.WHITE); + y.setAxisMaximum(currentMax); + y.setAxisMinimum(currentMin); + y.setDrawGridLines(true); + y.setLabelCount(10); + + y2.setDrawGridLines(false); + y2.setMaxWidth(0); + } + + @Override + public void onPause() { + super.onPause(); + if (graphTimer != null) { + returningFromPause = true; + graphTimer.cancel(); + graphTimer = null; + if (baroSensor.playingData) { + baroSensor.finish(); + } + } + } + + private void updateGraphs() { + final Handler handler = new Handler(); + if (graphTimer != null) { + graphTimer.cancel(); + } + graphTimer = new Timer(); + graphTimer.schedule(new TimerTask() { + @Override + public void run() { + handler.post(new Runnable() { + @Override + public void run() { + try { + visualizeData(); + } catch (NullPointerException e) { + /* Pass for another refresh round */ + } + } + }); + } + }, 0, updatePeriod); + } + + private void writeLogToFile(long timestamp, float sensorReading) { + if (getActivity() != null && baroSensor.isRecording) { + if (baroSensor.writeHeaderToFile) { + baroSensor.csvLogger.prepareLogFile(); + baroSensor.csvLogger.writeCSVFile("Timestamp,DateTime,Readings,Latitude,Longitude"); + block = timestamp; + baroSensor.recordSensorDataBlockID(new SensorDataBlock(timestamp, baroSensor.getSensorName())); + baroSensor.writeHeaderToFile = !baroSensor.writeHeaderToFile; + } + if (baroSensor.addLocation && baroSensor.gpsLogger.isGPSEnabled()) { + String dateTime = CSVLogger.FILE_NAME_FORMAT.format(new Date(timestamp)); + Location location = baroSensor.gpsLogger.getDeviceLocation(); + baroSensor.csvLogger.writeCSVFile(timestamp + "," + dateTime + "," + + sensorReading + "," + location.getLatitude() + "," + location.getLongitude()); + sensorData = new BaroData(timestamp, block, baroValue, location.getLatitude(), location.getLongitude()); + } else { + String dateTime = CSVLogger.FILE_NAME_FORMAT.format(new Date(timestamp)); + baroSensor.csvLogger.writeCSVFile(timestamp + "," + dateTime + "," + + sensorReading + ",0.0,0.0"); + sensorData = new BaroData(timestamp, block, baroValue, 0.0, 0.0); + } + baroSensor.recordSensorData(sensorData); + } else { + baroSensor.writeHeaderToFile = true; + } + } + + private void visualizeData() { + if (currentMax < baroValue) { + currentMax = baroValue; + statMax.setText(String.valueOf(baroValue)); + } + if (currentMin > baroValue) { + currentMin = baroValue; + statMin.setText(String.valueOf(baroValue)); + } + y.setAxisMaximum(currentMax); + y.setAxisMinimum(currentMin); + y.setLabelCount(10); + if (baroValue >= 0) { + baroMeter.setWithTremble(false); + baroMeter.setSpeedAt(baroValue); + if (baroValue > highLimit) + baroMeter.setPointerColor(Color.RED); + else + baroMeter.setPointerColor(Color.WHITE); + + timeElapsed = ((System.currentTimeMillis() - startTime) / updatePeriod); + if (timeElapsed != previousTimeElapsed) { + previousTimeElapsed = timeElapsed; + Entry entry = new Entry((float) timeElapsed, baroValue); + Long currentTime = System.currentTimeMillis(); + writeLogToFile(currentTime, baroValue); + entries.add(entry); + + count++; + sum += entry.getY(); + statMean.setText(String.format(Locale.getDefault(), PSLabSensor.BAROMETER_DATA_FORMAT, (sum / count))); + + LineDataSet dataSet = new LineDataSet(entries, getString(R.string.baro_unit)); + dataSet.setDrawCircles(false); + dataSet.setDrawValues(false); + dataSet.setLineWidth(2); + LineData data = new LineData(dataSet); + + mChart.setData(data); + mChart.notifyDataSetChanged(); + mChart.setVisibleXRangeMaximum(80); + mChart.moveViewToX(data.getEntryCount()); + mChart.invalidate(); + } + } + } + + private SensorEventListener baroSensorEventListener = new SensorEventListener() { + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) {/**/} + + @Override + public void onSensorChanged(SensorEvent event) { + if (event.sensor.getType() == Sensor.TYPE_PRESSURE) { + baroValue = Float.valueOf(String.format(Locale.getDefault(), PSLabSensor.BAROMETER_DATA_FORMAT, event.values[0] / 1000)); + } + } + }; + + private void resetInstrumentData() { + baroValue = 0; + count = 0; + currentMin = 2; + currentMax = 0.5f; + sum = 0; + sensor = null; + if (sensorManager != null) { + sensorManager.unregisterListener(baroSensorEventListener); + } + startTime = System.currentTimeMillis(); + statMax.setText(getResources().getString(R.string.value_null)); + statMin.setText(getResources().getString(R.string.value_null)); + statMean.setText(getResources().getString(R.string.value_null)); + baroMeter.setSpeedAt(0); + baroMeter.setWithTremble(false); + entries.clear(); + } + + private void initiateBaroSensor(int type) { + BaroMeterDataFragment.BARO_SENSOR s = BaroMeterDataFragment.BARO_SENSOR.values()[type]; + resetInstrumentData(); + ScienceLab scienceLab; + switch (s) { + case INBUILT_SENSOR: + sensorLabel.setText(getResources().getStringArray(R.array.baro_sensors)[0]); + sensorManager = (SensorManager) getContext().getSystemService(SENSOR_SERVICE); + sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE); + if (sensor == null) { + Toast.makeText(getContext(), getResources().getString(R.string.no_baro_sensor), Toast.LENGTH_LONG).show(); + } else { + float max = sensor.getMaximumRange() / 1000; + PreferenceManager.getDefaultSharedPreferences(getActivity()).edit().putFloat(baroSensor.BAROMETER_LIMIT, max).apply(); + baroMeter.setMaxSpeed(max); + sensorManager.registerListener(baroSensorEventListener, + sensor, SensorManager.SENSOR_DELAY_FASTEST); + } + break; + case BMP180_SENSOR: + sensorLabel.setText(getResources().getStringArray(R.array.baro_sensors)[1]); + scienceLab = ScienceLabCommon.scienceLab; + if (scienceLab.isConnected()) { + ArrayList data; + try { + I2C i2c = scienceLab.i2c; + data = i2c.scan(null); + if (data.contains(0x23)) { + BMP180 sensorBMP180 = new BMP180(i2c, scienceLab); + sensorBMP180.setOversampling(10); + sensorType = 0; + } else { + Toast.makeText(getContext(), getResources().getText(R.string.sensor_not_connected_tls), Toast.LENGTH_SHORT).show(); + sensorType = 0; + } + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + } else { + Toast.makeText(getContext(), getResources().getText(R.string.device_not_found), Toast.LENGTH_SHORT).show(); + sensorType = 0; + } + break; + default: + break; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/pslab/fragment/BaroMeterSettingsFragment.java b/app/src/main/java/io/pslab/fragment/BaroMeterSettingsFragment.java new file mode 100644 index 000000000..7ab3a45d1 --- /dev/null +++ b/app/src/main/java/io/pslab/fragment/BaroMeterSettingsFragment.java @@ -0,0 +1,117 @@ +package io.pslab.fragment; + +import android.annotation.SuppressLint; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.v7.preference.CheckBoxPreference; +import android.support.v7.preference.EditTextPreference; +import android.support.v7.preference.ListPreference; +import android.support.v7.preference.PreferenceFragmentCompat; +import android.support.v7.preference.PreferenceManager; + +import io.pslab.R; +import io.pslab.others.PSLabPermission; + +/** + * Created by Padmal on 12/13/18. + */ + +public class BaroMeterSettingsFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener { + + public static final String KEY_INCLUDE_LOCATION = "include_location_sensor_data"; + public static final String KEY_UPDATE_PERIOD = "setting_baro_update_period"; + public static final String KEY_HIGH_LIMIT = "setting_baro_high_limit"; + public static final String KEY_BARO_SENSOR_TYPE = "setting_baro_sensor_type"; + + private PSLabPermission psLabPermission; + + private EditTextPreference updatePeriodPref; + private EditTextPreference highLimitPref; + private CheckBoxPreference locationPreference; + private ListPreference sensorTypePreference; + private SharedPreferences sharedPref; + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + setPreferencesFromResource(R.xml.baro_meter_settings, rootKey); + updatePeriodPref = (EditTextPreference) getPreferenceScreen().findPreference(KEY_UPDATE_PERIOD); + highLimitPref = (EditTextPreference) getPreferenceScreen().findPreference(KEY_HIGH_LIMIT); + locationPreference = (CheckBoxPreference) getPreferenceScreen().findPreference(KEY_INCLUDE_LOCATION); + sensorTypePreference = (ListPreference) getPreferenceScreen().findPreference(KEY_BARO_SENSOR_TYPE); + sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity()); + + psLabPermission = PSLabPermission.getInstance(); + if (!psLabPermission.checkPermissions(getActivity(), PSLabPermission.MAP_PERMISSION)) { + SharedPreferences.Editor editor = sharedPref.edit(); + editor.putBoolean(BaroMeterSettingsFragment.KEY_INCLUDE_LOCATION, true); + editor.apply(); + } + } + + @Override + public void onResume() { + super.onResume(); + locationPreference.setChecked(sharedPref.getBoolean(KEY_INCLUDE_LOCATION, true)); + updatePeriodPref.setSummary(updatePeriodPref.getText() + " ms"); + highLimitPref.setSummary(highLimitPref.getText() + " atm"); + sensorTypePreference.setSummary(sensorTypePreference.getEntry()); + getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onPause() { + super.onPause(); + getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); + } + + @SuppressLint("ApplySharedPref") + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { + switch (s) { + case KEY_INCLUDE_LOCATION: + if (locationPreference.isChecked()) { + psLabPermission.checkPermissions( + getActivity(), PSLabPermission.MAP_PERMISSION); + } + break; + case KEY_UPDATE_PERIOD: + try { + Integer updatePeriod = Integer.valueOf(updatePeriodPref.getText()); + if (updatePeriod > 2000 || updatePeriod < 100) { + throw new NumberFormatException(); + } else { + updatePeriodPref.setSummary(String.valueOf(updatePeriod)); + } + updatePeriodPref.setSummary(updatePeriod + " ms"); + } catch (NumberFormatException e) { + updatePeriodPref.setSummary("1000 ms"); + updatePeriodPref.setText("1000"); + SharedPreferences.Editor editor = sharedPref.edit(); + editor.putString(s, "1000"); + editor.commit(); + } + break; + case KEY_HIGH_LIMIT: + try { + Float highLimit = Float.valueOf(highLimitPref.getText()); + if (highLimit > 1.1 || highLimit < 0.0) { + throw new NumberFormatException(); + } else { + highLimitPref.setSummary(String.valueOf(highLimit)); + } + } catch (NumberFormatException e) { + highLimitPref.setSummary("1.1 atm"); + highLimitPref.setText("1.1"); + SharedPreferences.Editor editor = sharedPref.edit(); + editor.putString(KEY_HIGH_LIMIT, "1.1"); + editor.commit(); + } + break; + case KEY_BARO_SENSOR_TYPE: + sensorTypePreference.setSummary(sensorTypePreference.getEntry()); + break; + default: + break; + } + } +} diff --git a/app/src/main/java/io/pslab/fragment/InstrumentsFragment.java b/app/src/main/java/io/pslab/fragment/InstrumentsFragment.java index 6e0b5e6b0..24afd7adf 100644 --- a/app/src/main/java/io/pslab/fragment/InstrumentsFragment.java +++ b/app/src/main/java/io/pslab/fragment/InstrumentsFragment.java @@ -16,6 +16,7 @@ import io.pslab.R; import io.pslab.activity.AccelerometerActivity; +import io.pslab.activity.BarometerActivity; import io.pslab.activity.CompassActivity; import io.pslab.activity.LogicalAnalyzerActivity; import io.pslab.activity.LuxMeterActivity; @@ -26,7 +27,7 @@ import io.pslab.activity.WaveGeneratorActivity; import io.pslab.adapters.ApplicationAdapter; import io.pslab.items.ApplicationItem; -import io.pslab.activity.BarometerActivity; +import io.pslab.models.PSLabSensor; import java.util.ArrayList; import java.util.List; @@ -84,7 +85,7 @@ public void onItemClick(ApplicationItem item) { intent = new Intent(context, PowerSourceActivity.class); startActivity(intent); break; - case "Lux Meter": + case PSLabSensor.LUXMETER: intent = new Intent(context, LuxMeterActivity.class); startActivity(intent); break; @@ -92,7 +93,7 @@ public void onItemClick(ApplicationItem item) { intent = new Intent(context, AccelerometerActivity.class); startActivity(intent); break; - case "Barometer": + case PSLabSensor.BAROMETER: intent = new Intent(context, BarometerActivity.class); startActivity(intent); break; @@ -141,7 +142,7 @@ protected Void doInBackground(Void... params) { R.string.power_source_description, R.string.lux_meter_description, R.string.accelerometer_description, - R.string.barometer_description, + R.string.baro_meter_description, R.string.compass_description }; @@ -170,7 +171,7 @@ protected Void doInBackground(Void... params) { getResources().getString(R.string.accelerometer), R.drawable.tile_icon_accelerometer, getResources().getString(descriptions[7])) ); applicationItemList.add(new ApplicationItem( - getResources().getString(R.string.barometer), R.drawable.tile_icon_barometer, getResources().getString(descriptions[8]) + getResources().getString(R.string.baro_meter), R.drawable.tile_icon_barometer, getResources().getString(descriptions[8]) )); applicationItemList.add(new ApplicationItem( getResources().getString(R.string.compass), R.drawable.tile_icon_compass, getResources().getString(descriptions[9]) diff --git a/app/src/main/java/io/pslab/fragment/LuxMeterDataFragment.java b/app/src/main/java/io/pslab/fragment/LuxMeterDataFragment.java index 10e03e20d..b564ace26 100644 --- a/app/src/main/java/io/pslab/fragment/LuxMeterDataFragment.java +++ b/app/src/main/java/io/pslab/fragment/LuxMeterDataFragment.java @@ -10,6 +10,7 @@ import android.os.Handler; import android.support.annotation.NonNull; import android.support.v4.app.Fragment; +import android.support.v7.preference.PreferenceManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -42,7 +43,9 @@ import io.pslab.communication.sensors.BH1750; import io.pslab.communication.sensors.TSL2561; import io.pslab.models.LuxData; +import io.pslab.models.PSLabSensor; import io.pslab.models.SensorDataBlock; +import io.pslab.others.CSVLogger; import io.pslab.others.ScienceLabCommon; import static android.content.Context.SENSOR_SERVICE; @@ -88,7 +91,6 @@ private enum LUX_SENSOR {INBUILT_SENSOR, BH1750_SENSOR, TSL2561_SENSOR} private LuxData sensorData; private float currentMin = 10000; private float currentMax = 0; - private boolean playComplete = false; private YAxis y; private Unbinder unbinder; private long previousTimeElapsed = (System.currentTimeMillis() - startTime) / updatePeriod; @@ -126,11 +128,15 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public void onResume() { super.onResume(); if (luxSensor.playingData) { - sensorLabel.setText(getResources().getString(R.string.recorder)); + sensorLabel.setText(getResources().getString(R.string.lux_meter)); recordedLuxArray = new ArrayList<>(); resetInstrumentData(); playRecordedData(); - + } else if (luxSensor.viewingData) { + sensorLabel.setText(getResources().getString(R.string.lux_meter)); + recordedLuxArray = new ArrayList<>(); + resetInstrumentData(); + plotAllRecordedData(); } else if (!luxSensor.isRecording) { updateGraphs(); sum = 0; @@ -158,14 +164,56 @@ public void onDestroyView() { unbinder.unbind(); } + private void plotAllRecordedData() { + recordedLuxArray.addAll(luxSensor.recordedLuxData); + if (recordedLuxArray.size() != 0) { + for (LuxData d: recordedLuxArray) { + if (currentMax < d.getLux()) { + currentMax = d.getLux(); + } + if (currentMin > d.getLux()) { + currentMin = d.getLux(); + } + Entry entry = new Entry((float) (d.getTime() - d.getBlock()) / 1000, d.getLux()); + entries.add(entry); + lightMeter.setWithTremble(false); + lightMeter.setSpeedAt(d.getLux()); + sum += entry.getY(); + } + y.setAxisMaximum(currentMax); + y.setAxisMinimum(currentMin); + y.setLabelCount(10); + statMax.setText(String.valueOf(currentMax)); + statMin.setText(String.valueOf(currentMin)); + statMean.setText(String.format(Locale.getDefault(), PSLabSensor.LUXMETER_DATA_FORMAT, (sum / recordedLuxArray.size()))); + + LineDataSet dataSet = new LineDataSet(entries, getString(R.string.lux)); + dataSet.setDrawCircles(false); + dataSet.setDrawValues(false); + dataSet.setLineWidth(2); + LineData data = new LineData(dataSet); + + mChart.setData(data); + mChart.notifyDataSetChanged(); + mChart.setVisibleXRangeMaximum(80); + mChart.moveViewToX(data.getEntryCount()); + mChart.invalidate(); + } + } + private void playRecordedData() { recordedLuxArray.addAll(luxSensor.recordedLuxData); - if (recordedLuxArray.size() > 1) { - LuxData i = recordedLuxArray.get(1); - long timeGap = i.getTime() - i.getBlock(); - processRecordedData(timeGap); - } else { - processRecordedData(0); + try { + if (recordedLuxArray.size() > 1) { + LuxData i = recordedLuxArray.get(1); + long timeGap = i.getTime() - i.getBlock(); + processRecordedData(timeGap); + } else { + processRecordedData(0); + } + } catch (IllegalArgumentException e) { + Toast.makeText(getActivity(), + getActivity().getResources().getString(R.string.no_data_fetched), Toast.LENGTH_SHORT).show(); } } @@ -182,44 +230,49 @@ public void run() { handler.post(new Runnable() { @Override public void run() { - try { - playComplete = false; - LuxData d = recordedLuxArray.get(turns); - turns++; - if (currentMax < d.getLux()) { - currentMax = d.getLux(); - statMax.setText(String.valueOf(d.getLux())); + if (luxSensor.playingData) { + try { + LuxData d = recordedLuxArray.get(turns); + turns++; + if (currentMax < d.getLux()) { + currentMax = d.getLux(); + statMax.setText(String.valueOf(d.getLux())); + } + if (currentMin > d.getLux()) { + currentMin = d.getLux(); + statMin.setText(String.valueOf(d.getLux())); + } + y.setAxisMaximum(currentMax); + y.setAxisMinimum(currentMin); + y.setLabelCount(10); + lightMeter.setWithTremble(false); + lightMeter.setSpeedAt(d.getLux()); + + Entry entry = new Entry((float) (d.getTime() - d.getBlock()) / 1000, d.getLux()); + entries.add(entry); + count++; + sum += entry.getY(); + statMean.setText(String.format(Locale.getDefault(), PSLabSensor.LUXMETER_DATA_FORMAT, (sum / count))); + + LineDataSet dataSet = new LineDataSet(entries, getString(R.string.lux)); + dataSet.setDrawCircles(false); + dataSet.setDrawValues(false); + dataSet.setLineWidth(2); + LineData data = new LineData(dataSet); + + mChart.setData(data); + mChart.notifyDataSetChanged(); + mChart.setVisibleXRangeMaximum(80); + mChart.moveViewToX(data.getEntryCount()); + mChart.invalidate(); + } catch (IndexOutOfBoundsException e) { + graphTimer.cancel(); + graphTimer = null; + turns = 0; + luxSensor.playingData = false; + luxSensor.startedPlay = false; + luxSensor.invalidateOptionsMenu(); } - if (currentMin > d.getLux()) { - currentMin = d.getLux(); - statMin.setText(String.valueOf(d.getLux())); - } - y.setAxisMaximum(currentMax); - y.setAxisMinimum(currentMin); - y.setLabelCount(10); - lightMeter.setWithTremble(false); - lightMeter.setSpeedAt(d.getLux()); - - Entry entry = new Entry((float) (d.getTime() - d.getBlock()) / 1000, d.getLux()); - entries.add(entry); - count++; - sum += entry.getY(); - statMean.setText(String.format(Locale.getDefault(), "%.2f", (sum / count))); - - LineDataSet dataSet = new LineDataSet(entries, getString(R.string.lux)); - dataSet.setDrawCircles(false); - dataSet.setDrawValues(false); - dataSet.setLineWidth(2); - LineData data = new LineData(dataSet); - - mChart.setData(data); - mChart.notifyDataSetChanged(); - mChart.setVisibleXRangeMaximum(80); - mChart.moveViewToX(data.getEntryCount()); - mChart.invalidate(); - } catch (IndexOutOfBoundsException e) { - graphTimer.cancel(); - playComplete = true; } } }); @@ -227,17 +280,43 @@ public void run() { }, 0, timeGap); } - public void saveGraph() { - if (playComplete) { - mChart.saveToGallery(luxSensor.dateFormat.format(recordedLuxArray.get(0).getTime()), 100); - Toast.makeText(getActivity(), "Graph saved to gallery", Toast.LENGTH_LONG).show(); - } else { - Toast.makeText(getActivity(), "Wait until the play is complete", Toast.LENGTH_LONG).show(); + public void stopData() { + if (graphTimer != null) { + graphTimer.cancel(); + graphTimer = null; + } + recordedLuxArray.clear(); + entries.clear(); + plotAllRecordedData(); + luxSensor.startedPlay = false; + luxSensor.playingData = false; + turns = 0; + luxSensor.invalidateOptionsMenu(); + } + + public void playData() { + resetInstrumentData(); + luxSensor.startedPlay = true; + try { + if (recordedLuxArray.size() > 1) { + LuxData i = recordedLuxArray.get(1); + long timeGap = i.getTime() - i.getBlock(); + processRecordedData(timeGap); + } else { + processRecordedData(0); + } + } catch (IllegalArgumentException e) { + Toast.makeText(getActivity(), + getActivity().getResources().getString(R.string.no_data_fetched), Toast.LENGTH_SHORT).show(); } } + public void saveGraph() { + // Todo: Save graph view to gallery + } + private void setupInstruments() { - lightMeter.setMaxSpeed(10000); + lightMeter.setMaxSpeed(PreferenceManager.getDefaultSharedPreferences(getActivity()).getFloat(luxSensor.LUXMETER_LIMIT, 10000)); XAxis x = mChart.getXAxis(); this.y = mChart.getAxisLeft(); @@ -319,13 +398,13 @@ private void writeLogToFile(long timestamp, float sensorReading) { luxSensor.writeHeaderToFile = !luxSensor.writeHeaderToFile; } if (luxSensor.addLocation && luxSensor.gpsLogger.isGPSEnabled()) { - String dateTime = luxSensor.dateFormat.format(new Date(timestamp)); + String dateTime = CSVLogger.FILE_NAME_FORMAT.format(new Date(timestamp)); Location location = luxSensor.gpsLogger.getDeviceLocation(); luxSensor.csvLogger.writeCSVFile(timestamp + "," + dateTime + "," + sensorReading + "," + location.getLatitude() + "," + location.getLongitude()); sensorData = new LuxData(timestamp, block, luxValue, location.getLatitude(), location.getLongitude()); } else { - String dateTime = luxSensor.dateFormat.format(new Date(timestamp)); + String dateTime = CSVLogger.FILE_NAME_FORMAT.format(new Date(timestamp)); luxSensor.csvLogger.writeCSVFile(timestamp + "," + dateTime + "," + sensorReading + ",0.0,0.0"); sensorData = new LuxData(timestamp, block, luxValue, 0.0, 0.0); @@ -366,7 +445,7 @@ private void visualizeData() { count++; sum += entry.getY(); - statMean.setText(String.format(Locale.getDefault(), "%.2f", (sum / count))); + statMean.setText(String.format(Locale.getDefault(), PSLabSensor.LUXMETER_DATA_FORMAT, (sum / count))); LineDataSet dataSet = new LineDataSet(entries, getString(R.string.lux)); dataSet.setDrawCircles(false); @@ -428,6 +507,7 @@ private void initiateLuxSensor(int type) { Toast.makeText(getContext(), getResources().getString(R.string.no_lux_sensor), Toast.LENGTH_LONG).show(); } else { float max = sensor.getMaximumRange(); + PreferenceManager.getDefaultSharedPreferences(getActivity()).edit().putFloat(luxSensor.LUXMETER_LIMIT, max).apply(); lightMeter.setMaxSpeed(max); sensorManager.registerListener(lightSensorEventListener, sensor, SensorManager.SENSOR_DELAY_FASTEST); diff --git a/app/src/main/java/io/pslab/interfaces/sensorloggers/BaroMeterRecordables.java b/app/src/main/java/io/pslab/interfaces/sensorloggers/BaroMeterRecordables.java new file mode 100644 index 000000000..d8ced963c --- /dev/null +++ b/app/src/main/java/io/pslab/interfaces/sensorloggers/BaroMeterRecordables.java @@ -0,0 +1,21 @@ +package io.pslab.interfaces.sensorloggers; + +import io.pslab.models.BaroData; +import io.realm.RealmResults; + +/** + * Created by Padmal on 12/13/18. + */ + +public interface BaroMeterRecordables { + + BaroData getBaroData(long timeStamp); + + void clearAllBaroRecords(); + + void clearBlockOfBaroRecords(long block); + + RealmResults getAllBaroRecords(); + + RealmResults getBlockOfBaroRecords(long block); +} diff --git a/app/src/main/java/io/pslab/models/BaroData.java b/app/src/main/java/io/pslab/models/BaroData.java new file mode 100644 index 000000000..2d2c3d745 --- /dev/null +++ b/app/src/main/java/io/pslab/models/BaroData.java @@ -0,0 +1,72 @@ +package io.pslab.models; + +import io.realm.RealmObject; +import io.realm.annotations.PrimaryKey; + +/** + * Created by Padmal on 12/13/18. + */ + +public class BaroData extends RealmObject { + + @PrimaryKey + private long time; + private long block; + private float baro; + private double lat, lon; + + public BaroData() {/**/} + + public BaroData(long time, long block, float baro, double lat, double lon) { + this.time = time; + this.block = block; + this.baro = baro; + this.lat = lat; + this.lon = lon; + } + + public long getTime() { + return time; + } + + public void setTime(long time) { + this.time = time; + } + + public long getBlock() { + return block; + } + + public void setBlock(long block) { + this.block = block; + } + + public float getBaro() { + return baro; + } + + public void setBaro(float baro) { + this.baro = baro; + } + + public double getLat() { + return lat; + } + + public void setLat(double lat) { + this.lat = lat; + } + + public double getLon() { + return lon; + } + + public void setLon(double lon) { + this.lon = lon; + } + + @Override + public String toString() { + return "Block - " + block + ", Time - " + time + ", Baro - " + baro + ", Lat - " + lat + ", Lon - " + lon; + } +} \ No newline at end of file diff --git a/app/src/main/java/io/pslab/models/PSLabSensor.java b/app/src/main/java/io/pslab/models/PSLabSensor.java index 6703931e2..9bc07a974 100644 --- a/app/src/main/java/io/pslab/models/PSLabSensor.java +++ b/app/src/main/java/io/pslab/models/PSLabSensor.java @@ -5,12 +5,15 @@ import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.location.LocationManager; +import android.net.Uri; import android.os.Bundle; +import android.os.Environment; import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.design.widget.BottomSheetBehavior; import android.support.design.widget.CoordinatorLayout; +import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; @@ -29,6 +32,8 @@ import org.json.JSONArray; +import java.io.File; +import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Locale; @@ -38,6 +43,7 @@ import io.pslab.activity.DataLoggerActivity; import io.pslab.activity.MapsActivity; import io.pslab.activity.SettingsActivity; +import io.pslab.fragment.BaroMeterDataFragment; import io.pslab.fragment.LuxMeterDataFragment; import io.pslab.others.CSVLogger; import io.pslab.others.CustomSnackBar; @@ -61,6 +67,8 @@ public abstract class PSLabSensor extends AppCompatActivity { public boolean checkGPSOnResume = false; public boolean writeHeaderToFile = true; public boolean playingData = false; + public boolean viewingData = false; + public boolean startedPlay = false; public CoordinatorLayout sensorParentView; public BottomSheetBehavior bottomSheetBehavior; @@ -75,11 +83,15 @@ public abstract class PSLabSensor extends AppCompatActivity { public Realm realm; private Intent map; - public SimpleDateFormat dateFormat; public SimpleDateFormat titleFormat; public final String KEY_LOG = "has_log"; public final String DATA_BLOCK = "data_block"; + public static final String LUXMETER = "Lux Meter"; + public static final String LUXMETER_DATA_FORMAT = "%.2f"; + public static final String BAROMETER = "Barometer"; + public static final String BAROMETER_DATA_FORMAT = "%.5f"; + @BindView(R.id.sensor_toolbar) Toolbar sensorToolBar; @BindView(R.id.sensor_cl) @@ -104,13 +116,6 @@ public abstract class PSLabSensor extends AppCompatActivity { @BindView(R.id.custom_dialog_additional_content) LinearLayout bottomSheetAdditionalContent; - /** - * Getting layout file distinct to each sensor - * - * @return Layout resource file in 'R.layout.id' format - */ - public abstract int getLayout(); - /** * Getting menu layout distinct to each sensor * @@ -206,7 +211,7 @@ public abstract class PSLabSensor extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(getLayout()); + setContentView(R.layout.activity_generic_sensor); ButterKnife.bind(this); setSupportActionBar(sensorToolBar); getSupportActionBar().setTitle(getSensorName()); @@ -217,7 +222,6 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { map = new Intent(this, MapsActivity.class); csvLogger = new CSVLogger(getSensorName()); realm = LocalDataLog.with().getRealm(); - dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ", Locale.getDefault()); titleFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); sensorParentView = coordinatorLayout; setUpBottomSheet(); @@ -240,12 +244,15 @@ private void fillUpFragment() { } private void setUpMenu(Menu menu) { - if (playingData) { + if (playingData || viewingData) { for (int i = 0; i < menu.size(); i++) { menu.getItem(i).setVisible(false); } } - menu.findItem(R.id.save_graph).setVisible(playingData); + menu.findItem(R.id.save_graph).setVisible(viewingData || playingData); + menu.findItem(R.id.play_data).setVisible(viewingData || playingData); + menu.findItem(R.id.settings).setTitle(getSensorName() + " Configurations"); + menu.findItem(R.id.stop_data).setVisible(viewingData).setEnabled(startedPlay); } @Override @@ -260,6 +267,10 @@ public boolean onCreateOptionsMenu(Menu menu) { public boolean onPrepareOptionsMenu(Menu menu) { MenuItem record = menu.findItem(R.id.record_data); record.setIcon(isRecording ? R.drawable.ic_record_stop_white : R.drawable.ic_record_white); + MenuItem play = menu.findItem(R.id.play_data); + play.setIcon(playingData ? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_24dp); + MenuItem stop = menu.findItem(R.id.stop_data); + stop.setVisible(startedPlay); return super.onPrepareOptionsMenu(menu); } @@ -286,13 +297,34 @@ public boolean onOptionsItemSelected(MenuItem item) { dataRecordingCycle(); } else { stopRecordSensorData(); - CustomSnackBar.showSnackBar(sensorParentView, - getString(R.string.data_recording_stopped), null, null); + displayLogLocationOnSnackBar(); isRecording = false; prepareMarkers(); } invalidateOptionsMenu(); break; + case R.id.play_data: + playingData = !playingData; + if (!startedPlay) { + if (getSensorFragment() instanceof LuxMeterDataFragment) { + ((LuxMeterDataFragment) getSupportFragmentManager() + .findFragmentByTag(getSensorName())).playData(); + } else if (getSensorFragment() instanceof BaroMeterDataFragment) { + ((BaroMeterDataFragment) getSupportFragmentManager() + .findFragmentByTag(getSensorName())).playData(); + } + } + invalidateOptionsMenu(); + break; + case R.id.stop_data: + if (getSensorFragment() instanceof LuxMeterDataFragment) { + ((LuxMeterDataFragment) getSupportFragmentManager() + .findFragmentByTag(getSensorName())).stopData(); + } else if (getSensorFragment() instanceof BaroMeterDataFragment) { + ((BaroMeterDataFragment) getSupportFragmentManager() + .findFragmentByTag(getSensorName())).stopData(); + } + break; case R.id.show_map: if (psLabPermission.checkPermissions(PSLabSensor.this, PSLabPermission.MAP_PERMISSION)) { @@ -316,9 +348,13 @@ public boolean onOptionsItemSelected(MenuItem item) { bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); break; case R.id.save_graph: + displayLogLocationOnSnackBar(); if (getSensorFragment() instanceof LuxMeterDataFragment) { ((LuxMeterDataFragment) getSupportFragmentManager() .findFragmentByTag(getSensorName())).saveGraph(); + } else if (getSensorFragment() instanceof BaroMeterDataFragment) { + ((BaroMeterDataFragment) getSupportFragmentManager() + .findFragmentByTag(getSensorName())).saveGraph(); } break; default: @@ -335,7 +371,7 @@ private void dataRecordingCycle() { } } else { CustomSnackBar.showSnackBar(sensorParentView, - getString(R.string.data_recording_without_location), null, null); + getString(R.string.data_recording_without_location), null, null, Snackbar.LENGTH_LONG); isRecording = true; } } @@ -346,16 +382,41 @@ private void gpsRecordingCycle() { gpsLogger.startCaptureLocation(); if (gpsLogger.isGPSEnabled()) { CustomSnackBar.showSnackBar(sensorParentView, - getString(R.string.data_recording_with_location), null, null); + getString(R.string.data_recording_with_location), null, null, Snackbar.LENGTH_LONG); isRecording = true; } else { gpsLogger.gpsAlert.show(); } } + public void displayLogLocationOnSnackBar() { + final File logDirectory = new File( + Environment.getExternalStorageDirectory().getAbsolutePath() + + File.separator + CSVLogger.CSV_DIRECTORY + File.separator + getSensorName()); + String logLocation; + try { + logLocation = getString(R.string.log_saved_directory) + logDirectory.getCanonicalPath(); + } catch (IOException e) { + // This message wouldn't appear in usual cases. Added in order to handle ex: + logLocation = getString(R.string.log_saved_failed); + } + CustomSnackBar.showSnackBar(sensorParentView, logLocation, getString(R.string.open), + new View.OnClickListener() { + @Override + public void onClick(View view) { + Uri selectedUri = Uri.parse(logDirectory.getAbsolutePath()); + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(selectedUri, "resource/folder"); + if (intent.resolveActivityInfo(getPackageManager(), 0) != null) { + startActivity(intent); + } + } + }, Snackbar.LENGTH_INDEFINITE); + } + private void nogpsRecordingCycle() { CustomSnackBar.showSnackBar(sensorParentView, - getString(R.string.data_recording_without_location), null, null); + getString(R.string.data_recording_without_location), null, null, Snackbar.LENGTH_LONG); addLocation = false; isRecording = true; } @@ -520,7 +581,11 @@ private void handleFirstTimeUsage() { @Override protected void onResume() { super.onResume(); - getDataFromDataLogger(); + try { + getDataFromDataLogger(); + } catch (ArrayIndexOutOfBoundsException e) { + Toast.makeText(getApplicationContext(), getString(R.string.no_data_fetched), Toast.LENGTH_LONG).show(); + } if (checkGPSOnResume) { isRecording = true; checkGPSOnResume = false; diff --git a/app/src/main/java/io/pslab/others/CSVLogger.java b/app/src/main/java/io/pslab/others/CSVLogger.java index f723d8bdd..dde35c8f7 100644 --- a/app/src/main/java/io/pslab/others/CSVLogger.java +++ b/app/src/main/java/io/pslab/others/CSVLogger.java @@ -19,9 +19,10 @@ public class CSVLogger { private File csvFile; private String category; - SimpleDateFormat TIME; - private static final String CSV_DIRECTORY = "PSLab"; + public static final String CSV_DIRECTORY = "PSLab"; + public static final SimpleDateFormat FILE_NAME_FORMAT = new SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault()); /** * Constructor initiate logger with a category folder @@ -60,8 +61,7 @@ private void setupPath() { } public void prepareLogFile() { - TIME = new SimpleDateFormat("yyyyMMdd-hh:mm:ss:SSS", Locale.getDefault()); - String uniqueFileName = TIME.format(new Date()); + String uniqueFileName = FILE_NAME_FORMAT.format(new Date()); csvFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + CSV_DIRECTORY + File.separator + category + File.separator + uniqueFileName + ".csv"); diff --git a/app/src/main/java/io/pslab/others/CustomSnackBar.java b/app/src/main/java/io/pslab/others/CustomSnackBar.java index cd3372e56..4990c1aa0 100644 --- a/app/src/main/java/io/pslab/others/CustomSnackBar.java +++ b/app/src/main/java/io/pslab/others/CustomSnackBar.java @@ -15,14 +15,15 @@ */ public class CustomSnackBar { + public static Snackbar snackbar; + public static void showSnackBar(@NonNull CoordinatorLayout holderLayout, @NonNull String displayText, - String actionText, View.OnClickListener clickListener){ - Snackbar snackbar = Snackbar.make(holderLayout,displayText,Snackbar.LENGTH_LONG) + String actionText, View.OnClickListener clickListener, int duration) { + snackbar = Snackbar.make(holderLayout, displayText, duration) .setAction(actionText, clickListener); - snackbar.setActionTextColor(ContextCompat.getColor(holderLayout.getContext(), R.color.colorPrimary)); View sbView = snackbar.getView(); - TextView textView = sbView.findViewById(android.support.design.R.id.snackbar_text); + TextView textView = sbView.findViewById(android.support.design.R.id.snackbar_text); textView.setTextColor(Color.WHITE); snackbar.show(); } diff --git a/app/src/main/java/io/pslab/others/GPSLogger.java b/app/src/main/java/io/pslab/others/GPSLogger.java index 2f9495596..30be9bf72 100644 --- a/app/src/main/java/io/pslab/others/GPSLogger.java +++ b/app/src/main/java/io/pslab/others/GPSLogger.java @@ -11,6 +11,7 @@ import android.location.LocationManager; import android.os.Bundle; import android.provider.Settings; +import android.support.design.widget.Snackbar; import android.widget.Toast; import io.pslab.R; @@ -63,13 +64,13 @@ public void onClick(DialogInterface dialogInterface, int i) { if (sensorActivity.isRecording) { CustomSnackBar.showSnackBar(sensorActivity.sensorParentView, context.getResources().getString(R.string.data_recording_with_gps_off), - null, null); + null, null, Snackbar.LENGTH_LONG); } else { sensorActivity.isRecording = true; sensorActivity.invalidateOptionsMenu(); CustomSnackBar.showSnackBar(sensorActivity.sensorParentView, context.getResources().getString(R.string.data_recording_with_nogps), - null, null); + null, null, Snackbar.LENGTH_LONG); } } }) diff --git a/app/src/main/java/io/pslab/others/LocalDataLog.java b/app/src/main/java/io/pslab/others/LocalDataLog.java index d8cd49aa8..b43985d9c 100644 --- a/app/src/main/java/io/pslab/others/LocalDataLog.java +++ b/app/src/main/java/io/pslab/others/LocalDataLog.java @@ -1,7 +1,9 @@ package io.pslab.others; +import io.pslab.interfaces.sensorloggers.BaroMeterRecordables; import io.pslab.interfaces.sensorloggers.LuxMeterRecordables; import io.pslab.interfaces.sensorloggers.SensorRecordables; +import io.pslab.models.BaroData; import io.pslab.models.LuxData; import io.pslab.models.SensorDataBlock; import io.realm.Realm; @@ -12,7 +14,7 @@ * Created by Padmal on 11/5/18. */ -public class LocalDataLog implements LuxMeterRecordables, SensorRecordables { +public class LocalDataLog implements LuxMeterRecordables, BaroMeterRecordables, SensorRecordables { private static LocalDataLog instance; private final Realm realm; @@ -118,4 +120,39 @@ public RealmResults getBlockOfLuxRecords(long block) { .equalTo("block", block) .findAll(); } + + /*********************************************************************************************** + * Baro Sensor Section + ***********************************************************************************************/ + @Override + public BaroData getBaroData(long timestamp) { + return realm.where(BaroData.class).equalTo("time", timestamp).findFirst(); + } + + @Override + public void clearAllBaroRecords() { + realm.beginTransaction(); + realm.delete(BaroData.class); + realm.commitTransaction(); + } + + @Override + public void clearBlockOfBaroRecords(long block) { + realm.beginTransaction(); + RealmResults data = getBlockOfBaroRecords(block); + data.deleteAllFromRealm(); + realm.commitTransaction(); + } + + @Override + public RealmResults getAllBaroRecords() { + return realm.where(BaroData.class).findAll(); + } + + @Override + public RealmResults getBlockOfBaroRecords(long block) { + return realm.where(BaroData.class) + .equalTo("block", block) + .findAll(); + } } diff --git a/app/src/main/res/drawable/ic_pause_white_24dp.xml b/app/src/main/res/drawable/ic_pause_white_24dp.xml new file mode 100644 index 000000000..baf8f08b3 --- /dev/null +++ b/app/src/main/res/drawable/ic_pause_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_play_arrow_white_24dp.xml b/app/src/main/res/drawable/ic_play_arrow_white_24dp.xml new file mode 100644 index 000000000..7e05ffccf --- /dev/null +++ b/app/src/main/res/drawable/ic_play_arrow_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_stop_white_24dp.xml b/app/src/main/res/drawable/ic_stop_white_24dp.xml new file mode 100644 index 000000000..86b8cd2de --- /dev/null +++ b/app/src/main/res/drawable/ic_stop_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/tile_icon_barometer_log.xml b/app/src/main/res/drawable/tile_icon_barometer_log.xml new file mode 100644 index 000000000..18314c11c --- /dev/null +++ b/app/src/main/res/drawable/tile_icon_barometer_log.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/tile_icon_lux_meter_log.xml b/app/src/main/res/drawable/tile_icon_lux_meter_log.xml new file mode 100644 index 000000000..f67692589 --- /dev/null +++ b/app/src/main/res/drawable/tile_icon_lux_meter_log.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout-land/splash_screen.xml b/app/src/main/res/layout-land/splash_screen.xml index f36026103..48b17cb70 100644 --- a/app/src/main/res/layout-land/splash_screen.xml +++ b/app/src/main/res/layout-land/splash_screen.xml @@ -11,12 +11,14 @@ android:layout_width="match_parent" android:layout_height="200dp" android:contentDescription="@string/pocket_science_logo" - android:src="@drawable/logo" /> + android:src="@drawable/logo" + android:alpha="0"/> + android:src="@drawable/text" + android:alpha="0"/> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_barometer.xml b/app/src/main/res/layout/activity_barometer.xml deleted file mode 100644 index 41dab3b00..000000000 --- a/app/src/main/res/layout/activity_barometer.xml +++ /dev/null @@ -1,285 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/activity_barometer_main.xml b/app/src/main/res/layout/activity_barometer_main.xml deleted file mode 100644 index 671c188ee..000000000 --- a/app/src/main/res/layout/activity_barometer_main.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_barometer_data.xml b/app/src/main/res/layout/fragment_barometer_data.xml new file mode 100644 index 000000000..a73b69214 --- /dev/null +++ b/app/src/main/res/layout/fragment_barometer_data.xml @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_faq.xml b/app/src/main/res/layout/fragment_faq.xml index fd6d4730d..900f62629 100644 --- a/app/src/main/res/layout/fragment_faq.xml +++ b/app/src/main/res/layout/fragment_faq.xml @@ -4,13 +4,14 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" - android:orientation="vertical" > + android:orientation="vertical"> + android:layout_weight="0.14" + android:childDivider="@android:color/transparent"> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_lux_meter_data.xml b/app/src/main/res/layout/fragment_lux_meter_data.xml index e43bea6f9..b65264ccc 100644 --- a/app/src/main/res/layout/fragment_lux_meter_data.xml +++ b/app/src/main/res/layout/fragment_lux_meter_data.xml @@ -1,143 +1,136 @@ - + android:layout_height="match_parent" + android:orientation="vertical"> - + android:layout_margin="@dimen/card_margin"> - + android:baselineAligned="false"> - - - - - - - - - - - - - - - - - - - - - - - - + android:layout_weight="3" + android:gravity="center_horizontal|center_vertical" + android:orientation="vertical"> + + + + + + + + + + + + + + - + + + + + + + + + + + - + android:layout_height="match_parent" + android:layout_weight="4"> - - - - - - - - - - - - - - + android:id="@+id/chart_xaxis_layout" + style="@style/graph_x_axis_title_block"> + + + - + + + + + + + + - + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/list_group.xml b/app/src/main/res/layout/list_group.xml index 9c002474a..16b13c259 100644 --- a/app/src/main/res/layout/list_group.xml +++ b/app/src/main/res/layout/list_group.xml @@ -9,36 +9,35 @@ + android:orientation="vertical"> + android:textColor="@color/colorPrimary" + android:textSize="@dimen/faq_question_text_size" /> + android:orientation="vertical"> diff --git a/app/src/main/res/layout/list_item.xml b/app/src/main/res/layout/list_item.xml index 989591be2..0f9f698d7 100644 --- a/app/src/main/res/layout/list_item.xml +++ b/app/src/main/res/layout/list_item.xml @@ -2,8 +2,9 @@ - + @@ -11,25 +12,24 @@ + android:textSize="@dimen/faq_question_text_size" /> + android:textSize="@dimen/text_size_wavegen" /> diff --git a/app/src/main/res/layout/logger_data_item.xml b/app/src/main/res/layout/logger_data_item.xml index 617a0ba2d..cf4029123 100644 --- a/app/src/main/res/layout/logger_data_item.xml +++ b/app/src/main/res/layout/logger_data_item.xml @@ -1,6 +1,7 @@ + android:tint="@color/colorPrimary" + tools:ignore="ContentDescription" /> + android:padding="5dp" + android:src="@drawable/ic_map_red_24dp" + tools:ignore="ContentDescription" /> + android:padding="5dp" + android:src="@drawable/ic_delete_red_24dp" + tools:ignore="ContentDescription" /> diff --git a/app/src/main/res/layout/splash_screen.xml b/app/src/main/res/layout/splash_screen.xml index 1c0ef9a71..ac2957da9 100644 --- a/app/src/main/res/layout/splash_screen.xml +++ b/app/src/main/res/layout/splash_screen.xml @@ -11,13 +11,15 @@ android:layout_width="match_parent" android:layout_height="@dimen/splash_screen_logo_height" android:contentDescription="@string/pocket_science_logo" - android:src="@drawable/logo" /> + android:src="@drawable/logo" + android:alpha="0"/> + app:srcCompat="@drawable/text" + android:alpha="0"/> \ No newline at end of file diff --git a/app/src/main/res/menu/lux_data_log_menu.xml b/app/src/main/res/menu/sensor_data_log_menu.xml similarity index 58% rename from app/src/main/res/menu/lux_data_log_menu.xml rename to app/src/main/res/menu/sensor_data_log_menu.xml index 085e6e06f..0f2eb1f01 100644 --- a/app/src/main/res/menu/lux_data_log_menu.xml +++ b/app/src/main/res/menu/sensor_data_log_menu.xml @@ -4,29 +4,41 @@ + + + - - diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 717caa8f6..323378504 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -361,6 +361,15 @@ 8sp 16sp + 5dp + 5dp + 10dp + 20dp + 200dp + 16sp + 8sp + 16sp + 5dp 18sp 3dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ef55fdc55..f72c13202 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -527,6 +527,7 @@ Data Logger Start Logging Stop Logging + Stop Cancel OK Save Data @@ -915,17 +916,6 @@ \u2022 The above pin configuration has to be same except for the pin GND. You can use any of the PSLab device GND pins.\n - Barometer - No barometer sensor in device - Connect a BMP180 sensor using I2C pins on PSLab to use this instrument - Measures the atmospheric pressure - \u2022 The Barometer can be used to measure Atmospheric pressure. This instrument - is compatible with either the built in pressure sensor on any android device or the BMP-180 pressure sensor.\n\n - \u2022 If you want to use the sensor BMP-180, connect the sensor to PSLab device as shown in the figure. - \u2022 The above pin configuration has to be same except for the pin - GND. GND is meant for Ground and any of the PSLab device GND pins can be used since they are common.\n\n - \u2022 Select the sensor by going to the Configure tab from the bottom navigation bar and choose BMP-180 in the drop down menu under Select Sensor. - Data Plot Configure High Limit @@ -974,12 +964,15 @@ Data Recording: Paused Recorded data deleted successfully Nothing to delete + Log deleted Please record some data CSV file stored at Are you sure you want to delete this file? Delete File DELETE + Delete + Are you sure you want to delete this log GPS not enabled Allow GPS @@ -1057,14 +1050,42 @@ Time Elapsed Experiment Logged Data Saved + Device does not have a barometer + + + Built-In + BMP180 + + + 0 + 1 + + + Barometer + atm + Avg (atm) + Min (atm) + Max (atm) + Connect a BMP180 sensor using I2C pins on PSLab to use this instrument + Measures the atmospheric pressure + \u2022 The Barometer can be used to measure Atmospheric pressure. This instrument + is compatible with either the built in pressure sensor on any android device or the BMP-180 pressure sensor.\n\n + \u2022 If you want to use the sensor BMP-180, connect the sensor to PSLab device as shown in the figure. + \u2022 The above pin configuration has to be same except for the pin + GND. GND is meant for Ground and any of the PSLab device GND pins can be used since they are common.\n\n + \u2022 Select the sensor by going to the Configure tab from the bottom navigation bar and choose BMP-180 in the drop down menu under Select Sensor. + Lux Meter + Log saved in\n + Could not save the log. Please check storage permission. + Open + Play \u2022 The Lux meter can be used to measure the ambient light intensity. This instruments is compatible with either the built in light sensor on any android device or the BH-1750 light sensor.\n\n \u2022 If you want to use the sensor BH-1750, connect the sensor to PSLab device as shown below \u2022 The above pin configuration has to be same except for the pin GND. GND is meant for Ground and any of the PSLab device GND pins can be used since they are common.\n\n \u2022 Select sensor by going to the Configure tab from the bottom navigation bar and choose BHT-1750 in the drop down menu under Select Sensor.\n - Lux Meter Configurations No Data Fetched Recorder Save Graph diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index e48d6e4d5..7a361a809 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -70,6 +70,28 @@ 15sp + + + +