diff --git a/app/src/main/java/uk/org/openseizuredetector/LocationFinder.java b/app/src/main/java/uk/org/openseizuredetector/LocationFinder.java
index c783daf..ed14bbf 100644
--- a/app/src/main/java/uk/org/openseizuredetector/LocationFinder.java
+++ b/app/src/main/java/uk/org/openseizuredetector/LocationFinder.java
@@ -31,7 +31,7 @@ public class LocationFinder implements LocationListener {
Timer mTimeoutTimer = null;
LocationManager mLocationManager = null;
LocationListener mLocationListener;
- int mTimeoutPeriod = 60; // Location search timeout period in seconds.
+ int mTimeoutPeriod = 7; // Location search timeout period in seconds.
String TAG = "LocationFinder";
diff --git a/app/src/main/java/uk/org/openseizuredetector/SdDataSource.java b/app/src/main/java/uk/org/openseizuredetector/SdDataSource.java
index b32f1bd..12b86bb 100644
--- a/app/src/main/java/uk/org/openseizuredetector/SdDataSource.java
+++ b/app/src/main/java/uk/org/openseizuredetector/SdDataSource.java
@@ -116,6 +116,9 @@ public abstract class SdDataSource {
private Time mHrStatusTime;
private double mHrFrozenPeriod = 60; // seconds
private boolean mHrFrozenAlarm;
+ private boolean mRequireHrForSeizureAlarm = false;
+ private int mHrConfirmationWindowSecs = 0;
+ private long mLastHrAlarmMillis = 0;
private boolean mFidgetDetectorEnabled;
private double mFidgetPeriod;
private double mFidgetThreshold;
@@ -734,9 +737,22 @@ public abstract class SdDataSource {
// set the alarmState to Alarm, Warning or OK, depending on the current state and previous ones.
if (inAlarm) {
mAlarmCount += mSamplePeriod;
+
if (mAlarmCount > mAlarmTime) {
- // full alarm
- mSdData.alarmState = 2;
+ if (mRequireHrForSeizureAlarm) {
+ if (hasRecentHrConfirmation()) {
+ mSdData.alarmState = 2;
+ mSdData.alarmCause = mSdData.alarmCause + "HR_CONFIRM ";
+ } else {
+ // Motion algorithm reached alarm, but HR has not confirmed it.
+ // Keep warning state rather than raising seizure alarm.
+ mSdData.alarmState = 1;
+ mSdData.alarmCause = mSdData.alarmCause + "NO_HR_CONFIRM ";
+ }
+ } else {
+ // Existing behavior
+ mSdData.alarmState = 2;
+ }
} else if (mAlarmCount > mWarnTime) {
// warning
mSdData.alarmState = 1;
@@ -761,7 +777,24 @@ public abstract class SdDataSource {
+ " mAlarmTime=" + mAlarmTime);
}
+ private boolean isHrAlarmStanding() {
+ return mSdData.mHRAlarmStanding
+ || mSdData.mAdaptiveHrAlarmStanding
+ || mSdData.mAverageHrAlarmStanding;
+ }
+ private boolean hasRecentHrConfirmation() {
+ if (mHrConfirmationWindowSecs <= 0) {
+ return isHrAlarmStanding();
+ }
+
+ if (mLastHrAlarmMillis <= 0) {
+ return false;
+ }
+
+ long ageMillis = System.currentTimeMillis() - mLastHrAlarmMillis;
+ return ageMillis <= (mHrConfirmationWindowSecs * 1000L);
+ }
public void muteCheck() {
if (mMute != 0) {
Log.v(TAG, "Mute Active - setting alarms to mute");
@@ -816,9 +849,14 @@ public abstract class SdDataSource {
mSdData.mAverageHrAlarmStanding = checkResults.get(2);
if (mSdData.mAverageHrAlarmStanding)
mSdData.alarmCause = mSdData.alarmCause + "HR_AVG ";
- // Show an ALARM state if any of the HR alarms is standing.
- if (mSdData.mHRAlarmStanding | mSdData.mAdaptiveHrAlarmStanding | mSdData.mAverageHrAlarmStanding) {
- mSdData.alarmState = 2;
+ // Record HR alarm timing. In HR-confirmation mode, HR is used to confirm
+ // a motion/OSD seizure alarm rather than independently raising seizure alarm.
+ if (isHrAlarmStanding()) {
+ mLastHrAlarmMillis = System.currentTimeMillis();
+
+ if (!mRequireHrForSeizureAlarm) {
+ mSdData.alarmState = 2;
+ }
}
}
} else {
@@ -1320,6 +1358,17 @@ public abstract class SdDataSource {
Log.d(TAG, "updatePrefs(): mAverageHrAlarmThreshMin=" + mSdData.mAverageHrAlarmThreshMin);
Log.d(TAG, "updatePrefs(): mAverageHrAlarmThreshMax=" + mSdData.mAverageHrAlarmThreshMax);
+ mRequireHrForSeizureAlarm = SP.getBoolean("RequireHrForSeizureAlarm", false);
+
+ try {
+ String hrConfirmWindowStr = SP.getString("HrConfirmationWindowSecs", "0");
+ mHrConfirmationWindowSecs = Integer.parseInt(hrConfirmWindowStr);
+ } catch (Exception ex) {
+ mHrConfirmationWindowSecs = 0;
+ }
+
+ Log.d(TAG, "updatePrefs(): mRequireHrForSeizureAlarm=" + mRequireHrForSeizureAlarm);
+ Log.d(TAG, "updatePrefs(): mHrConfirmationWindowSecs=" + mHrConfirmationWindowSecs);
mSdData.mO2SatAlarmActive = SP.getBoolean("O2SatAlarmActive", false);
Log.v(TAG, "updatePrefs() O2SatAlarmActive = " + mSdData.mO2SatAlarmActive);
diff --git a/app/src/main/java/uk/org/openseizuredetector/SdServer.java b/app/src/main/java/uk/org/openseizuredetector/SdServer.java
index 93cd591..4b1d6a6 100644
--- a/app/src/main/java/uk/org/openseizuredetector/SdServer.java
+++ b/app/src/main/java/uk/org/openseizuredetector/SdServer.java
@@ -1442,7 +1442,8 @@ public class SdServer extends Service implements SdDataReceiver {
// SmsManager sm = SmsManager.getDefault();
for (int i = 0; i < mSMSNumbers.length; i++) {
Log.i(TAG, "SmsTimer.onFinish() - Sending to " + mSMSNumbers[i]);
- sendSMS(new String(mSMSNumbers[i]), mSMSMsgStr + " - " + dateStr + " " + shortUuidStr);
+ sendSMS(new String(mSMSNumbers[i]),
+ mSMSMsgStr + " at " + dateStr + ". Location pending. Device: " + shortUuidStr);
}
}
@@ -1510,8 +1511,11 @@ public class SdServer extends Service implements SdDataReceiver {
+ ll.getLatitude() + "%2C" + ll.getLongitude();
String shortUuidStr = mUuidStr.substring(mUuidStr.length() - 6);
- String messageStr = mSMSMsgStr + " - " +
- dateStr + " - " + googleUrl + " " + shortUuidStr;
+ String messageStr = "Location update for seizure detected at "
+ + dateStr + ": "
+ + googleUrl
+ + " Device: "
+ + shortUuidStr;
Log.i(TAG, "onSdLocationReceived() - Message is " + messageStr);
mUtil.showToast(messageStr);
for (int i = 0; i < mSMSNumbers.length; i++) {
diff --git a/app/src/main/res/xml/alarm_prefs.xml b/app/src/main/res/xml/alarm_prefs.xml
index 4a677a4..006e2e3 100644
--- a/app/src/main/res/xml/alarm_prefs.xml
+++ b/app/src/main/res/xml/alarm_prefs.xml
@@ -12,8 +12,23 @@
android:summary="@string/latch_timer_period_summary"
android:numeric="integer"
android:defaultValue="10" />
-
+
+
+
+
+
+
+