it.flaviomascetti.posture.PostureCheckFragment.java Source code

Java tutorial

Introduction

Here is the source code for it.flaviomascetti.posture.PostureCheckFragment.java

Source

package it.flaviomascetti.posture;

/*
*    Copyright 2015 - 2016 Flavio Mascetti
*
*    This file is part of Posture.
*
*    Posture 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.
*
*    Posture 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 Posture.  If not, see <http://www.gnu.org/licenses/>
*/

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Vibrator;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Calendar;

public class PostureCheckFragment extends Fragment implements SensorEventListener {

    static final int MY_PERMISSION_REQUEST_SDCARD_WRITE = 01;

    private SensorManager sensorManager;
    private Sensor accelerometer;

    private final int windowLength = 100;
    private final int ordinateNumber = 3;

    private boolean testInProgress = false; // says if the test has begun
    private boolean beginFiltering = false; // says if the filtering has begun

    private double actualCoP[] = new double[ordinateNumber]; // contains the actual accelerometer values
    private double filterActualCoP[];
    private double previousCoP[]; // contains the previous accelerometer values
    private double filterPreviousCoP[];
    private double lengthCoPPath; // length of Center of Pressure path
    private double dCoP; // distance from actual CoP to previous CoP
    private double filterWindow[][]; // array used in the filter section of the
    private int chestHeight; // chest height variable
    // accelerometer
    private int filterCounter; // counter used by the filter

    private File file;
    private File folder;

    private BufferedWriter bW;

