Java tutorial
/* Copyright (c) 2013-2014 Agustn Prats * * This file is part of HeartWave. * * HeartWave is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeartWave is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeartWave. If not, see <http://www.gnu.org/licenses/>. */ package com.agustinprats.myhrv; import android.app.Activity; import android.app.AlertDialog; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothManager; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.os.IBinder; import android.preference.PreferenceManager; //import android.support.v4.app.FragmentTransaction; import android.util.Log; import android.view.Menu; import android.content.ServiceConnection; import android.content.ComponentName; import android.view.MenuInflater; import android.view.MenuItem; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentTransaction; import android.support.v4.app.NavUtils; import android.view.Window; import android.view.WindowManager; import com.agustinprats.myhrv.fragment.BasicMonitorFragment; import com.agustinprats.myhrv.fragment.CameraBasicMonitorFragment; import com.agustinprats.myhrv.fragment.MonitorFragment; import com.agustinprats.myhrv.model.RrInterval; import com.agustinprats.myhrv.model.RrIntervalList; import com.agustinprats.myhrv.service.BleHeartRateService; import com.agustinprats.myhrv.service.BleHeartRateServiceElad; import com.agustinprats.myhrv.service.CameraHeartRateService; import com.agustinprats.myhrv.service.HeartRateService; import com.agustinprats.myhrv.service.MockHeartRateService; import com.agustinprats.myhrv.service.SamsungS5HeartRateService; import com.agustinprats.myhrv.service.USBSPOHeartRateService; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; public class MainActivity extends FragmentActivity { private static final String TAG = MainActivity.class.getSimpleName(); /** Request code for requesting enabling bluetooth. */ private static final int REQUEST_ENABLE_BT = 1; /** SharedPreferences key that holds the selected theme. */ private static final String LIGHT_THEME_KEY = "light_theme_key"; /** Boolean storing if the activity is in the foreground. */ private boolean _inForeground = false; /** Service that connects in the background to a heart rate device and notifies its changes. */ private HeartRateService _heartRateService = null; /** Fragment that shows the values notified by the heart rate device. */ private MonitorFragment _monitorFragment = null; /** Manages the connection to the heart rate device service. */ private final ServiceConnection _heartRateServiceConn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder service) { // Init service _heartRateService = ((HeartRateService.LocalBinder) service).getService(); _heartRateService.setInForeground(MainActivity.this._inForeground); // Check if bluetooth is enabled boolean bleInit = _heartRateService.initialize(); if (!bleInit) { showUnableToInitBleDialog(); } // notify service is ready onHeartRateServiceBinded(_heartRateService); } @Override public void onServiceDisconnected(ComponentName componentName) { // notify service inbinded onHeartRateServiceUnbinded(_heartRateService); } }; /** Called when the service is binded to the activity */ public void onHeartRateServiceBinded(final HeartRateService service) { _monitorFragment.onHeartRateServiceBinded(service); } /** Called when the service is unbinded from the activity */ public void onHeartRateServiceUnbinded(final HeartRateService service) { _heartRateService = null; _monitorFragment.onHeartRateServiceUnbinded(service); } /** Shows unable to init BLE message and exit app. */ private void showUnableToInitBleDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setCancelable(false); builder.setMessage(R.string.unable_init_ble); builder.setPositiveButton(R.string.exit, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { finish(); } }); builder.create().show(); } /** Shows BLE is not supported and exit app. */ public void showBleRequireDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setCancelable(false); builder.setMessage(R.string.ble_required) .setNeutralButton(R.string.exit, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { finish(); } }).create().show(); } /** Ensures Bluetooth is enabled on the device. If Bluetooth is not currently enabled, * fire an intent to display a dialog asking the user to grant permission to enable it. */ public void requestEnableBt() { if (!isBluetoothEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } } /** Returns true if bluetooth is enabled. False otherwise. */ public boolean isBluetoothEnabled() { final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); return bluetoothManager.getAdapter().isEnabled(); } @Override public void onPause() { super.onPause(); _inForeground = false; if (_heartRateService != null) { _heartRateService.setInForeground(_inForeground); } } @Override public void onResume() { super.onResume(); _inForeground = true; if (_heartRateService != null) { _heartRateService.setInForeground(_inForeground); } // If the device doesn't support BLE show message and exit if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { showBleRequireDialog(); } } @Override public void onDestroy() { saveSessionDate(); saveRRIntervalList(); if (_heartRateServiceConn != null) { unbindService(_heartRateServiceConn); _heartRateService = null; } super.onDestroy(); } private void saveSessionDate() { String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); SharedPreferences coherenceHistorySharedPrefs = getApplicationContext() .getSharedPreferences("CoherenceHistoryData1", Context.MODE_PRIVATE); SharedPreferences sampleSizeHistorySharedPrefs = getApplicationContext() .getSharedPreferences("SampleSizeHistoryData1", Context.MODE_PRIVATE); // PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); int lastCoherenceAvgToday = coherenceHistorySharedPrefs.getInt(date, 0); int lastSampleSizeToday = sampleSizeHistorySharedPrefs.getInt(date, 0); if (_heartRateService != null) { int currentCoherenceAvg = (int) _heartRateService.getIntervals().getCoherence(); int currentSampleSize = _heartRateService.getIntervals().size(); if (currentSampleSize > 0) { int newCoherenceAvg = (lastCoherenceAvgToday * lastSampleSizeToday + currentCoherenceAvg * currentSampleSize) / (lastSampleSizeToday + currentSampleSize); int newSampleSize = lastSampleSizeToday + currentSampleSize; coherenceHistorySharedPrefs.edit().putInt(date, newCoherenceAvg).commit(); sampleSizeHistorySharedPrefs.edit().putInt(date, newSampleSize).commit(); } } } private void saveRRIntervalList() { RrIntervalList rrIntervalList = _heartRateService._intervals; if (rrIntervalList != null) if (rrIntervalList.size() > 0) { Date d = new Date(rrIntervalList.get(0).getTimestamp()); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); File file = new File(Environment.getExternalStorageDirectory() + File.separator + "HRVLog" + File.separator + sdf.format(d) + ".csv"); file.mkdirs(); try { if (!file.createNewFile()) { file.delete(); file.createNewFile(); } FileOutputStream fos = new FileOutputStream(file); OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8"); PrintWriter pw = new PrintWriter(osw); pw.println( "Time Stamp Calculated,RR-Interval,Heart Rate Calculated,Packet Num, Packet Size,Real Time Stamp,Time Diff ,Drooped, Repeated, Error Rate Time Diff"); int sizeInInterval = 1; int lastIntervalNum = 0; int lastIntervalSize = 0; int lastRrIntervalValue = 0; long startTimeStamp = 0; for (int i = 0; i < rrIntervalList.size(); i++) { RrInterval rrInterval = rrIntervalList.get(i); // Calendar c = new GregorianCalendar(); // This creates a Calendar instance with the current time long currentTimeStamp = rrInterval.getTimestamp(); d = new Date(currentTimeStamp); // c.setTime(d); //SimpleDateFormat simpleDateFormat; sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); // String string=c.get(Calendar.MINUTE)+":"+c.get(Calendar.SECOND)+":"+c.get(Calendar.MILLISECOND)+", "; String string = sdf.format(d) + ", "; int currentRrIntervalValue = rrInterval.getRRInterval(); string += currentRrIntervalValue + ", "; string += rrInterval.getHeartRate() + ", "; int currentIntervalNum = rrInterval.get_intervalNum(); string += currentIntervalNum + ","; int currentIntervalSize = rrInterval.get_intervalSize(); string += currentIntervalSize + ","; long realTimeStamp = rrInterval.get_realTimeStamp(); if (startTimeStamp == 0) startTimeStamp = realTimeStamp; string += sdf.format(realTimeStamp) + ","; long timeDiff = Math.abs(realTimeStamp - currentTimeStamp); string += sdf.format(timeDiff) + ","; //dropped string += ","; //repeated if (currentRrIntervalValue == lastRrIntervalValue) string += "true,"; else { string += ","; lastRrIntervalValue = currentRrIntervalValue; } //error Rate long timeFromStart = Math.abs(realTimeStamp - startTimeStamp); if ((timeFromStart > 0) && (i == rrIntervalList.size() - 1)) { double errorPercentage = ((double) timeDiff / (double) timeFromStart) * 100; string += errorPercentage; } //string+=rrInterval._heartRateFromDevice+", "; //string+=rrInterval._intervalDiscard+", "; //string+=rrInterval._empty; if (currentIntervalNum == lastIntervalNum) sizeInInterval++; else { if (currentIntervalNum > lastIntervalNum + 1) { for (; currentIntervalNum > lastIntervalNum + 1; lastIntervalNum++) { pw.println("," + "," + "," + (lastIntervalNum + 1) + "," + 1 + "," + "," + ",true"); } } if (sizeInInterval < lastIntervalSize) { for (int j = sizeInInterval; j < lastIntervalSize; j++) { pw.println("," + "," + "," + lastIntervalNum + "," + lastIntervalSize + "," + "," + ",true"); } } lastIntervalNum = currentIntervalNum; lastIntervalSize = currentIntervalSize; sizeInInterval = 1; } pw.println(string); } pw.flush(); pw.close(); } catch (IOException e) { e.printStackTrace(); } // Send the file via email sendFileByEmail(file); } } protected void sendFileByEmail(File file) { Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_EMAIL, new String[] { "eladfein@gmail.com" }); intent.putExtra(Intent.EXTRA_SUBJECT, "Testing result of HRV bluetooth monitor"); intent.putExtra(Intent.EXTRA_TEXT, "see files attached"); Uri uri = Uri.fromFile(file); intent.putExtra(Intent.EXTRA_STREAM, uri); startActivity(Intent.createChooser(intent, "Send email...")); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // User chose not to enable Bluetooth. if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) { Log.d(TAG, "User declined to enable BT: closing app"); finish(); } else if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_OK) { Log.d(TAG, "Bluetooth enabled"); _heartRateService.reconnect(); } super.onActivityResult(requestCode, resultCode, data); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); //Remove title bar this.requestWindowFeature(Window.FEATURE_NO_TITLE); //Remove notification bar this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); //set content view AFTER ABOVE sequence (to avoid crash) this.setContentView(R.layout.fragment_basic_monitor_video); final Uri uri = getIntent().getData(); // set previously saved theme // setTheme(isLightTheme() ? R.style.LightTheme : R.style.DarkTheme); // elad change set theme to dark setTheme(R.style.LightTheme); // setContentView(R.layout.activity_main); // Elad different services // Connect to Bluetooth service //Intent serviceIntent = new Intent(this, BleHeartRateService.class); //Intent serviceIntent = new Intent(this, BleHeartRateServiceElad.class); Intent serviceIntent = new Intent(this, SamsungS5HeartRateService.class); //Intent serviceIntent = new Intent(this, CameraHeartRateService.class); //Intent serviceIntent = new Intent(this, MockHeartRateService.class); //Intent serviceIntent = new Intent(this, USBSPOHeartRateService.class); bindService(serviceIntent, _heartRateServiceConn, BIND_AUTO_CREATE); Log.d(TAG, "binding with BleHeartRateService service"); // Init monitor fragment if (savedInstanceState == null) { final FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); // Adds a newly created ContactDetailFragment that is instantiated with the // data Uri // Elad Camera _monitorFragment = BasicMonitorFragment.newInstance(uri); ft.add(android.R.id.content, _monitorFragment, TAG); ft.commit(); /* getFragmentManager().beginTransaction() .add(R.id.container, _monitorFragment) .commit(); */ } } @Override public boolean onCreateOptionsMenu(Menu menu) { //Elad change to take out menu /* MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main, menu); boolean lightTheme = isLightTheme(); menu.findItem(R.id.menu_dark_theme).setVisible(lightTheme); menu.findItem(R.id.menu_light_theme).setVisible(!lightTheme); */ return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action buttons if (item.getItemId() == R.id.menu_light_theme) { setLightTheme(true); return true; } if (item.getItemId() == R.id.menu_dark_theme) { setLightTheme(false); return true; } return super.onOptionsItemSelected(item); } /** Returns the heart rate service. */ public HeartRateService getHeartRateService() { return _heartRateService; } /** Changes the theme to light if passed a true value or to dark theme if passed a false value. */ private void setLightTheme(boolean lightTheme) { // Save to preferences SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); sharedPrefs.edit().putBoolean(LIGHT_THEME_KEY, lightTheme).commit(); // Restart activity Intent intent = getIntent(); finish(); startActivity(intent); } /** Returns true if light theme was previously selected. False otherwise. */ public boolean isLightTheme() { SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); return sharedPrefs.getBoolean(LIGHT_THEME_KEY, true); } }