com.agustinprats.myhrv.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.agustinprats.myhrv.MainActivity.java

Source

/* 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);
    }
}