    private Button button;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.posture_check_fragment, viewGroup, false);
    }

    public void onResume() {
        super.onResume();

        // create the programs directory if it doesn't exist
        folder = new File(Environment.getExternalStorageDirectory(), getString(R.string.app_name));
        if (folder.mkdirs()) {
            Log.e(getString(R.string.app_name), getString(R.string.error_directory));
        }
    }

    @Override
    public void onStart() {
        super.onStart();

        button = (Button) getActivity().findViewById(R.id.button_posture_check);

        if (ContextCompat.checkSelfPermission(getActivity(),
                Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
            Log.e(getString(R.string.app_name), getString(R.string.error_write_permission));

            ActivityCompat.requestPermissions(getActivity(),
                    new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE },
                    MY_PERMISSION_REQUEST_SDCARD_WRITE);
        } else // if the permission is granted the button has to be enabled
            button.setEnabled(true);

        button.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                // Close the keyboard
                InputMethodManager inputManager = (InputMethodManager) getActivity()
                        .getSystemService(Context.INPUT_METHOD_SERVICE);

                inputManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(),
                        InputMethodManager.HIDE_NOT_ALWAYS);

                // Retrieve the chest height from the editText
                EditText et = (EditText) getActivity().findViewById(R.id.edit_text_height);
                Integer height = Integer.parseInt(et.getText().toString());

                if (height >= 1000 && height <= 2000) {
                    chestHeight = height;

                    et.setEnabled(false);

                    // Check SdCard write permission
                    Calendar c = Calendar.getInstance();
                    String name = String.valueOf(c.get(Calendar.YEAR)) + "-"
                            + String.valueOf(c.get(Calendar.MONTH) + 1) + "-"
                            + String.valueOf(c.get(Calendar.DAY_OF_MONTH)) + "-"
                            + String.valueOf(c.get(Calendar.HOUR)) + "-" + String.valueOf(c.get(Calendar.MINUTE))
                            + "-" + String.valueOf(c.get(Calendar.SECOND));

                    // Create the results file
                    file = createFile(folder, name + ".csv");

                    // Showing the start snackbar
                    Snackbar.make(getActivity().findViewById(R.id.fragment_posture_test), R.string.snack_begin_test,
                            Snackbar.LENGTH_LONG).show();

                    // Opening the output stream on the file
                    try {
                        bW = new BufferedWriter(new FileWriter(file, true));
                        bW.write("x\t" + //
                        "y\t" + // Acceleration force
                        "z\t" + //
                        "x (mm)\t" + // Conversion of acceleration
                        "z (mm)\t" + // force to mm
                        "dCoP\t" + // Euclidean distance from actualCoP to previous CoP
                        "lengthCoPPath"); // Summation of euclidean dist
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                    testInProgress = false;

                    // Delayed start of function testStart
                    Handler handler = new Handler();
                    handler.postDelayed(testStart, 7000); // 7000 ms = 7 sec*

                    // Make the Begin Button unclickable
                    button.setEnabled(false);
                } else {
                    // Showing the error snackbar
                    Snackbar.make(getActivity().findViewById(R.id.fragment_posture_test),
                            R.string.snack_error_height, Snackbar.LENGTH_LONG).show();
                }

            }
        });
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
        case MY_PERMISSION_REQUEST_SDCARD_WRITE: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                button.setEnabled(true);

            } else {
                button.setEnabled(false);
            }
            return;
        }

        }
    }

    private Runnable testStart = new Runnable() {
        @Override
        public void run() {
            button.setText(getString(R.string.during_posture_check));

            // Two beep to notify the start
            ToneGenerator sound = new ToneGenerator(AudioManager.STREAM_MUSIC, 85);
            sound.startTone(ToneGenerator.TONE_PROP_BEEP2, 400);

            // Keep the screen on
            getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

            // Beginning accelerometer tracking
            sensorManager.registerListener(PostureCheckFragment.this, accelerometer,
                    SensorManager.SENSOR_DELAY_FASTEST);

            // Delayed start of function completeTest
            Handler handler = new Handler();
            handler.postDelayed(completeTest, 60000);
        }
    };

    private Runnable completeTest = new Runnable() {
        @Override
        public void run() {
            // Stopping accelerometer tracking
            sensorManager.unregisterListener(PostureCheckFragment.this);

            // One beep to notify the stop
            ToneGenerator sound = new ToneGenerator(AudioManager.STREAM_MUSIC, 85);
            sound.startTone(ToneGenerator.TONE_PROP_BEEP, 100);

            Vibrator vibrator = (Vibrator) getActivity().getSystemService(Context.VIBRATOR_SERVICE);
            vibrator.vibrate(700);

            // Stopping screen on keeping
            getActivity().getWindow().clearFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

            testInProgress = false;
            beginFiltering = false;

            button.setText(getString(R.string.begin_posture_check));
            button.setEnabled(true);
            getActivity().findViewById(R.id.edit_text_height).setEnabled(true);

            // Stopping the output stream on the file
            try {
                bW.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            // Showing lengthCoPPath on the fragment textBox
            TextView txt = (TextView) getActivity().findViewById(R.id.text_view_posture);

            txt.setText(getString(R.string.distance) + ": " + Double.toString(lengthCoPPath));
            if (txt.getVisibility() != TextView.VISIBLE)
                txt.setVisibility(TextView.VISIBLE);
        }
    };

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (testInProgress) {
            // Obtaining accelerations
            for (int i = 0; i < ordinateNumber; i++)
                actualCoP[i] = event.values[i];

            // Writing them on file
            try {
                bW.newLine();
                bW.write(String.valueOf(actualCoP[0]) + "\t" + String.valueOf(actualCoP[1]) + "\t"
                        + String.valueOf(actualCoP[2]) + "\t" + String.valueOf(mmConversion(actualCoP[0])) + "\t"
                        + String.valueOf(mmConversion(actualCoP[2])));
            } catch (IOException e) {
                e.printStackTrace();
            }

            for (int i = 0; i < ordinateNumber; i++)
                filterWindow[i][filterCounter] = actualCoP[i];

            if (beginFiltering) {
                for (int i = 0; i < ordinateNumber; i++) {
                    for (int j = 0; j < windowLength; j++)
                        filterActualCoP[i] += filterWindow[i][j];
                    filterActualCoP[i] /= windowLength;
                }

                dCoP = euclideanDistance(mmConversion(filterPreviousCoP[0]), mmConversion(filterPreviousCoP[2]),
                        mmConversion(filterActualCoP[0]), mmConversion(filterActualCoP[2]));
                lengthCoPPath += dCoP;

                try {
                    bW.write("\t" + dCoP + "\t" + lengthCoPPath + "\n");
                } catch (IOException e) {
                    e.printStackTrace();
                }

                System.arraycopy(filterActualCoP, 0, filterPreviousCoP, 0, ordinateNumber);
            } else {
                if (filterCounter == (windowLength - 1)) {
                    beginFiltering = true;
                    for (int i = 0; i < ordinateNumber; i++) {
                        for (int j = 0; j < windowLength; j++)
                            filterPreviousCoP[i] += filterWindow[i][j];
                        filterPreviousCoP[i] /= windowLength;
                    }
                }
            }
            filterCounter++;
            if (filterCounter == windowLength)
                filterCounter = 0;

            System.arraycopy(actualCoP, 0, previousCoP, 0, ordinateNumber);
        } else {
            testInProgress = true;
            lengthCoPPath = 0;
            previousCoP = new double[] { 0, 0, 0 };
            dCoP = 0;
            actualCoP = new double[] { 0, 0, 0 };
            filterCounter = 0;
            filterActualCoP = new double[] { 0, 0, 0 };
            filterPreviousCoP = new double[] { 0, 0, 0 };
            filterWindow = new double[ordinateNumber][windowLength];
        }
    }

    private double mmConversion(double value) {
        return ((chestHeight / 9.8) * value);
    }

    private double euclideanDistance(double a1, double a2, double b1, double b2) {
        return (Math.sqrt(Math.pow(b1 - a1, 2.0) + Math.pow(b2 - a2, 2.0)));
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        sensorManager = (SensorManager) getActivity().getSystemService(Context.SENSOR_SERVICE);
        accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    }

    public void onPause() {
        super.onPause();
        // sensorManager.unregisterListener(this);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int i) {
    }

    private File createFile(File path, String name) {
        File f = new File(path, name);
        try {
            if (!f.createNewFile()) {
                // Showing the start snackbar
                Snackbar.make(getActivity().findViewById(R.id.fragment_posture_test), R.string.error_file_creation,
                        Snackbar.LENGTH_LONG).show();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        return f;
    }
}