diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f5ed6fd9a..cbe09cc83 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,9 +16,9 @@ + - - + \ No newline at end of file diff --git a/app/src/main/java/io/pslab/activity/AccelerometerActivity.java b/app/src/main/java/io/pslab/activity/AccelerometerActivity.java index 74e7c26bc..b34074429 100644 --- a/app/src/main/java/io/pslab/activity/AccelerometerActivity.java +++ b/app/src/main/java/io/pslab/activity/AccelerometerActivity.java @@ -150,7 +150,7 @@ public boolean onOptionsItemSelected(MenuItem item) { } else { checkGpsOnResume = true; } - gpsLogger.startFetchingLocation(); + gpsLogger.startCaptureLocation(); } else { recordData = true; CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.data_recording_start) + "\n" + getString(R.string.location_disabled), null, null); @@ -173,7 +173,7 @@ public boolean onOptionsItemSelected(MenuItem item) { } if (locationPref && gpsLogger != null) { String data; - Location location = gpsLogger.getBestLocation(); + Location location = gpsLogger.getDeviceLocation(); if (location != null) { data = "\nLocation" + "," + String.valueOf(location.getLatitude()) + "," + String.valueOf(location.getLongitude() + "\n"); } else { diff --git a/app/src/main/java/io/pslab/activity/DataLoggerActivity.java b/app/src/main/java/io/pslab/activity/DataLoggerActivity.java index 9bde96b67..7c3e9fd7e 100644 --- a/app/src/main/java/io/pslab/activity/DataLoggerActivity.java +++ b/app/src/main/java/io/pslab/activity/DataLoggerActivity.java @@ -12,17 +12,18 @@ import butterknife.ButterKnife; import io.pslab.R; import io.pslab.adapters.SensorLoggerListAdapter; -import io.pslab.models.SensorLogged; -import io.realm.Realm; +import io.pslab.models.SensorDataBlock; +import io.pslab.others.LocalDataLog; import io.realm.RealmResults; -import io.realm.Sort; /** * Created by Avjeet on 05/08/18. */ public class DataLoggerActivity extends AppCompatActivity { + public static final String CALLER_ACTIVITY = "Caller"; + @BindView(R.id.recycler_view) RecyclerView recyclerView; @@ -35,33 +36,29 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_data_logger); ButterKnife.bind(this); setSupportActionBar(toolbar); - Realm realm = Realm.getDefaultInstance(); String caller = getIntent().getStringExtra(CALLER_ACTIVITY); - if (caller == null) - caller = ""; + if (getSupportActionBar() != null) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setDisplayShowHomeEnabled(true); + } + if (caller == null) caller = ""; + + RealmResults categoryData; - RealmResults results; - String title; switch (caller) { case "Lux Meter": - results = realm.where(SensorLogged.class).equalTo("sensor", caller) - .findAll() - .sort("dateTimeStart", Sort.DESCENDING); - title = caller + " Data"; + getSupportActionBar().setTitle(caller); + categoryData = LocalDataLog.with().getTypeOfSensorBlocks("Lux Meter"); break; default: - results = realm.where(SensorLogged.class) - .findAll() - .sort("dateTimeStart", Sort.DESCENDING); - title = getString(R.string.logged_data); - } - if (getSupportActionBar() != null) { - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setDisplayShowHomeEnabled(true); - getSupportActionBar().setTitle(title); + // TODO: Fetch all + categoryData = LocalDataLog.with().getTypeOfSensorBlocks("Lux Meter"); + getSupportActionBar().setTitle(getString(R.string.logged_data)); } - SensorLoggerListAdapter adapter = new SensorLoggerListAdapter(results, this); - LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); + + SensorLoggerListAdapter adapter = new SensorLoggerListAdapter(categoryData, this); + LinearLayoutManager linearLayoutManager = new LinearLayoutManager( + this, LinearLayoutManager.VERTICAL, false); recyclerView.setLayoutManager(linearLayoutManager); DividerItemDecoration itemDecor = new DividerItemDecoration(this, DividerItemDecoration.HORIZONTAL); diff --git a/app/src/main/java/io/pslab/activity/LuxMeterActivity.java b/app/src/main/java/io/pslab/activity/LuxMeterActivity.java index 67e5cf65a..1b8ded58e 100644 --- a/app/src/main/java/io/pslab/activity/LuxMeterActivity.java +++ b/app/src/main/java/io/pslab/activity/LuxMeterActivity.java @@ -1,309 +1,133 @@ package io.pslab.activity; -import android.Manifest; -import android.content.Context; -import android.content.Intent; import android.content.SharedPreferences; -import android.content.pm.PackageManager; -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.v4.app.ActivityCompat; -import android.support.v4.app.FragmentTransaction; -import android.support.v4.content.ContextCompat; -import android.support.v7.app.AppCompatActivity; +import android.support.v4.app.Fragment; import android.support.v7.preference.PreferenceManager; -import android.support.v7.widget.Toolbar; -import android.view.GestureDetector; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.Toast; -import butterknife.BindView; -import butterknife.ButterKnife; import io.pslab.R; -import io.pslab.fragment.LuxMeterFragmentData; +import io.pslab.fragment.LuxMeterDataFragment; import io.pslab.fragment.LuxMeterSettingFragment; -import io.pslab.others.CSVLogger; -import io.pslab.others.CustomSnackBar; -import io.pslab.others.GPSLogger; -import io.pslab.others.MathUtils; -import io.pslab.others.SwipeGestureDetector; +import io.pslab.models.LuxData; +import io.pslab.models.PSLabSensor; +import io.pslab.models.SensorDataBlock; +import io.pslab.others.LocalDataLog; +import io.realm.RealmObject; +import io.realm.RealmResults; -public class LuxMeterActivity extends AppCompatActivity { +public class LuxMeterActivity extends PSLabSensor { private static final String PREF_NAME = "customDialogPreference"; - private static final int MY_PERMISSIONS_REQUEST_STORAGE_FOR_DATA = 101; - private static final int MY_PERMISSIONS_REQUEST_STORAGE_FOR_MAPS = 102; + public RealmResults recordedLuxData; - public boolean recordData = false; - public boolean exportData = false; - public boolean recordingStarted = false; - public GPSLogger gpsLogger; - public CSVLogger luxLogger; - private Menu menu; - - BottomSheetBehavior bottomSheetBehavior; - GestureDetector gestureDetector; - - @BindView(R.id.toolbar) - Toolbar toolbar; - @BindView(R.id.cl) - CoordinatorLayout coordinatorLayout; - //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 boolean checkGpsOnResume = false; - public boolean locationPref; - private LuxMeterFragmentData selectedFragment; - public static final String NAME = "realmData"; - private SharedPreferences realmPreferences; + @Override + public int getLayout() { + return R.layout.activity_generic_sensor; + } @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_lux_main); - ButterKnife.bind(this); - setSupportActionBar(toolbar); - realmPreferences = getSharedPreferences(NAME, Context.MODE_PRIVATE); - new GPSLogger(this).requestPermissionIfNotGiven(); - setUpBottomSheet(); - tvShadow.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) - bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); - tvShadow.setVisibility(View.GONE); - } - }); - try { - FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); - selectedFragment = LuxMeterFragmentData.newInstance(); - transaction.replace(R.id.frame_layout_lux_meter, selectedFragment, selectedFragment.getTag()); - transaction.commit(); - } catch (Exception e) { - e.printStackTrace(); - } + public int getMenu() { + return R.menu.lux_data_log_menu; } - private void setUpBottomSheet() { - bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet); + @Override + public SharedPreferences getStateSettings() { + return this.getSharedPreferences(PREF_NAME, MODE_PRIVATE); + } - final SharedPreferences settings = this.getSharedPreferences(PREF_NAME, MODE_PRIVATE); - Boolean isFirstTime = settings.getBoolean("LuxMeterFirstTime", true); + @Override + public String getFirstTimeSettingID() { + return "LuxMeterFirstTime"; + } - bottomSheetGuideTitle.setText(R.string.lux_meter); - bottomSheetText.setText(R.string.lux_meter_intro); - bottomSheetSchematic.setImageResource(R.drawable.bh1750_schematic); - bottomSheetDesc.setText(R.string.lux_meter_desc); + @Override + public String getSensorName() { + return getResources().getString(R.string.lux_meter); + } - 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("LuxMeterFirstTime", false); - editor.apply(); - } else { - bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); - } + @Override + public int getGuideTitle() { + return R.string.lux_meter; + } - 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 int getGuideAbstract() { + return R.string.lux_meter_intro; + } - @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; + @Override + public int getGuideSchematics() { + return R.drawable.bh1750_schematic; + } - case BottomSheetBehavior.STATE_COLLAPSED: - handler.postDelayed(runnable, 2000); - break; + @Override + public int getGuideDescription() { + return R.string.lux_meter_desc; + } - default: - handler.removeCallbacks(runnable); - bottomSheetSlideText.setText(R.string.show_guide_text); - break; - } - } + @Override + public int getGuideExtraContent() { + return 0; + } - @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 void recordSensorDataBlockID(SensorDataBlock categoryData) { + realm.beginTransaction(); + realm.copyToRealm(categoryData); + realm.commitTransaction(); } @Override - public boolean onTouchEvent(MotionEvent event) { - gestureDetector.onTouchEvent(event); //Gesture detector need this to transfer touch event to the gesture detector. - return super.onTouchEvent(event); + public void recordSensorData(RealmObject sensorData) { + realm.beginTransaction(); + realm.copyToRealm((LuxData) sensorData); + realm.commitTransaction(); } @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.lux_data_log_menu, menu); - this.menu = menu; - return true; + public void stopRecordSensorData() { + LocalDataLog.with().refresh(); } @Override - public boolean onPrepareOptionsMenu(Menu menu) { - MenuItem item = menu.findItem(R.id.record_data); - item.setIcon(recordData ? R.drawable.ic_record_stop_white : R.drawable.ic_record_white); - return super.onPrepareOptionsMenu(menu); + public Fragment getSensorFragment() { + return LuxMeterDataFragment.newInstance(); } @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.record_data: - if (recordData) { - ((LuxMeterFragmentData) selectedFragment).stopSensorFetching(); - invalidateOptionsMenu(); - Long uniqueRef = realmPreferences.getLong("uniqueCount", 0); - if (selectedFragment.saveDataInRealm(uniqueRef, locationPref, gpsLogger)) { - CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.exp_data_saved), null, null); - SharedPreferences.Editor editor = realmPreferences.edit(); - editor.putLong("uniqueCount", uniqueRef + 1); - editor.commit(); - } else { - CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.no_data_fetched), null, null); - } - recordData = false; - } else { - if (locationPref) { - gpsLogger = new GPSLogger(this, (LocationManager) getSystemService(Context.LOCATION_SERVICE)); - if (gpsLogger.isGPSEnabled()) { - recordData = true; - ((LuxMeterFragmentData) selectedFragment).startSensorFetching(); - CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.data_recording_start) + "\n" + getString(R.string.location_enabled), null, null); - invalidateOptionsMenu(); - } else { - checkGpsOnResume = true; - } - gpsLogger.startFetchingLocation(); - } else { - recordData = true; - ((LuxMeterFragmentData) selectedFragment).startSensorFetching(); - CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.data_recording_start) + "\n" + getString(R.string.location_disabled), null, null); - invalidateOptionsMenu(); - } - } - break; - case R.id.show_map: - if (ContextCompat.checkSelfPermission(this, - Manifest.permission.WRITE_EXTERNAL_STORAGE) - != PackageManager.PERMISSION_GRANTED) { - ActivityCompat.requestPermissions(this, - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, MY_PERMISSIONS_REQUEST_STORAGE_FOR_MAPS); - return true; - } - Intent MAP = new Intent(getApplicationContext(), MapsActivity.class); - startActivity(MAP); - break; - case R.id.settings: - Intent settingIntent = new Intent(this, SettingsActivity.class); - settingIntent.putExtra("title", getResources().getString(R.string.lux_meter_configurations)); - startActivity(settingIntent); - break; - case R.id.show_logged_data: - Intent intent = new Intent(this, DataLoggerActivity.class); - intent.putExtra(DataLoggerActivity.CALLER_ACTIVITY, "Lux Meter"); - startActivity(intent); - break; - case R.id.show_guide: - bottomSheetBehavior.setState(bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_HIDDEN ? - BottomSheetBehavior.STATE_EXPANDED : BottomSheetBehavior.STATE_HIDDEN); - break; - default: - break; + public void getDataFromDataLogger() { + if (getIntent().getExtras() != null && getIntent().getExtras().getBoolean(KEY_LOG)) { + playingData = true; + recordedLuxData = LocalDataLog.with() + .getBlockOfLuxRecords(getIntent().getExtras().getLong(DATA_BLOCK)); + String title = titleFormat.format(recordedLuxData.get(0).getTime()); + getSupportActionBar().setTitle(title); } - return true; } + /** + * Once settings have been changed, those changes can be captured from onResume method. + */ @Override protected void onResume() { super.onResume(); - SharedPreferences sharedPref; - sharedPref = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); - if (checkGpsOnResume) { - if (gpsLogger.isGPSEnabled()) { - recordData = true; - gpsLogger.startFetchingLocation(); - ((LuxMeterFragmentData) selectedFragment).startSensorFetching(); - invalidateOptionsMenu(); - CustomSnackBar.showSnackBar(coordinatorLayout, getString(R.string.data_recording_start) + "\n" + getString(R.string.location_enabled), null, null); - } else { - recordData = false; - Toast.makeText(getApplicationContext(), getString(R.string.gps_not_enabled), - Toast.LENGTH_SHORT).show(); - gpsLogger.removeUpdate(); - } - checkGpsOnResume = false; - } - locationPref = sharedPref.getBoolean(LuxMeterSettingFragment.KEY_INCLUDE_LOCATION, false); - if (!locationPref && gpsLogger != null) { - gpsLogger = null; - } - String highLimit = sharedPref.getString(LuxMeterSettingFragment.KEY_HIGH_LIMIT, "2000"); - String updatePeriod = sharedPref.getString(LuxMeterSettingFragment.KEY_UPDATE_PERIOD, "1000"); - LuxMeterFragmentData.setParameters(getValueFromText(highLimit, 10, 10000), getValueFromText(updatePeriod, 100, 1000)); + reinstateConfigurations(); } - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - if (requestCode == MY_PERMISSIONS_REQUEST_STORAGE_FOR_MAPS - && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - Intent MAP = new Intent(getApplicationContext(), MapsActivity.class); - startActivity(MAP); - } + private void reinstateConfigurations() { + SharedPreferences luxMeterConfigurations; + luxMeterConfigurations = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); + locationEnabled = luxMeterConfigurations.getBoolean(LuxMeterSettingFragment.KEY_INCLUDE_LOCATION, true); + LuxMeterDataFragment.setParameters( + getValueFromText(luxMeterConfigurations.getString(LuxMeterSettingFragment.KEY_HIGH_LIMIT, "2000"), + 10, 10000), + getValueFromText(luxMeterConfigurations.getString(LuxMeterSettingFragment.KEY_UPDATE_PERIOD, "1000"), + 100, 1000), + luxMeterConfigurations.getString(LuxMeterSettingFragment.KEY_LUX_SENSOR_TYPE, "0"), + luxMeterConfigurations.getString(LuxMeterSettingFragment.KEY_LUX_SENSOR_GAIN, "1")); } - public int getValueFromText(String strValue, int lowerBound, int upperBound) { - - if ("".equals(strValue)) { - return lowerBound; - } + private int getValueFromText(String strValue, int lowerBound, int upperBound) { + if (strValue.isEmpty()) return lowerBound; int value = Integer.parseInt(strValue); if (value > upperBound) return upperBound; else if (value < lowerBound) return lowerBound; diff --git a/app/src/main/java/io/pslab/activity/MainActivity.java b/app/src/main/java/io/pslab/activity/MainActivity.java index 4ea6a5251..0104bb156 100644 --- a/app/src/main/java/io/pslab/activity/MainActivity.java +++ b/app/src/main/java/io/pslab/activity/MainActivity.java @@ -12,6 +12,7 @@ import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.customtabs.CustomTabsServiceConnection; import android.support.design.widget.NavigationView; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; @@ -66,6 +67,7 @@ public class MainActivity extends AppCompatActivity { private ProgressDialog initialisationDialog; private CustomTabService customTabService; + private CustomTabsServiceConnection customTabsServiceConnection; public static int navItemIndex = 0; @@ -110,7 +112,7 @@ protected void onCreate(Bundle savedInstanceState) { usbManager = (UsbManager) getSystemService(USB_SERVICE); - customTabService = new CustomTabService(MainActivity.this); + customTabService = new CustomTabService(MainActivity.this, customTabsServiceConnection); mScienceLabCommon = ScienceLabCommon.getInstance(); @@ -436,6 +438,9 @@ protected void onDestroy() { e.printStackTrace(); } unregisterReceiver(usbDetachReceiver); + if (customTabsServiceConnection != null) { + this.unbindService(customTabsServiceConnection); + } if (receiverRegister) unregisterReceiver(mUsbReceiver); } diff --git a/app/src/main/java/io/pslab/activity/MapsActivity.java b/app/src/main/java/io/pslab/activity/MapsActivity.java index 6aea0e1fe..93f74cbbb 100644 --- a/app/src/main/java/io/pslab/activity/MapsActivity.java +++ b/app/src/main/java/io/pslab/activity/MapsActivity.java @@ -1,13 +1,18 @@ package io.pslab.activity; -import android.support.v7.app.AppCompatActivity; import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; -import io.pslab.R; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import org.osmdroid.api.IMapController; import org.osmdroid.tileprovider.tilesource.TileSourceFactory; import org.osmdroid.util.GeoPoint; import org.osmdroid.views.MapView; +import org.osmdroid.views.overlay.Marker; + +import io.pslab.R; /** * Created by Padmal on 11/7/18. @@ -16,6 +21,7 @@ public class MapsActivity extends AppCompatActivity { MapView map = null; + private Marker m; @Override protected void onCreate(Bundle savedInstanceState) { @@ -27,10 +33,36 @@ protected void onCreate(Bundle savedInstanceState) { map.setBuiltInZoomControls(true); map.setMultiTouchControls(true); + m = new Marker(map); + IMapController mapController = map.getController(); mapController.setZoom((double) 9); - GeoPoint startPoint = new GeoPoint(0.00, 0.00); - mapController.setCenter(startPoint); + + if (getIntent().getExtras() != null && getIntent().getExtras().getBoolean("hasMarkers")) { + try { + JSONArray markers = new JSONArray(getIntent().getExtras().getString("markers")); + addMarkers(markers); + } catch (JSONException e) { + e.printStackTrace(); + } finally { + map.invalidate(); + mapController.setCenter(m.getPosition()); + } + } else { + GeoPoint startPoint = new GeoPoint(-33.8688, 151.2093); + mapController.setCenter(startPoint); + } + } + + private void addMarkers(JSONArray markers) throws JSONException { + for (int i = 0; i < markers.length(); i++) { + JSONObject marker = markers.getJSONObject(i); + m.setPosition(new GeoPoint(marker.getDouble("lat"), marker.getDouble("lon"))); + m.setTitle(marker.getString("data") + " @ " + marker.getString("date")); + m.setIcon(getResources().getDrawable(R.drawable.action_item_read)); + m.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_TOP); + map.getOverlays().add(m); + } } @Override diff --git a/app/src/main/java/io/pslab/activity/SensorGraphViewActivity.java b/app/src/main/java/io/pslab/activity/SensorGraphViewActivity.java index f82eb2c48..49b931f86 100644 --- a/app/src/main/java/io/pslab/activity/SensorGraphViewActivity.java +++ b/app/src/main/java/io/pslab/activity/SensorGraphViewActivity.java @@ -39,11 +39,8 @@ import butterknife.BindView; import butterknife.ButterKnife; import io.pslab.R; -import io.pslab.models.LuxData; import io.pslab.others.CSVLogger; import io.pslab.others.CustomSnackBar; -import io.realm.Realm; -import io.realm.RealmResults; public class SensorGraphViewActivity extends AppCompatActivity { public static final String TYPE_SENSOR = "sensor"; @@ -139,13 +136,7 @@ public void run() { tv_long.setText("NA"); } - Long foreignKey = intent.getLongExtra(DATA_FOREIGN_KEY, -1); - Realm realm = Realm.getDefaultInstance(); entries = new ArrayList<>(); - RealmResults results = realm.where(LuxData.class).equalTo(DATA_FOREIGN_KEY, foreignKey).findAll(); - for (LuxData item : results) { - entries.add(new Entry((float) item.getTimeElapsed(), item.getLux())); - } XAxis x = mChart.getXAxis(); YAxis y = mChart.getAxisLeft(); diff --git a/app/src/main/java/io/pslab/activity/SettingsActivity.java b/app/src/main/java/io/pslab/activity/SettingsActivity.java index d16d8ba85..b05e6fedf 100644 --- a/app/src/main/java/io/pslab/activity/SettingsActivity.java +++ b/app/src/main/java/io/pslab/activity/SettingsActivity.java @@ -52,7 +52,7 @@ protected void onCreate(Bundle savedInstanceState) { Fragment fragment; switch (title) { - case "Lux Meter Configurations": + case "Lux Meter": fragment = new LuxMeterSettingFragment(); break; default: @@ -82,12 +82,12 @@ protected void onDestroy() { @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { - case GPSLogger.MY_PERMISSIONS_REQUEST_LOCATION: { + case GPSLogger.PSLAB_PERMISSION_FOR_MAPS: { if (grantResults.length <= 0 || grantResults[0] != PackageManager.PERMISSION_GRANTED) { SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(getBaseContext()).edit(); editor.putBoolean(LuxMeterSettingFragment.KEY_INCLUDE_LOCATION, false); - editor.commit(); + editor.apply(); } } } diff --git a/app/src/main/java/io/pslab/activity/SplashActivity.java b/app/src/main/java/io/pslab/activity/SplashActivity.java index 755e27557..048f94b65 100644 --- a/app/src/main/java/io/pslab/activity/SplashActivity.java +++ b/app/src/main/java/io/pslab/activity/SplashActivity.java @@ -3,12 +3,13 @@ import android.content.Intent; import android.os.Bundle; import android.os.Handler; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; -import io.pslab.R; - import butterknife.ButterKnife; +import io.pslab.R; +import io.pslab.others.PSLabPermission; /** * Created by viveksb007 on 11/3/17. @@ -16,16 +17,37 @@ public class SplashActivity extends AppCompatActivity { - private static int SPLASH_TIME_OUT = 2000; private Handler handler; private Runnable runnable; + @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.splash_screen); ButterKnife.bind(this); + PSLabPermission psLabPermission = PSLabPermission.getInstance(); + if (psLabPermission.checkPermissions(SplashActivity.this, + PSLabPermission.ALL_PERMISSION)) { + exitSplashScreen(); + } + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + handler.removeCallbacks(runnable); + } + + @Override + public void onRequestPermissionsResult( + int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + exitSplashScreen(); + } + + private void exitSplashScreen() { handler = new Handler(); - handler.postDelayed(runnable=new Runnable() { + int SPLASH_TIME_OUT = 2000; + handler.postDelayed(runnable = new Runnable() { @Override public void run() { Intent intent = new Intent(SplashActivity.this, MainActivity.class); @@ -34,9 +56,4 @@ public void run() { } }, SPLASH_TIME_OUT); } - @Override - public void onBackPressed() { - super.onBackPressed(); - handler.removeCallbacks(runnable); - } } diff --git a/app/src/main/java/io/pslab/adapters/SensorLoggerListAdapter.java b/app/src/main/java/io/pslab/adapters/SensorLoggerListAdapter.java index 9ed7589a8..8134eff01 100644 --- a/app/src/main/java/io/pslab/adapters/SensorLoggerListAdapter.java +++ b/app/src/main/java/io/pslab/adapters/SensorLoggerListAdapter.java @@ -10,78 +10,113 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import android.widget.Toast; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.Locale; import io.pslab.R; -import io.pslab.activity.SensorGraphViewActivity; +import io.pslab.activity.LuxMeterActivity; +import io.pslab.activity.MapsActivity; import io.pslab.models.LuxData; -import io.pslab.models.SensorLogged; -import io.realm.Realm; +import io.pslab.models.SensorDataBlock; +import io.pslab.others.LocalDataLog; import io.realm.RealmRecyclerViewAdapter; import io.realm.RealmResults; /** * Created by Avjeet on 03-08-2018. */ -public class SensorLoggerListAdapter extends RealmRecyclerViewAdapter { + +public class SensorLoggerListAdapter extends RealmRecyclerViewAdapter { private Activity context; - private SimpleDateFormat sdf = new SimpleDateFormat("dd MMM,yyyy HH:mm:ss"); - private Realm realm; + private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault()); + private final String KEY_LOG = "has_log"; + private final String DATA_BLOCK = "data_block"; - public SensorLoggerListAdapter(RealmResults results, Activity context) { + public SensorLoggerListAdapter(RealmResults results, Activity context) { super(results, true, true); this.context = context; - realm = Realm.getDefaultInstance(); } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.logger_data_item, parent, false); + View itemView = LayoutInflater.from(parent.getContext()).inflate( + R.layout.logger_data_item, parent, false); return new ViewHolder(itemView); } @Override public void onBindViewHolder(@NonNull final ViewHolder holder, int position) { - SensorLogged temp = getItem(position); - holder.sensor.setText(temp.getSensor()); - Date date = new Date(temp.getDateTimeStart()); - holder.dateTime.setText(String.valueOf(sdf.format(date))); + final SensorDataBlock block = getItem(position); + assert block != null; + holder.sensor.setText(block.getSensorType()); + holder.dateTime.setText(String.valueOf(sdf.format(new Date(block.getBlock())))); holder.cardView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - SensorLogged item = getItem(holder.getAdapterPosition()); - Intent intent = new Intent(context, SensorGraphViewActivity.class); - intent.putExtra(SensorGraphViewActivity.TYPE_SENSOR, item.getSensor()); - intent.putExtra(SensorGraphViewActivity.DATA_FOREIGN_KEY, item.getUniqueRef()); - intent.putExtra(SensorGraphViewActivity.DATE_TIME_START,item.getDateTimeStart()); - intent.putExtra(SensorGraphViewActivity.DATE_TIME_END,item.getDateTimeEnd()); - intent.putExtra(SensorGraphViewActivity.TIME_ZONE,item.getTimeZone()); - intent.putExtra(SensorGraphViewActivity.LATITUDE,item.getLatitude()); - intent.putExtra(SensorGraphViewActivity.LONGITUDE,item.getLongitude()); - context.startActivity(intent); + 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); + } } }); holder.deleteIcon.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - RealmResults sensorItem = realm.where(SensorLogged.class).equalTo("uniqueRef", getItem(holder.getAdapterPosition()).getUniqueRef()).findAll(); - RealmResults results = realm.where(LuxData.class).equalTo("foreignKey", getItem(holder.getAdapterPosition()).getUniqueRef()).findAll(); - realm.beginTransaction(); - results.deleteAllFromRealm(); - sensorItem.deleteAllFromRealm(); - realm.commitTransaction(); + // TODO: Request confirmation + if (block.getSensorType().equalsIgnoreCase("Lux Meter")) { + LocalDataLog.with().clearBlockOfLuxRecords(block.getBlock()); + LocalDataLog.with().clearSensorBlock(block.getBlock()); + } + } + }); + holder.mapIcon.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (block.getSensorType().equalsIgnoreCase("Lux Meter")) { + RealmResults 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(); + } + } + 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; + private ImageView deleteIcon, mapIcon; private CardView cardView; public ViewHolder(View itemView) { @@ -89,6 +124,7 @@ public ViewHolder(View itemView) { dateTime = itemView.findViewById(R.id.date_time); sensor = itemView.findViewById(R.id.sensor_name); deleteIcon = itemView.findViewById(R.id.delete_item); + mapIcon = itemView.findViewById(R.id.map_item); cardView = itemView.findViewById(R.id.data_item_card); } } diff --git a/app/src/main/java/io/pslab/fragment/LuxMeterDataFragment.java b/app/src/main/java/io/pslab/fragment/LuxMeterDataFragment.java new file mode 100644 index 000000000..10e03e20d --- /dev/null +++ b/app/src/main/java/io/pslab/fragment/LuxMeterDataFragment.java @@ -0,0 +1,489 @@ +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.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.LuxMeterActivity; +import io.pslab.communication.ScienceLab; +import io.pslab.communication.peripherals.I2C; +import io.pslab.communication.sensors.BH1750; +import io.pslab.communication.sensors.TSL2561; +import io.pslab.models.LuxData; +import io.pslab.models.SensorDataBlock; +import io.pslab.others.ScienceLabCommon; + +import static android.content.Context.SENSOR_SERVICE; + +/** + * Created by Padmal on 11/2/18. + */ + +public class LuxMeterDataFragment extends Fragment { + + private static int sensorType = 0; + private static int highLimit = 2000; + private static int updatePeriod = 100; + private static int gain = 1; + private long timeElapsed; + private int count = 0, turns = 0; + private float sum = 0; + private boolean returningFromPause = false; + + private float luxValue = -1; + + private enum LUX_SENSOR {INBUILT_SENSOR, BH1750_SENSOR, TSL2561_SENSOR} + + @BindView(R.id.lux_max) + TextView statMax; + @BindView(R.id.lux_min) + TextView statMin; + @BindView(R.id.lux_avg) + TextView statMean; + @BindView(R.id.label_lux_sensor) + TextView sensorLabel; + @BindView(R.id.chart_lux_meter) + LineChart mChart; + @BindView(R.id.light_meter) + PointerSpeedometer lightMeter; + + private Timer graphTimer; + private SensorManager sensorManager; + private Sensor sensor; + private long startTime, block; + private ArrayList entries; + private ArrayList recordedLuxArray; + 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; + private LuxMeterActivity luxSensor; + + public static LuxMeterDataFragment newInstance() { + return new LuxMeterDataFragment(); + } + + public static void setParameters(int highLimit, int updatePeriod, String type, String gain) { + LuxMeterDataFragment.highLimit = highLimit; + LuxMeterDataFragment.updatePeriod = updatePeriod; + LuxMeterDataFragment.sensorType = Integer.valueOf(type); + LuxMeterDataFragment.gain = Integer.valueOf(gain); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + startTime = System.currentTimeMillis(); + entries = new ArrayList<>(); + luxSensor = (LuxMeterActivity) getActivity(); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_lux_meter_data, container, false); + unbinder = ButterKnife.bind(this, view); + setupInstruments(); + return view; + } + + @Override + public void onResume() { + super.onResume(); + if (luxSensor.playingData) { + sensorLabel.setText(getResources().getString(R.string.recorder)); + recordedLuxArray = new ArrayList<>(); + resetInstrumentData(); + playRecordedData(); + + } else if (!luxSensor.isRecording) { + updateGraphs(); + sum = 0; + count = 0; + currentMin = 10000; + currentMax = 0; + entries.clear(); + mChart.clear(); + mChart.invalidate(); + initiateLuxSensor(sensorType); + } else if (returningFromPause) { + updateGraphs(); + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + if (graphTimer != null) { + graphTimer.cancel(); + } + if (sensorManager != null) { + sensorManager.unregisterListener(lightSensorEventListener); + } + unbinder.unbind(); + } + + 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); + } + } + + 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() { + try { + playComplete = false; + 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(), "%.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; + } + } + }); + } + }, 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(); + } + } + + private void setupInstruments() { + lightMeter.setMaxSpeed(10000); + + 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); + } + + @Override + public void onPause() { + super.onPause(); + if (graphTimer != null) { + returningFromPause = true; + graphTimer.cancel(); + graphTimer = null; + if (luxSensor.playingData) { + luxSensor.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 && luxSensor.isRecording) { + if (luxSensor.writeHeaderToFile) { + luxSensor.csvLogger.prepareLogFile(); + luxSensor.csvLogger.writeCSVFile("Timestamp,DateTime,Readings,Latitude,Longitude"); + block = timestamp; + luxSensor.recordSensorDataBlockID(new SensorDataBlock(timestamp, luxSensor.getSensorName())); + luxSensor.writeHeaderToFile = !luxSensor.writeHeaderToFile; + } + if (luxSensor.addLocation && luxSensor.gpsLogger.isGPSEnabled()) { + String dateTime = luxSensor.dateFormat.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)); + luxSensor.csvLogger.writeCSVFile(timestamp + "," + dateTime + "," + + sensorReading + ",0.0,0.0"); + sensorData = new LuxData(timestamp, block, luxValue, 0.0, 0.0); + } + luxSensor.recordSensorData(sensorData); + } else { + luxSensor.writeHeaderToFile = true; + } + } + + private void visualizeData() { + if (currentMax < luxValue) { + currentMax = luxValue; + statMax.setText(String.valueOf(luxValue)); + } + if (currentMin > luxValue) { + currentMin = luxValue; + statMin.setText(String.valueOf(luxValue)); + } + y.setAxisMaximum(currentMax); + y.setAxisMinimum(currentMin); + y.setLabelCount(10); + if (luxValue >= 0) { + lightMeter.setWithTremble(false); + lightMeter.setSpeedAt(luxValue); + if (luxValue > highLimit) + lightMeter.setPointerColor(Color.RED); + else + lightMeter.setPointerColor(Color.WHITE); + + timeElapsed = ((System.currentTimeMillis() - startTime) / updatePeriod); + if (timeElapsed != previousTimeElapsed) { + previousTimeElapsed = timeElapsed; + Entry entry = new Entry((float) timeElapsed, luxValue); + Long currentTime = System.currentTimeMillis(); + writeLogToFile(currentTime, luxValue); + 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(); + } + } + } + + private SensorEventListener lightSensorEventListener = new SensorEventListener() { + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) {/**/} + + @Override + public void onSensorChanged(SensorEvent event) { + if (event.sensor.getType() == Sensor.TYPE_LIGHT) { + luxValue = event.values[0]; + } + } + }; + + private void resetInstrumentData() { + luxValue = 0; + count = 0; + currentMin = 10000; + currentMax = 0; + sum = 0; + sensor = null; + if (sensorManager != null) { + sensorManager.unregisterListener(lightSensorEventListener); + } + 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)); + lightMeter.setSpeedAt(0); + lightMeter.setWithTremble(false); + entries.clear(); + } + + private void initiateLuxSensor(int type) { + LUX_SENSOR s = LUX_SENSOR.values()[type]; + resetInstrumentData(); + ScienceLab scienceLab; + switch (s) { + case INBUILT_SENSOR: + sensorLabel.setText(getResources().getStringArray(R.array.lux_sensors)[0]); + sensorManager = (SensorManager) getContext().getSystemService(SENSOR_SERVICE); + sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); + if (sensor == null) { + Toast.makeText(getContext(), getResources().getString(R.string.no_lux_sensor), Toast.LENGTH_LONG).show(); + } else { + float max = sensor.getMaximumRange(); + lightMeter.setMaxSpeed(max); + sensorManager.registerListener(lightSensorEventListener, + sensor, SensorManager.SENSOR_DELAY_FASTEST); + } + break; + case BH1750_SENSOR: + sensorLabel.setText(getResources().getStringArray(R.array.lux_sensors)[1]); + scienceLab = ScienceLabCommon.scienceLab; + if (scienceLab.isConnected()) { + ArrayList data; + try { + I2C i2c = scienceLab.i2c; + data = i2c.scan(null); + if (data.contains(0x23)) { + BH1750 sensorBH1750 = new BH1750(i2c); + sensorBH1750.setRange(String.valueOf(gain)); + 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; + case TSL2561_SENSOR: + sensorLabel.setText(getResources().getStringArray(R.array.lux_sensors)[2]); + scienceLab = ScienceLabCommon.scienceLab; + if (scienceLab.isConnected()) { + try { + I2C i2c = scienceLab.i2c; + ArrayList data; + data = i2c.scan(null); + if (data.contains(0x39)) { + TSL2561 sensorTSL2561 = new TSL2561(i2c, scienceLab); + sensorTSL2561.setGain(String.valueOf(gain)); + sensorType = 2; + } 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; + } + } +} diff --git a/app/src/main/java/io/pslab/fragment/LuxMeterFragmentData.java b/app/src/main/java/io/pslab/fragment/LuxMeterFragmentData.java deleted file mode 100644 index bcb1d2470..000000000 --- a/app/src/main/java/io/pslab/fragment/LuxMeterFragmentData.java +++ /dev/null @@ -1,513 +0,0 @@ -package io.pslab.fragment; - -import android.annotation.SuppressLint; -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.AsyncTask; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.content.ContextCompat; -import android.support.v7.widget.CardView; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.Spinner; -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.text.DecimalFormat; -import java.util.ArrayList; -import java.util.TimeZone; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.Unbinder; -import io.pslab.R; -import io.pslab.communication.ScienceLab; -import io.pslab.communication.peripherals.I2C; -import io.pslab.communication.sensors.BH1750; -import io.pslab.communication.sensors.TSL2561; -import io.pslab.models.LuxData; -import io.pslab.models.SensorLogged; -import io.pslab.others.GPSLogger; -import io.pslab.others.ScienceLabCommon; -import io.realm.Realm; - -import static android.content.Context.SENSOR_SERVICE; - -public class LuxMeterFragmentData extends Fragment { - - private static int sensorType = 0; - private static int highLimit = 2000; - private static int updatePeriod = 100; - private final Object lock = new Object(); - - @BindView(R.id.lux_stat_max) - TextView statMax; - @BindView(R.id.lux_stat_min) - TextView statMin; - @BindView(R.id.lux_stat_mean) - TextView statMean; - @BindView(R.id.chart_lux_meter) - LineChart mChart; - @BindView(R.id.spinner_lux_sensor_gain) - Spinner gainValue; - @BindView(R.id.light_meter) - PointerSpeedometer lightMeter; - @BindView(R.id.cardview_gain_range) - CardView gainRangeCardView; - - private SensorDataFetch sensorDataFetch; - private BH1750 sensorBH1750 = null; - private TSL2561 sensorTSL2561 = null; - private SensorManager sensorManager; - private Sensor sensor; - private ScienceLab scienceLab; - private long startTime; - private long endTime; - private int flag; - private ArrayList entries; - private ArrayList luxRealmData; - private float currentMin; - private float currentMax; - private YAxis y; - private volatile boolean monitor = true; - private Unbinder unbinder; - private long previousTimeElapsed = (System.currentTimeMillis() - startTime) / 1000; - private GPSLogger gpsLogger; - private Runnable runnable; - private Realm realm; - private Spinner selectSensor; - - public static LuxMeterFragmentData newInstance() { - return new LuxMeterFragmentData(); - } - - public static void setParameters(int highLimit, int updatePeriod) { - LuxMeterFragmentData.highLimit = highLimit; - LuxMeterFragmentData.updatePeriod = updatePeriod; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setRetainInstance(true); - currentMin = 10000; - currentMax = 0; - entries = new ArrayList<>(); - luxRealmData = new ArrayList<>(); - realm = Realm.getDefaultInstance(); - - } - - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_lux_meter_data, container, false); - unbinder = ButterKnife.bind(this, view); - selectSensor = (Spinner) view.findViewById(R.id.spinner_select_light); - 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: - case 2: - 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; - } - } - } - }; - - changeSensor(sensorType); - gainRangeCardView.setVisibility(View.GONE); - - selectSensor.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - changeSensor(position); - } - - @Override - public void onNothingSelected(AdapterView parent) { - //do nothing - } - }); - - gainValue.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - try { - switch (position) { - case 0: - case 1: - case 2: - if (sensorBH1750 != null) { - sensorBH1750.setRange(gainValue.getSelectedItem().toString()); - } - break; - case 3: - case 4: - case 5: - if (sensorTSL2561 != null) { - sensorTSL2561.setGain(gainValue.getSelectedItem().toString()); - } - break; - default: - break; - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - @Override - public void onNothingSelected(AdapterView parent) { - //do nothing - } - }); - - lightMeter.setMaxSpeed(10000); - - 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); - - return view; - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - monitor = false; - if (sensor != null && sensorDataFetch != null) { - sensorManager.unregisterListener(sensorDataFetch); - sensorDataFetch.cancel(true); - } - unbinder.unbind(); - } - - 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 (sensorBH1750 != null && scienceLab.isConnected()) { - data = sensorBH1750.getRaw().floatValue(); - sensorManager.unregisterListener(this); - } else if (sensorTSL2561 != null && scienceLab.isConnected()) { - int[] dataSet = sensorTSL2561.getRaw(); - data = (float) dataSet[2]; - sensorManager.unregisterListener(this); - } else if (sensor != null) { - sensorManager.registerListener(this, sensor, updatePeriod); - } - } catch (IOException e) { - e.printStackTrace(); - } - return null; - } - - protected void onPostExecute(Void aVoid) { - super.onPostExecute(aVoid); - visualizeData(); - synchronized (lock) { - lock.notify(); - } - } - - @Override - public void onSensorChanged(SensorEvent event) { - data = Float.valueOf(df.format(event.values[0])); - visualizeData(); - unRegisterListener(); - } - - @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)); - } - - y.setAxisMaximum(currentMax); - y.setAxisMinimum(currentMin); - y.setLabelCount(10); - if (data != 0) { - lightMeter.setSpeedAt(data); - - if (data > highLimit) - lightMeter.setPointerColor(Color.RED); - else - lightMeter.setPointerColor(Color.WHITE); - timeElapsed = ((System.currentTimeMillis() - startTime) / 1000); - if (timeElapsed != previousTimeElapsed) { - previousTimeElapsed = timeElapsed; - Entry entry = new Entry((float) timeElapsed, data); - entries.add(entry); - Long currentTime = System.currentTimeMillis(); - LuxData tempObject = new LuxData(data, currentTime, timeElapsed); - luxRealmData.add(tempObject); - - count++; - sum += entry.getY(); - statMean.setText(Float.toString(Float.valueOf(df.format(sum / count)))); - - LineDataSet dataSet = new LineDataSet(entries, getString(R.string.lux)); - LineData data = new LineData(dataSet); - dataSet.setDrawCircles(false); - dataSet.setDrawValues(false); - dataSet.setLineWidth(2); - - mChart.setData(data); - mChart.notifyDataSetChanged(); - mChart.setVisibleXRangeMaximum(80); - mChart.moveViewToX(data.getEntryCount()); - mChart.invalidate(); - } - } - } - - @Override - public void onAccuracyChanged(Sensor sensor, int accuracy) { - //do nothing - } - - private void unRegisterListener() { - sensorManager.unregisterListener(this); - } - } - - public void startSensorFetching() { - entries.clear(); - mChart.invalidate(); - mChart.clear(); - monitor = true; - flag = 0; - lightMeter.setWithTremble(true); - - Thread dataThread = new Thread(runnable); - - dataThread.start(); - } - - public void stopSensorFetching() { - monitor = false; - endTime = System.currentTimeMillis(); - if (sensor != null && sensorDataFetch != null) { - sensorManager.unregisterListener(sensorDataFetch); - sensorDataFetch.cancel(true); - lightMeter.setWithTremble(false); - lightMeter.speedTo(0f, 500); - lightMeter.setPointerColor(ContextCompat.getColor(getActivity(), R.color.white)); - } - } - - public boolean saveDataInRealm(Long uniqueRef, boolean includeLocation, GPSLogger gpsLogger) { - boolean flag = luxRealmData.isEmpty(); - if (!flag) { - realm.beginTransaction(); - - SensorLogged sensorLogged = realm.createObject(SensorLogged.class, uniqueRef); - sensorLogged.setSensor(getResources().getString(R.string.lux_meter)); - sensorLogged.setDateTimeStart(startTime); - sensorLogged.setDateTimeEnd(endTime); - sensorLogged.setTimeZone(TimeZone.getDefault().getDisplayName()); - - if (includeLocation && gpsLogger != null) { - Location location = gpsLogger.getBestLocation(); - if (location != null) { - sensorLogged.setLatitude(location.getLatitude()); - sensorLogged.setLongitude(location.getLongitude()); - } else { - sensorLogged.setLatitude(0.0); - sensorLogged.setLongitude(0.0); - } - gpsLogger.removeUpdate(); - } else { - sensorLogged.setLatitude(0.0); - sensorLogged.setLongitude(0.0); - } - - for (int i = 0; i < luxRealmData.size(); i++) { - LuxData tempObject = luxRealmData.get(i); - tempObject.setId(i); - tempObject.setForeignKey(uniqueRef); - realm.copyToRealm(tempObject); - Log.i("dataResult", String.valueOf(tempObject.getLux())); - } - realm.copyToRealm(sensorLogged); - realm.commitTransaction(); - luxRealmData.clear(); - return true; - } else { - return false; - } - } - - @Override - public void onResume() { - super.onResume(); - mChart.clear(); - mChart.invalidate(); - } - - private void changeSensor(int sensorTypeSelected) { - switch (sensorTypeSelected) { - case 0: - sensorManager = (SensorManager) getContext().getSystemService(SENSOR_SERVICE); - sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); - break; - case 1: - scienceLab = ScienceLabCommon.scienceLab; - if (scienceLab.isConnected()) { - ArrayList data = new ArrayList<>(); - try { - I2C i2c = scienceLab.i2c; - data = i2c.scan(null); - if (data.contains(0x23)) { - sensorBH1750 = new BH1750(i2c); - gainRangeCardView.setVisibility(View.VISIBLE); - sensorType = 0; - } else { - Toast.makeText(getContext(), getResources().getText(R.string.sensor_not_connected_tls), Toast.LENGTH_SHORT).show(); - sensorType = 0; - selectSensor.setSelection(0); - } - } catch (IOException | InterruptedException e) { - e.printStackTrace(); - } - } else { - Toast.makeText(getContext(), getResources().getText(R.string.device_not_found), Toast.LENGTH_SHORT).show(); - sensorType = 0; - selectSensor.setSelection(0); - } - - break; - case 2: - scienceLab = ScienceLabCommon.scienceLab; - if (scienceLab.isConnected()) { - try { - I2C i2c = scienceLab.i2c; - ArrayList data = new ArrayList<>(); - data = i2c.scan(null); - if (data.contains(0x39)) { - sensorTSL2561 = new TSL2561(i2c, scienceLab); - gainRangeCardView.setVisibility(View.VISIBLE); - sensorType = 2; - } else { - Toast.makeText(getContext(), getResources().getText(R.string.sensor_not_connected_tls), Toast.LENGTH_SHORT).show(); - sensorType = 0; - selectSensor.setSelection(0); - } - } catch (IOException | InterruptedException e) { - e.printStackTrace(); - } - } else { - Toast.makeText(getContext(), getResources().getText(R.string.device_not_found), Toast.LENGTH_SHORT).show(); - sensorType = 0; - selectSensor.setSelection(0); - } - break; - default: - break; - } - } -} diff --git a/app/src/main/java/io/pslab/fragment/LuxMeterSettingFragment.java b/app/src/main/java/io/pslab/fragment/LuxMeterSettingFragment.java index ba775d998..f63cf4d45 100644 --- a/app/src/main/java/io/pslab/fragment/LuxMeterSettingFragment.java +++ b/app/src/main/java/io/pslab/fragment/LuxMeterSettingFragment.java @@ -1,17 +1,16 @@ package io.pslab.fragment; -import android.Manifest; +import android.annotation.SuppressLint; import android.content.SharedPreferences; -import android.content.pm.PackageManager; import android.os.Bundle; -import android.support.v4.content.ContextCompat; 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.GPSLogger; +import io.pslab.others.PSLabPermission; /** * Created by Avjeet on 10-08-2018. @@ -21,10 +20,16 @@ public class LuxMeterSettingFragment extends PreferenceFragmentCompat implements public static final String KEY_INCLUDE_LOCATION = "include_location_sensor_data"; public static final String KEY_UPDATE_PERIOD = "setting_lux_update_period"; public static final String KEY_HIGH_LIMIT = "setting_lux_high_limit"; + public static final String KEY_LUX_SENSOR_TYPE = "setting_lux_sensor_type"; + public static final String KEY_LUX_SENSOR_GAIN = "setting_lux_sensor_gain"; + + private PSLabPermission psLabPermission; private EditTextPreference updatePeriodPref; private EditTextPreference higLimitPref; + private EditTextPreference sensorGainPref; private CheckBoxPreference locationPreference; + private ListPreference sensorTypePreference; private SharedPreferences sharedPref; @Override @@ -32,25 +37,27 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { setPreferencesFromResource(R.xml.lux_meter_settings, rootKey); updatePeriodPref = (EditTextPreference) getPreferenceScreen().findPreference(KEY_UPDATE_PERIOD); higLimitPref = (EditTextPreference) getPreferenceScreen().findPreference(KEY_HIGH_LIMIT); + sensorGainPref = (EditTextPreference) getPreferenceScreen().findPreference(KEY_LUX_SENSOR_GAIN); locationPreference = (CheckBoxPreference) getPreferenceScreen().findPreference(KEY_INCLUDE_LOCATION); + sensorTypePreference = (ListPreference) getPreferenceScreen().findPreference(KEY_LUX_SENSOR_TYPE); sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity()); - if (ContextCompat.checkSelfPermission(getActivity(), - Manifest.permission.ACCESS_FINE_LOCATION) - != PackageManager.PERMISSION_GRANTED) { + psLabPermission = PSLabPermission.getInstance(); + if (!psLabPermission.checkPermissions(getActivity(), PSLabPermission.MAP_PERMISSION)) { SharedPreferences.Editor editor = sharedPref.edit(); editor.putBoolean(LuxMeterSettingFragment.KEY_INCLUDE_LOCATION, true); - editor.commit(); + editor.apply(); } - } @Override public void onResume() { super.onResume(); locationPreference.setChecked(sharedPref.getBoolean(KEY_INCLUDE_LOCATION, true)); - updatePeriodPref.setSummary("Update Period is " + updatePeriodPref.getText() + " ms"); - higLimitPref.setSummary("High Limit is " + higLimitPref.getText()); + updatePeriodPref.setSummary(updatePeriodPref.getText() + " ms"); + higLimitPref.setSummary(higLimitPref.getText() + " Lx"); + sensorTypePreference.setSummary(sensorTypePreference.getEntry()); + sensorGainPref.setSummary(sensorGainPref.getText()); getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); } @@ -60,19 +67,54 @@ public void onPause() { getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); } + @SuppressLint("ApplySharedPref") @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { switch (s) { case KEY_INCLUDE_LOCATION: if (locationPreference.isChecked()) { - new GPSLogger(getActivity()).requestPermissionIfNotGiven(); + psLabPermission.checkPermissions( + getActivity(), PSLabPermission.MAP_PERMISSION); } break; case KEY_UPDATE_PERIOD: - updatePeriodPref.setSummary("Update Period is " + updatePeriodPref.getText() + " " + "ms"); + try { + Integer updatePeriod = Integer.valueOf(updatePeriodPref.getText()); + 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_LUX_SENSOR_GAIN: + try { + Integer gain = Integer.valueOf(sensorGainPref.getText()); + sensorGainPref.setSummary(String.valueOf(gain)); + } catch (NumberFormatException e) { + sensorGainPref.setSummary("1"); + sensorGainPref.setText("1"); + SharedPreferences.Editor editor = sharedPref.edit(); + editor.putString(KEY_LUX_SENSOR_GAIN, "1"); + editor.commit(); + } break; case KEY_HIGH_LIMIT: - higLimitPref.setSummary("High Limit is " + higLimitPref.getText()); + try { + Integer highLimit = Integer.valueOf(higLimitPref.getText()); + higLimitPref.setSummary(String.valueOf(highLimit)); + } catch (NumberFormatException e) { + higLimitPref.setSummary("2000 Lx"); + higLimitPref.setText("2000"); + SharedPreferences.Editor editor = sharedPref.edit(); + editor.putString(KEY_HIGH_LIMIT, "2000"); + editor.commit(); + } + break; + case KEY_LUX_SENSOR_TYPE: + sensorTypePreference.setSummary(sensorTypePreference.getEntry()); break; default: break; diff --git a/app/src/main/java/io/pslab/interfaces/sensorloggers/LuxMeterRecordables.java b/app/src/main/java/io/pslab/interfaces/sensorloggers/LuxMeterRecordables.java new file mode 100644 index 000000000..bfa0c9249 --- /dev/null +++ b/app/src/main/java/io/pslab/interfaces/sensorloggers/LuxMeterRecordables.java @@ -0,0 +1,21 @@ +package io.pslab.interfaces.sensorloggers; + +import io.pslab.models.LuxData; +import io.realm.RealmResults; + +/** + * Created by Padmal on 11/5/18. + */ + +public interface LuxMeterRecordables { + + LuxData getLuxData(long timeStamp); + + void clearAllLuxRecords(); + + void clearBlockOfLuxRecords(long block); + + RealmResults getAllLuxRecords(); + + RealmResults getBlockOfLuxRecords(long block); +} diff --git a/app/src/main/java/io/pslab/interfaces/sensorloggers/SensorRecordables.java b/app/src/main/java/io/pslab/interfaces/sensorloggers/SensorRecordables.java new file mode 100644 index 000000000..93e8019e2 --- /dev/null +++ b/app/src/main/java/io/pslab/interfaces/sensorloggers/SensorRecordables.java @@ -0,0 +1,23 @@ +package io.pslab.interfaces.sensorloggers; + +import io.pslab.models.SensorDataBlock; +import io.realm.RealmResults; + +/** + * Created by Padmal on 11/5/18. + */ + +public interface SensorRecordables { + + SensorDataBlock getSensorBlock(long block); + + void clearAllSensorBlocks(); + + void clearTypeOfSensorBlock(String type); + + void clearSensorBlock(long block); + + RealmResults getAllSensorBlocks(); + + RealmResults getTypeOfSensorBlocks(String type); +} diff --git a/app/src/main/java/io/pslab/models/LuxData.java b/app/src/main/java/io/pslab/models/LuxData.java index 3f828353a..a596c5898 100644 --- a/app/src/main/java/io/pslab/models/LuxData.java +++ b/app/src/main/java/io/pslab/models/LuxData.java @@ -1,53 +1,72 @@ package io.pslab.models; - import io.realm.RealmObject; - +import io.realm.annotations.PrimaryKey; /** * Created by Avjeet on 31-07-2018. */ + public class LuxData extends RealmObject { - private long foreignKey; - private long id; + + @PrimaryKey private long time; + private long block; private float lux; - private long timeElapsed; + private double lat, lon; - public LuxData() { - } + public LuxData() {/**/} - public LuxData(float lux, long time, long timeElapsed) { + public LuxData(long time, long block, float lux, double lat, double lon) { + this.time = time; + this.block = block; this.lux = lux; + this.lat = lat; + this.lon = lon; + } + + public long getTime() { + return time; + } + + public void setTime(long time) { this.time = time; - this.timeElapsed = timeElapsed; } - public long getForeignKey() { - return foreignKey; + + public long getBlock() { + return block; } - public void setForeignKey(long foreignKey) { - this.foreignKey = foreignKey; + public void setBlock(long block) { + this.block = block; } - public long getId() { - return id; + public float getLux() { + return lux; } - public void setId(long id) { - this.id = id; + public void setLux(float lux) { + this.lux = lux; } + public double getLat() { + return lat; + } - public long getTime() { - return time; + public void setLat(double lat) { + this.lat = lat; } - public float getLux() { - return lux; + public double getLon() { + return lon; + } + + public void setLon(double lon) { + this.lon = lon; } - public long getTimeElapsed() { - return timeElapsed; + @Override + public String toString() { + return "Block - " + block + ", Time - " + time + ", Lux - " + lux + ", Lat - " + lat + ", Lon - " + lon; } } diff --git a/app/src/main/java/io/pslab/models/PSLabSensor.java b/app/src/main/java/io/pslab/models/PSLabSensor.java index ba0b5e766..6703931e2 100644 --- a/app/src/main/java/io/pslab/models/PSLabSensor.java +++ b/app/src/main/java/io/pslab/models/PSLabSensor.java @@ -1,17 +1,18 @@ package io.pslab.models; -import android.Manifest; +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.location.LocationManager; import android.os.Bundle; 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.v4.app.ActivityCompat; -import android.support.v4.content.ContextCompat; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.GestureDetector; @@ -24,6 +25,12 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import android.widget.Toast; + +import org.json.JSONArray; + +import java.text.SimpleDateFormat; +import java.util.Locale; import butterknife.BindView; import butterknife.ButterKnife; @@ -31,8 +38,16 @@ import io.pslab.activity.DataLoggerActivity; import io.pslab.activity.MapsActivity; import io.pslab.activity.SettingsActivity; +import io.pslab.fragment.LuxMeterDataFragment; +import io.pslab.others.CSVLogger; +import io.pslab.others.CustomSnackBar; +import io.pslab.others.GPSLogger; +import io.pslab.others.LocalDataLog; import io.pslab.others.MathUtils; +import io.pslab.others.PSLabPermission; import io.pslab.others.SwipeGestureDetector; +import io.realm.Realm; +import io.realm.RealmObject; /** * Created by Padmal on 10/20/18. @@ -40,17 +55,36 @@ public abstract class PSLabSensor extends AppCompatActivity { - public boolean recordData = false; - - public final int MY_PERMISSIONS_REQUEST_STORAGE_FOR_MAPS = 102; - - public Toolbar sensorToolBar; + public boolean isRecording = false; + public boolean locationEnabled = true; + public boolean addLocation = true; + public boolean checkGPSOnResume = false; + public boolean writeHeaderToFile = true; + public boolean playingData = false; + public CoordinatorLayout sensorParentView; public BottomSheetBehavior bottomSheetBehavior; public GestureDetector gestureDetector; - @BindView(R.id.cl) + public JSONArray markers; + + public Fragment sensorFragment; + public PSLabPermission psLabPermission; + public GPSLogger gpsLogger; + public CSVLogger csvLogger; + 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"; + + @BindView(R.id.sensor_toolbar) + Toolbar sensorToolBar; + @BindView(R.id.sensor_cl) CoordinatorLayout coordinatorLayout; + @BindView(R.id.bottom_sheet) LinearLayout bottomSheet; @BindView(R.id.shadow) @@ -84,13 +118,6 @@ public abstract class PSLabSensor extends AppCompatActivity { */ public abstract int getMenu(); - /** - * Getting toolbar layout distinct to each sensor - * - * @return Toolbar resource in 'R.id.id' format - */ - public abstract int getSensorToolBar(); - /** * Getting saved setting configurations for dialogs * @@ -147,63 +174,130 @@ public abstract class PSLabSensor extends AppCompatActivity { */ public abstract int getGuideExtraContent(); + /** + * This method will create a new entry in Realm database with a new block + * + * @param block Start timestamp of the recording + */ + public abstract void recordSensorDataBlockID(SensorDataBlock block); + /** * This method will be called upon when menu button for recording data has been clicked */ - public abstract void startRecordSensorData(); + public abstract void recordSensorData(RealmObject sensorData); /** * This method will be called upon when menu button for stop recording data has been clicked */ public abstract void stopRecordSensorData(); + /** + * Fragment implementation of each individual sensor + * + * @return Custom fragment instance of the sensor + */ + public abstract Fragment getSensorFragment(); + + /** + * This method will fetch logged data information from the data logger activity + */ + public abstract void getDataFromDataLogger(); + @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(getLayout()); ButterKnife.bind(this); - sensorToolBar = findViewById(getSensorToolBar()); setSupportActionBar(sensorToolBar); + getSupportActionBar().setTitle(getSensorName()); + markers = new JSONArray(); + psLabPermission = PSLabPermission.getInstance(); + gpsLogger = new GPSLogger(this, + (LocationManager) getSystemService(Context.LOCATION_SERVICE)); + 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(); + fillUpFragment(); + invalidateOptionsMenu(); + } + + /** + * Fill up the frame with the individual sensor fragment layout + */ + private void fillUpFragment() { + try { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + sensorFragment = getSensorFragment(); + transaction.replace(R.id.sensor_frame, sensorFragment, getSensorName()); + transaction.commit(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void setUpMenu(Menu menu) { + if (playingData) { + for (int i = 0; i < menu.size(); i++) { + menu.getItem(i).setVisible(false); + } + } + menu.findItem(R.id.save_graph).setVisible(playingData); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(getMenu(), menu); + setUpMenu(menu); return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { - MenuItem item = menu.findItem(R.id.record_data); - item.setIcon(recordData ? R.drawable.ic_record_stop_white : R.drawable.ic_record_white); + MenuItem record = menu.findItem(R.id.record_data); + record.setIcon(isRecording ? R.drawable.ic_record_stop_white : R.drawable.ic_record_white); return super.onPrepareOptionsMenu(menu); } + private void prepareMarkers() { + if (markers.length() > 0) { + map.putExtra("hasMarkers", true); + map.putExtra("markers", markers.toString()); + } else { + map.putExtra("hasMarkers", false); + } + } + @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { + /* + When record data button has been pressed, check if the device has write permission + to log and access to location. checkPermission method will prompt user with a dialog + box to allow app to use those features. Upon allowing, onRequestPermissionsResult + will fire up. If user declines to give permission, don't do anything. + */ case R.id.record_data: - if (recordData) { - startRecordSensorData(); + if (!isRecording) { + dataRecordingCycle(); } else { stopRecordSensorData(); + CustomSnackBar.showSnackBar(sensorParentView, + getString(R.string.data_recording_stopped), null, null); + isRecording = false; + prepareMarkers(); } - recordData = !recordData; invalidateOptionsMenu(); break; case R.id.show_map: - if (ContextCompat.checkSelfPermission(this, - Manifest.permission.WRITE_EXTERNAL_STORAGE) - != PackageManager.PERMISSION_GRANTED) { - ActivityCompat.requestPermissions(this, - new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, - MY_PERMISSIONS_REQUEST_STORAGE_FOR_MAPS); - return true; + if (psLabPermission.checkPermissions(PSLabSensor.this, + PSLabPermission.MAP_PERMISSION)) { + startActivity(map); } - Intent MAP = new Intent(getApplicationContext(), MapsActivity.class); - startActivity(MAP); break; case R.id.settings: Intent settingIntent = new Intent(this, SettingsActivity.class); @@ -211,26 +305,99 @@ public boolean onOptionsItemSelected(MenuItem item) { startActivity(settingIntent); break; case R.id.show_logged_data: - Intent intent = new Intent(this, DataLoggerActivity.class); - intent.putExtra(DataLoggerActivity.CALLER_ACTIVITY, getSensorName()); - startActivity(intent); + if (psLabPermission.checkPermissions(PSLabSensor.this, + PSLabPermission.CSV_PERMISSION)) { + Intent intent = new Intent(this, DataLoggerActivity.class); + intent.putExtra(DataLoggerActivity.CALLER_ACTIVITY, getSensorName()); + startActivity(intent); + } break; case R.id.show_guide: bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); break; + case R.id.save_graph: + if (getSensorFragment() instanceof LuxMeterDataFragment) { + ((LuxMeterDataFragment) getSupportFragmentManager() + .findFragmentByTag(getSensorName())).saveGraph(); + } + break; default: break; } return true; } + private void dataRecordingCycle() { + if (psLabPermission.checkPermissions(PSLabSensor.this, PSLabPermission.LOG_PERMISSION)) { + if (locationEnabled) { + if (psLabPermission.checkPermissions(PSLabSensor.this, PSLabPermission.GPS_PERMISSION)) { + gpsRecordingCycle(); + } + } else { + CustomSnackBar.showSnackBar(sensorParentView, + getString(R.string.data_recording_without_location), null, null); + isRecording = true; + } + } + } + + private void gpsRecordingCycle() { + addLocation = true; + gpsLogger.startCaptureLocation(); + if (gpsLogger.isGPSEnabled()) { + CustomSnackBar.showSnackBar(sensorParentView, + getString(R.string.data_recording_with_location), null, null); + isRecording = true; + } else { + gpsLogger.gpsAlert.show(); + } + } + + private void nogpsRecordingCycle() { + CustomSnackBar.showSnackBar(sensorParentView, + getString(R.string.data_recording_without_location), null, null); + addLocation = false; + isRecording = true; + } + @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - if (requestCode == MY_PERMISSIONS_REQUEST_STORAGE_FOR_MAPS - && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - Intent MAP = new Intent(getApplicationContext(), MapsActivity.class); - startActivity(MAP); + switch (requestCode) { + case PSLabPermission.MAP_PERMISSION: + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + Intent map = new Intent(getApplicationContext(), MapsActivity.class); + startActivity(map); + } else { + Toast.makeText(getApplicationContext(), + getResources().getString(R.string.no_permission_for_maps), + Toast.LENGTH_LONG).show(); + } + break; + case PSLabPermission.LOG_PERMISSION: + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + dataRecordingCycle(); + invalidateOptionsMenu(); + } + break; + case PSLabPermission.GPS_PERMISSION: + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + gpsRecordingCycle(); + invalidateOptionsMenu(); + } else { + nogpsRecordingCycle(); + invalidateOptionsMenu(); + } + break; + case PSLabPermission.CSV_PERMISSION: + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + Intent intent = new Intent(this, DataLoggerActivity.class); + intent.putExtra(DataLoggerActivity.CALLER_ACTIVITY, getSensorName()); + startActivity(intent); + } + break; + default: + break; } } @@ -247,10 +414,25 @@ private void setUpBottomSheet() { setupGuideLayout(); handleFirstTimeUsage(); handleBottomSheetBehavior(); + handleShadowClicks(); gestureDetector = new GestureDetector(this, new SwipeGestureDetector(bottomSheetBehavior)); } + /** + * Closes the guide when user clicks on dark background area + */ + private void handleShadowClicks() { + tvShadow.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) + bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); + tvShadow.setVisibility(View.GONE); + } + }); + } + /** * Handle sliding up and down behaviors and proper handling in closure. */ @@ -261,6 +443,7 @@ private void handleBottomSheetBehavior() { @Override public void run() { bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); + tvShadow.setVisibility(View.GONE); } }; @@ -277,6 +460,7 @@ public void onStateChanged(@NonNull final View bottomSheet, int newState) { break; default: + tvShadow.setVisibility(View.GONE); handler.removeCallbacks(runnable); bottomSheetSlideText.setText(R.string.show_guide_text); break; @@ -285,7 +469,8 @@ public void onStateChanged(@NonNull final View bottomSheet, int newState) { @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { - Float value = (float) MathUtils.map((double) slideOffset, 0.0, 1.0, 0.0, 0.8); + 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); @@ -328,7 +513,18 @@ private void handleFirstTimeUsage() { editor.apply(); } else { bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); + tvShadow.setVisibility(View.GONE); } } + @Override + protected void onResume() { + super.onResume(); + getDataFromDataLogger(); + if (checkGPSOnResume) { + isRecording = true; + checkGPSOnResume = false; + invalidateOptionsMenu(); + } + } } diff --git a/app/src/main/java/io/pslab/models/SensorDataBlock.java b/app/src/main/java/io/pslab/models/SensorDataBlock.java new file mode 100644 index 000000000..e25d8a200 --- /dev/null +++ b/app/src/main/java/io/pslab/models/SensorDataBlock.java @@ -0,0 +1,36 @@ +package io.pslab.models; + +import io.realm.RealmObject; + +/** + * Created by Padmal on 11/5/18. + */ + +public class SensorDataBlock extends RealmObject { + + private long block; + private String sensorType; + + public SensorDataBlock() {/**/} + + public SensorDataBlock(long block, String sensorType) { + this.block = block; + this.sensorType = sensorType; + } + + public long getBlock() { + return block; + } + + public void setBlock(long block) { + this.block = block; + } + + public String getSensorType() { + return sensorType; + } + + public void setSensorType(String sensorType) { + this.sensorType = sensorType; + } +} diff --git a/app/src/main/java/io/pslab/others/CSVLogger.java b/app/src/main/java/io/pslab/others/CSVLogger.java index 55e3c87bd..f723d8bdd 100644 --- a/app/src/main/java/io/pslab/others/CSVLogger.java +++ b/app/src/main/java/io/pslab/others/CSVLogger.java @@ -57,7 +57,10 @@ private void setupPath() { e.printStackTrace(); } } - TIME = new SimpleDateFormat("yyyyMMdd-hh:mm:ss", Locale.getDefault()); + } + + public void prepareLogFile() { + TIME = new SimpleDateFormat("yyyyMMdd-hh:mm:ss:SSS", Locale.getDefault()); String uniqueFileName = TIME.format(new Date()); csvFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + CSV_DIRECTORY + File.separator + category + @@ -81,7 +84,7 @@ public void writeCSVFile(String data) { try { PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(csvFile, true))); - out.write(data); + out.write(data + "\n"); out.flush(); out.close(); } catch (IOException e) { diff --git a/app/src/main/java/io/pslab/others/CustomTabService.java b/app/src/main/java/io/pslab/others/CustomTabService.java index dc02a62a6..bc1e52a11 100644 --- a/app/src/main/java/io/pslab/others/CustomTabService.java +++ b/app/src/main/java/io/pslab/others/CustomTabService.java @@ -29,6 +29,12 @@ public CustomTabService (Activity currentActivity) { init(); } + public CustomTabService (Activity currentActivity, CustomTabsServiceConnection serviceConnection) { + this.activity = currentActivity; + this.mCustomTabsServiceConnection = serviceConnection; + init(); + } + private void init() { mCustomTabsServiceConnection = new CustomTabsServiceConnection() { @Override diff --git a/app/src/main/java/io/pslab/others/GPSLogger.java b/app/src/main/java/io/pslab/others/GPSLogger.java index 040c7b1dd..2f9495596 100644 --- a/app/src/main/java/io/pslab/others/GPSLogger.java +++ b/app/src/main/java/io/pslab/others/GPSLogger.java @@ -1,23 +1,20 @@ package io.pslab.others; -import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.pm.PackageManager; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.provider.Settings; -import android.support.v4.app.ActivityCompat; -import android.support.v4.content.ContextCompat; +import android.widget.Toast; import io.pslab.R; -import io.pslab.activity.LuxMeterActivity; +import io.pslab.models.PSLabSensor; /** * Created by Padmal on 6/29/18. @@ -25,30 +22,65 @@ public class GPSLogger { - public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99; + public static final int PSLAB_PERMISSION_FOR_MAPS = 102; private static final int UPDATE_INTERVAL_IN_MILLISECONDS = 400; private static final int MIN_DISTANCE_CHANGE_FOR_UPDATES = 1; private LocationManager locationManager; private Context context; private Location bestLocation; - private LuxMeterActivity callerActivity; + private PSLabSensor sensorActivity; + private PSLabPermission psLabPermission; + private String provider = LocationManager.GPS_PROVIDER; + public AlertDialog gpsAlert; - public GPSLogger(Context context) { - this.context = context; - } + private boolean locationReady = false; public GPSLogger(Context context, LocationManager locationManager) { this.context = context; this.locationManager = locationManager; - if (context instanceof LuxMeterActivity) { - callerActivity = (LuxMeterActivity) context; + psLabPermission = PSLabPermission.getInstance(); + if (context instanceof PSLabSensor) { + sensorActivity = (PSLabSensor) context; + buildUpGPSAlert(); } } + private void buildUpGPSAlert() { + gpsAlert = new AlertDialog.Builder(sensorActivity, R.style.AlertDialogStyle) + .setTitle(R.string.allow_gps) + .setMessage(R.string.allow_gps_info) + .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); + context.startActivity(intent); + sensorActivity.checkGPSOnResume = true; + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + @Override + 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); + } else { + sensorActivity.isRecording = true; + sensorActivity.invalidateOptionsMenu(); + CustomSnackBar.showSnackBar(sensorActivity.sensorParentView, + context.getResources().getString(R.string.data_recording_with_nogps), + null, null); + } + } + }) + .create(); + } + private LocationListener locationListener = new LocationListener() { @Override public void onLocationChanged(Location location) { bestLocation = location; + locationReady = true; } @Override @@ -59,19 +91,9 @@ public void onProviderEnabled(String s) { /**/} @Override public void onProviderDisabled(String s) { - callerActivity.recordData = false; - new AlertDialog.Builder(callerActivity, R.style.AlertDialogStyle) - .setTitle(R.string.allow_gps) - .setMessage(R.string.allow_gps_info) - .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); - context.startActivity(intent); - } - }) - .create() - .show(); + if (sensorActivity.isRecording && !gpsAlert.isShowing()) { + gpsAlert.show(); + } } }; @@ -79,56 +101,56 @@ public boolean isGPSEnabled() { return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); } - /** - * Requests constant updates of location - */ - @SuppressLint("MissingPermission") - private void getUpdate() { - String provider = LocationManager.GPS_PROVIDER; - locationManager.requestLocationUpdates(provider, UPDATE_INTERVAL_IN_MILLISECONDS, MIN_DISTANCE_CHANGE_FOR_UPDATES, - locationListener); - } - /** * Stop requesting updates */ public void removeUpdate() { + locationReady = false; locationManager.removeUpdates(locationListener); } - @SuppressLint("MissingPermission") - public Location whatsLocation() { - return locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); - } - /** * @return the best location fetched */ - public Location getBestLocation() { - return bestLocation; + @SuppressLint("MissingPermission") + public Location getDeviceLocation() { + if (bestLocation == null) { + if (psLabPermission.checkPermissions((Activity) context, PSLabPermission.MAP_PERMISSION)) { + locationManager.requestLocationUpdates(provider, + UPDATE_INTERVAL_IN_MILLISECONDS, MIN_DISTANCE_CHANGE_FOR_UPDATES, + locationListener); + if (locationReady) { + return locationManager.getLastKnownLocation(provider); + } else { + return dummyLocation(); + } + } else { + return dummyLocation(); + } + } else { + return bestLocation; + } } - /** - * Request for allow location permission - * if the permission is not given initially - */ - public void requestPermissionIfNotGiven() { - if (ContextCompat.checkSelfPermission(context, - Manifest.permission.ACCESS_FINE_LOCATION) - != PackageManager.PERMISSION_GRANTED) { - - ActivityCompat.requestPermissions((Activity) context, - new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, - MY_PERMISSIONS_REQUEST_LOCATION); - } + private Location dummyLocation() { + Location l = new Location(""); + l.setLatitude(0.0); + l.setLongitude(0.0); + return l; } /** - * First fetch last known location for faster results, - * then start listening for location updates + * Set location updates */ - public void startFetchingLocation() { - bestLocation = whatsLocation(); - getUpdate(); + @SuppressLint("MissingPermission") + public void startCaptureLocation() { + if (psLabPermission.checkPermissions((Activity) context, PSLabPermission.MAP_PERMISSION)) { + locationManager.requestLocationUpdates(provider, UPDATE_INTERVAL_IN_MILLISECONDS, MIN_DISTANCE_CHANGE_FOR_UPDATES, + locationListener); + } else { + Toast.makeText(context.getApplicationContext(), + context.getResources().getString(R.string.no_permission_for_maps), + Toast.LENGTH_LONG).show(); + } } } diff --git a/app/src/main/java/io/pslab/others/LocalDataLog.java b/app/src/main/java/io/pslab/others/LocalDataLog.java new file mode 100644 index 000000000..d8cd49aa8 --- /dev/null +++ b/app/src/main/java/io/pslab/others/LocalDataLog.java @@ -0,0 +1,121 @@ +package io.pslab.others; + +import io.pslab.interfaces.sensorloggers.LuxMeterRecordables; +import io.pslab.interfaces.sensorloggers.SensorRecordables; +import io.pslab.models.LuxData; +import io.pslab.models.SensorDataBlock; +import io.realm.Realm; +import io.realm.RealmResults; +import io.realm.Sort; + +/** + * Created by Padmal on 11/5/18. + */ + +public class LocalDataLog implements LuxMeterRecordables, SensorRecordables { + + private static LocalDataLog instance; + private final Realm realm; + + private LocalDataLog() { + realm = Realm.getDefaultInstance(); + } + + public static LocalDataLog with() { + if (instance == null) { + instance = new LocalDataLog(); + } + return instance; + } + + public static LocalDataLog getInstance() { + return instance; + } + + public Realm getRealm() { + return realm; + } + + public void refresh() { + realm.refresh(); + } + + /*********************************************************************************************** + * Generic Sensor Section + ***********************************************************************************************/ + @Override + public SensorDataBlock getSensorBlock(long block) { + return realm.where(SensorDataBlock.class).equalTo("block", block).findFirst(); + } + + @Override + public void clearAllSensorBlocks() { + realm.beginTransaction(); + realm.delete(SensorDataBlock.class); + realm.commitTransaction(); + } + + @Override + public void clearTypeOfSensorBlock(String type) { + realm.beginTransaction(); + RealmResults data = getTypeOfSensorBlocks(type); + data.deleteAllFromRealm(); + realm.commitTransaction(); + } + + @Override + public void clearSensorBlock(long block) { + realm.beginTransaction(); + SensorDataBlock dataBlock = getSensorBlock(block); + dataBlock.deleteFromRealm(); + realm.commitTransaction(); + } + + @Override + public RealmResults getAllSensorBlocks() { + return realm.where(SensorDataBlock.class) + .findAll().sort("block", Sort.DESCENDING); + } + + @Override + public RealmResults getTypeOfSensorBlocks(String type) { + return realm.where(SensorDataBlock.class) + .equalTo("sensorType", type) + .findAll().sort("block", Sort.DESCENDING); + } + + /*********************************************************************************************** + * Lux Sensor Section + ***********************************************************************************************/ + @Override + public LuxData getLuxData(long timestamp) { + return realm.where(LuxData.class).equalTo("time", timestamp).findFirst(); + } + + @Override + public void clearAllLuxRecords() { + realm.beginTransaction(); + realm.delete(LuxData.class); + realm.commitTransaction(); + } + + @Override + public void clearBlockOfLuxRecords(long block) { + realm.beginTransaction(); + RealmResults data = getBlockOfLuxRecords(block); + data.deleteAllFromRealm(); + realm.commitTransaction(); + } + + @Override + public RealmResults getAllLuxRecords() { + return realm.where(LuxData.class).findAll(); + } + + @Override + public RealmResults getBlockOfLuxRecords(long block) { + return realm.where(LuxData.class) + .equalTo("block", block) + .findAll(); + } +} diff --git a/app/src/main/java/io/pslab/others/PSLabPermission.java b/app/src/main/java/io/pslab/others/PSLabPermission.java new file mode 100644 index 000000000..597daa51c --- /dev/null +++ b/app/src/main/java/io/pslab/others/PSLabPermission.java @@ -0,0 +1,95 @@ +package io.pslab.others; + +import android.Manifest; +import android.app.Activity; +import android.content.pm.PackageManager; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Padmal on 11/3/18. + */ + +public class PSLabPermission { + + private String[] allPermissions = new String[] { + Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.RECORD_AUDIO, + Manifest.permission.ACCESS_FINE_LOCATION + }; + + private String[] csvPermissions = new String[] { + Manifest.permission.ACCESS_FINE_LOCATION + }; + + private String[] logPermissions = new String[] { + Manifest.permission.WRITE_EXTERNAL_STORAGE + }; + + private String[] mapPermissions = new String[] { + Manifest.permission.ACCESS_FINE_LOCATION + }; + + public static final int ALL_PERMISSION = 100; + public static final int LOG_PERMISSION = 101; + public static final int MAP_PERMISSION = 102; + public static final int GPS_PERMISSION = 103; + public static final int CSV_PERMISSION = 104; + + private static final PSLabPermission pslabPermission = new PSLabPermission(); + + public static PSLabPermission getInstance() { + return pslabPermission; + } + + private PSLabPermission() {/**/} + + public boolean checkPermissions(Activity activity, int mode) { + List listPermissionsNeeded = new ArrayList<>(); + if (mode == ALL_PERMISSION) { + for (String permission : allPermissions) { + if (ContextCompat.checkSelfPermission(activity, permission) + != PackageManager.PERMISSION_GRANTED) { + listPermissionsNeeded.add(permission); + } + } + } else if (mode == LOG_PERMISSION) { + for (String permission : logPermissions) { + if (ContextCompat.checkSelfPermission(activity, permission) + != PackageManager.PERMISSION_GRANTED) { + listPermissionsNeeded.add(permission); + } + } + } else if (mode == MAP_PERMISSION) { + for (String permission : mapPermissions) { + if (ContextCompat.checkSelfPermission(activity, permission) + != PackageManager.PERMISSION_GRANTED) { + listPermissionsNeeded.add(permission); + } + } + } else if (mode == GPS_PERMISSION) { + for (String permission : mapPermissions) { + if (ContextCompat.checkSelfPermission(activity, permission) + != PackageManager.PERMISSION_GRANTED) { + listPermissionsNeeded.add(permission); + } + } + } else if (mode == CSV_PERMISSION) { + for (String permission : csvPermissions) { + if (ContextCompat.checkSelfPermission(activity, permission) + != PackageManager.PERMISSION_GRANTED) { + listPermissionsNeeded.add(permission); + } + } + } + if (!listPermissionsNeeded.isEmpty()) { + ActivityCompat.requestPermissions(activity, listPermissionsNeeded.toArray( + new String[listPermissionsNeeded.size()]), mode); + return false; + } + return true; + } +} diff --git a/app/src/main/res/drawable/app_icon.png b/app/src/main/res/drawable/app_icon.png new file mode 100644 index 000000000..09da1420b Binary files /dev/null and b/app/src/main/res/drawable/app_icon.png differ diff --git a/app/src/main/res/drawable/app_icon_round.png b/app/src/main/res/drawable/app_icon_round.png new file mode 100644 index 000000000..87e92faff Binary files /dev/null and b/app/src/main/res/drawable/app_icon_round.png differ diff --git a/app/src/main/res/drawable/ic_map_red_24dp.xml b/app/src/main/res/drawable/ic_map_red_24dp.xml new file mode 100644 index 000000000..07885fb63 --- /dev/null +++ b/app/src/main/res/drawable/ic_map_red_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/logo.png b/app/src/main/res/drawable/logo.png index ac5023806..546d8afd0 100644 Binary files a/app/src/main/res/drawable/logo.png and b/app/src/main/res/drawable/logo.png differ diff --git a/app/src/main/res/drawable/logo200x200.png b/app/src/main/res/drawable/logo200x200.png index 1a9124345..effdfbab9 100644 Binary files a/app/src/main/res/drawable/logo200x200.png and b/app/src/main/res/drawable/logo200x200.png differ diff --git a/app/src/main/res/drawable/logo_200.png b/app/src/main/res/drawable/logo_200.png new file mode 100644 index 000000000..1883fe23c Binary files /dev/null and b/app/src/main/res/drawable/logo_200.png differ diff --git a/app/src/main/res/layout/activity_barometer.xml b/app/src/main/res/layout/activity_barometer.xml index 4475ee0b6..41dab3b00 100644 --- a/app/src/main/res/layout/activity_barometer.xml +++ b/app/src/main/res/layout/activity_barometer.xml @@ -244,7 +244,7 @@ android:layout_marginRight="@dimen/card_margin" android:layout_weight="@dimen/weight_1" android:gravity="center" - android:text="@string/lux_max" + android:text="@string/max_lx" android:textColor="@color/black" android:textSize="@dimen/text_size" /> @@ -256,7 +256,7 @@ android:layout_marginRight="@dimen/card_margin" android:layout_weight="@dimen/weight_1" android:gravity="center" - android:text="@string/lux_min" + android:text="@string/min_lx" android:textColor="@color/black" android:textSize="@dimen/text_size" /> @@ -268,7 +268,7 @@ android:layout_marginRight="@dimen/card_margin" android:layout_weight="@dimen/weight_1" android:gravity="center" - android:text="@string/lux_avg" + android:text="@string/avg_lx" android:textColor="@color/black" android:textSize="@dimen/text_size" /> diff --git a/app/src/main/res/layout/activity_data_logger.xml b/app/src/main/res/layout/activity_data_logger.xml index 56d0232bc..f8f23d2a2 100644 --- a/app/src/main/res/layout/activity_data_logger.xml +++ b/app/src/main/res/layout/activity_data_logger.xml @@ -1,10 +1,11 @@ + - + android:layout_height="wrap_content" + android:layout_below="@id/top_app_bar_layout" /> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_generic_sensor.xml b/app/src/main/res/layout/activity_generic_sensor.xml new file mode 100644 index 000000000..c56465c02 --- /dev/null +++ b/app/src/main/res/layout/activity_generic_sensor.xml @@ -0,0 +1,18 @@ + + + + + + + + + + \ 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 7bace0c73..e43bea6f9 100644 --- a/app/src/main/res/layout/fragment_lux_meter_data.xml +++ b/app/src/main/res/layout/fragment_lux_meter_data.xml @@ -2,215 +2,123 @@ + android:layout_height="match_parent"> - + android:layout_height="match_parent" + android:layout_margin="@dimen/card_margin"> + android:layout_height="match_parent" + android:baselineAligned="false"> - + android:layout_weight="3" + android:gravity="center_horizontal|center_vertical" + android:orientation="vertical"> - + - + - + - + - + - + - + - - + + + + - + - + + android:layout_margin="@dimen/card_margin"> + android:layout_height="match_parent" + android:layout_weight="4"> + style="@style/graph_x_axis_title_block"> - - + style="@style/graph_y_axis_title_block"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/generic_sensor_layout.xml b/app/src/main/res/layout/generic_sensor_layout.xml new file mode 100644 index 000000000..c69724315 --- /dev/null +++ b/app/src/main/res/layout/generic_sensor_layout.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/logger_data_item.xml b/app/src/main/res/layout/logger_data_item.xml index 78d502edd..617a0ba2d 100644 --- a/app/src/main/res/layout/logger_data_item.xml +++ b/app/src/main/res/layout/logger_data_item.xml @@ -17,7 +17,7 @@ android:layout_width="@dimen/length_0dp" android:layout_height="match_parent" android:layout_gravity="center_vertical" - android:layout_weight="0.2" + android:layout_weight="0.1" android:src="@drawable/tile_icon_lux_meter" android:tint="@color/colorPrimary" /> @@ -25,10 +25,10 @@ android:layout_width="@dimen/length_0dp" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/content_left_margin" + android:layout_marginStart="@dimen/content_left_margin" android:layout_weight="0.6" android:gravity="center_vertical" - android:orientation="vertical" - android:layout_marginStart="@dimen/content_left_margin"> + android:orientation="vertical"> + + + android:src="@drawable/ic_delete_red_24dp" /> + + \ 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/lux_data_log_menu.xml index bebfeefc3..085e6e06f 100644 --- a/app/src/main/res/menu/lux_data_log_menu.xml +++ b/app/src/main/res/menu/lux_data_log_menu.xml @@ -5,7 +5,7 @@ android:id="@+id/record_data" android:icon="@drawable/ic_record_white" android:title="@string/record_csv_data" - app:showAsAction="always" /> + app:showAsAction="ifRoom" /> - + app:showAsAction="never" />--> + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index c8a31c378..717caa8f6 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -311,7 +311,7 @@ 66dp 200dp 10dp - 40dp + 10dp 18sp 10dp 46dp @@ -357,6 +357,9 @@ 8dp 20dp 200dp + 16sp + 8sp + 16sp 5dp 18sp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 59ea5a672..ef55fdc55 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -322,7 +322,7 @@ Plot - Gyroscope (rad) Angle - Time + Time (sec) Timegap No. of samples @@ -466,6 +466,18 @@ PCS + + In-built Sensor + BH1750 + TSL2561 + + + + 0 + 1 + 2 + + Device Not Connected Use Autoscan button to find connected sensors to PSLab device No sensors connected via I2C. Try selecting a sensor from the below @@ -478,7 +490,8 @@ volts (s) (ms) - LUX + Lx + Intensity (Lx) Press. Plot - Altitude (°C) @@ -619,6 +632,12 @@ Share Data + Not sufficient permission to load map + Not sufficient permission to locate device + Not sufficient permission to log data + + 0.00 + TXT Format CSV Format @@ -912,13 +931,14 @@ High Limit Update Period Statistics - Min - Max - Avg + Max (Lx) + Min (Lx) + Avg (Lx) + Device does not have a Lux sensor Light Meter Select Sensor - - Built In + + Built-In BH1750 TSL2561 @@ -942,6 +962,14 @@ Record Data Pause Recording View Map + + Data recording started with location + Data recording started but GPS is off + Recorded data will not contain location + Data recording started without location + Data recording stopped + No location data in this log + Data Recording: Started Data Recording: Paused Recorded data deleted successfully @@ -1024,7 +1052,6 @@ Device Brand Device Android SDK - Logged Data Show Logged Data Time Elapsed @@ -1039,5 +1066,7 @@ \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 5195f5355..e48d6e4d5 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -34,6 +34,7 @@ @color/colorPrimaryDark @android:color/white + + + + + + + + + + + + + + diff --git a/app/src/main/res/xml/lux_meter_settings.xml b/app/src/main/res/xml/lux_meter_settings.xml index 827bc6a9f..ae0d5421e 100644 --- a/app/src/main/res/xml/lux_meter_settings.xml +++ b/app/src/main/res/xml/lux_meter_settings.xml @@ -1,24 +1,42 @@ - + - + - + + + + + \ No newline at end of file