/*
* Copyright (C) 2014 TU Darmstadt, Hessen, Germany.
* Department of Computer Science Databases and Distributed Systems
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
*/
package de.tudarmstadt.dvs.myhealthassistant.myhealthhub.services;
import java.util.LinkedList;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.sensorreadings.SensorReadingEvent;
import de.tudarmstadt.dvs.myhealthassistant.myhealthhub.events.sensorreadings.cardiovascular.HeartRateEvent;
/**
* @author Chris
*
*/
public class EventComposer extends Service {
private final static int minPulseValue = 55;
private final static int maxPulseValue = 180;
private final int[] pulseRangesIdle = {55, 160};
private final int[] pulseRangesRunning = {130, 175};
private final int[] pulseRangesCycling = {80, 160};
private final int[] pulseRangesWalking = {55, 160};
/** For LogCat. */
private static final String TAG = "EventComposer";
private static boolean D = false;
private final IBinder mEventComposerBinder = new EventComposerBinder();
private Handler mCallbackHandler;
private Handler mDBCallbackHandler;
private int heartbeatEventCounter;
private HeartbeatMonitor heartbeatMonitor;
private static int BUFFERSIZE_HEARTBEAT_MONITOR = 30;
// workout monitoring
private boolean isMonitoringGymWorkout;
public EventComposer() {
heartbeatMonitor = new HeartbeatMonitor(BUFFERSIZE_HEARTBEAT_MONITOR);
}
public class EventComposerBinder extends Binder {
private static final String TAG = "MessageHandler.LocalSensorHandlerBinder";
public void setActivityCallbackHandler(final Handler callback) {
mCallbackHandler = callback;
}
public void setDBCallbackHandler(final Handler callback) {
mDBCallbackHandler = callback;
}
public void incomingEvent(SensorReadingEvent event) {
processIncomingEvent(event);
}
}
@Override
public IBinder onBind(Intent arg0) {
Log.d(TAG, "onCreate(): entered...");
heartbeatEventCounter = 0;
isMonitoringGymWorkout = false;
//TODO
return mEventComposerBinder;
}
private class HeartbeatMonitor {
private LinkedList<Integer> heartbeats;
private int bufferSize;
public HeartbeatMonitor(int bufferSize) {
heartbeats = new LinkedList<Integer>();
this.bufferSize = bufferSize;
}
public void add(HeartRateEvent evt) {
heartbeats.add(evt.value);
if(heartbeats.size()>bufferSize) {
heartbeats.removeFirst();
}
}
public float getAvgValue(int numberOfRegardedReadings) {
if(numberOfRegardedReadings>heartbeats.size())
numberOfRegardedReadings = heartbeats.size();
float sum = 0;
for(int i = heartbeats.size()-numberOfRegardedReadings;
i<heartbeats.size(); i++) {
sum += heartbeats.get(i);
}
if(heartbeats.size()!=0) {
return (sum/numberOfRegardedReadings);
} else {
return 0;
}
}
public boolean hasJumpsOf(int numberOfBeats, int numberOfRegardedReadings) {
if(numberOfRegardedReadings>heartbeats.size())
numberOfRegardedReadings = heartbeats.size();
int offset = heartbeats.size()-numberOfRegardedReadings;
int prevValue = heartbeats.get(offset);
for(int i = offset+1; i<heartbeats.size(); i++) {
if(Math.abs(prevValue-heartbeats.get(i)
)>=numberOfBeats) return true;
prevValue = heartbeats.get(i);
}
return false;
}
public boolean hasMinDifferenceOf(int heartbeatDifference, int numberOfRegardedReadings) {
if(numberOfRegardedReadings>heartbeats.size())
numberOfRegardedReadings = heartbeats.size();
int offset = heartbeats.size()-numberOfRegardedReadings;
int prevValue = heartbeats.get(offset);
int diff = 0;
for(int i = offset+1; i<heartbeats.size(); i++) {
diff += Math.abs(prevValue-heartbeats.get(i));
prevValue = heartbeats.get(i);
}
if(diff >= heartbeatDifference) {
return true;
} else {
return false;
}
}
}
private int severity = 0;
private void processIncomingEvent(SensorReadingEvent event){
if(D)Log.d(TAG, "Incoming Event of type: "+event.getEventType());
if(event instanceof HeartRateEvent) {
HeartRateEvent myEvent = (HeartRateEvent)event;
heartbeatMonitor.add(myEvent);
/* Heart rate check every fifth reading (second) */
heartbeatEventCounter++;
if(heartbeatEventCounter != 5) return;
heartbeatEventCounter = 0;
/* Check whether heart rate is in healthy range */
if(heartbeatMonitor.getAvgValue(5)<minPulseValue) {
sendSensorAdjustMessage("Pulse too low");
severity++;
} else if(heartbeatMonitor.getAvgValue(5)>maxPulseValue) {
sendSensorAdjustMessage("Pulse too high");
severity++;
/* Check for jumps, peaks */
} else if(heartbeatMonitor.hasJumpsOf(40, 5)) {
sendSensorAdjustMessage("High jumps");
} else if(!heartbeatMonitor.hasMinDifferenceOf(1,30)) {
sendSensorAdjustMessage("Difference too low");
} else {
severity = 0;
}
/* Send alarm */
//TODO include severity
if(severity == 2) sendPulseAlarm(myEvent);
// Check whether pulsevalue is within the general range
/*if (myEvent.value < minPulseValue ||
myEvent.value > maxPulseValue) {
sendPulseAlarm(myEvent);
return;
}*/
/* sensys
*if(mDBMSBinder.isBinderAlive()) {
Cursor mCursor = mDBMSBinder.showRecentActivies(30);
mCursor.moveToFirst();
int count = mCursor.getInt(mCursor.getColumnIndex("count"));
if(count >= 20) {
String ACTIVITY = mCursor.getString(mCursor.getColumnIndex("ACTIVITY"));
if(ACTIVITY.equals("standing") || ACTIVITY.equals("sitting")) {
if(!isPulseInRange(myEvent.value, pulseRangesIdle))
sendPulseAlarm(myEvent);
} else if (ACTIVITY.equals("running")) {
if(!isPulseInRange(myEvent.value, pulseRangesRunning))
sendPulseAlarm(myEvent);
} else if (ACTIVITY.equals("walking")) {
if(!isPulseInRange(myEvent.value, pulseRangesWalking))
sendPulseAlarm(myEvent);
} else if (ACTIVITY.equals("cycling")) {
if(!isPulseInRange(myEvent.value, pulseRangesCycling))
sendPulseAlarm(myEvent);
} else {
sendPulseAlarm(myEvent);
}
} else {
Log.i(TAG, "Too different homecareActivities.");
int i = 1;
while (mCursor.isAfterLast() == false) {
Log.i(TAG, i+". Activity: "+mCursor.getString(mCursor.getColumnIndex("ACTIVITY"))
+"with count of "+mCursor.getInt(mCursor.getColumnIndex("count")));
i++;
mCursor.moveToNext();
}
}
mCursor.close();
} else {
if(D)Log.d(TAG, "Incoming heartbeat: DBMS was started again");
start_DB();
}*/
}
}
private void sendSensorAdjustMessage(String text) {
/*String alarmText = "Please check sensor: "+text;
HeartbeatAlarmEvent testAlarm =
new HeartbeatAlarmEvent(alarmText, Calendar.getInstance().getTime());
mCallbackHandler.obtainMessage(MessageHandler.ALARM_EVENT,
testAlarm).sendToTarget();
if(D)Log.d(TAG, testAlarm.getText());
ringAlarm();*/
}
private boolean isPulseInRange(int pulsevalue, int[] ranges) {
return (pulsevalue >= ranges[0] && pulsevalue <= ranges[1]);
}
private void sendPulseAlarm(HeartRateEvent event) {
/*String alarmText = "Dangerous heartrate of "+event.value+
" beats per minute!";
HeartbeatAlarmEvent testAlarm =
new HeartbeatAlarmEvent(alarmText, Calendar.getInstance().getTime());
mCallbackHandler.obtainMessage(MessageHandler.ALARM_EVENT,
testAlarm).sendToTarget();
if(D)Log.d(TAG, alarmText);
ringAlarm();*/
}
private void ringAlarm() {
//Context context = getApplicationContext();
NotificationManager notificationManager =
(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification();
notification.vibrate = new long[] {100, 250}; // (6)
notification.sound = Uri.parse("file:///system/media/audio/alarms/Alarm_Buzzer.ogg");
//notification.sound = Notification.DEFAULT_SOUND;
notificationManager.notify(123456789, notification);
}
}