diff --git a/app/release/app-release.apk b/app/release/app-release.apk index ccb8645..e133013 100644 Binary files a/app/release/app-release.apk and b/app/release/app-release.apk differ diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json index bc309a3..b900150 100644 --- a/app/release/output-metadata.json +++ b/app/release/output-metadata.json @@ -10,8 +10,8 @@ { "type": "SINGLE", "filters": [], - "versionCode": 88, - "versionName": "3.6.3a", + "versionCode": 90, + "versionName": "3.7.0a", "outputFile": "app-release.apk" } ] diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c5a75d6..3fc33ce 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="90" + android:versionName="3.7.0a"> diff --git a/app/src/main/java/uk/org/openseizuredetector/MainActivity.java b/app/src/main/java/uk/org/openseizuredetector/MainActivity.java index 04bd053..548dca7 100644 --- a/app/src/main/java/uk/org/openseizuredetector/MainActivity.java +++ b/app/src/main/java/uk/org/openseizuredetector/MainActivity.java @@ -460,11 +460,12 @@ public class MainActivity extends AppCompatActivity { // Pebble Connected Phrase - use for HR if active instead. tv = (TextView) findViewById(R.id.pebbleTv); if (mConnection.mSdServer.mSdData.mHRAlarmActive) { - tv.setText(getString(R.string.HR_Equals) + mConnection.mSdServer.mSdData.mHR); - if (mConnection.mSdServer.mSdData.mHRAlarmStanding) { + tv.setText(getString(R.string.HR_Equals) + mConnection.mSdServer.mSdData.mHR +" bpm\n" + + "O2 Sat = " + mConnection.mSdServer.mSdData.mO2Sat + "%"); + if (mConnection.mSdServer.mSdData.mHRAlarmStanding || mConnection.mSdServer.mSdData.mO2SatAlarmStanding) { tv.setBackgroundColor(alarmColour); tv.setTextColor(alarmTextColour); - } else if (mConnection.mSdServer.mSdData.mHRFaultStanding) { + } else if (mConnection.mSdServer.mSdData.mHRFaultStanding || mConnection.mSdServer.mSdData.mO2SatFaultStanding) { tv.setBackgroundColor(warnColour); tv.setTextColor(warnTextColour); } else { @@ -589,7 +590,7 @@ public class MainActivity extends AppCompatActivity { tv.setTextColor(warnTextColour); tv = (TextView) findViewById(R.id.pebbleTv); - tv.setText(getString(R.string.HR_Equals)+"---"); + tv.setText(getString(R.string.HR_Equals)+" --- bpm\nO2 Sat = --- %"); tv.setBackgroundColor(warnColour); tv.setTextColor(warnTextColour); diff --git a/app/src/main/java/uk/org/openseizuredetector/SdData.java b/app/src/main/java/uk/org/openseizuredetector/SdData.java index f24f7b0..407b711 100644 --- a/app/src/main/java/uk/org/openseizuredetector/SdData.java +++ b/app/src/main/java/uk/org/openseizuredetector/SdData.java @@ -65,6 +65,13 @@ public class SdData implements Parcelable { public boolean mHRNullAsAlarm = false; public double mHRThreshMin = 40.0; public double mHRThreshMax = 150.0; + + /* Oxygen Saturation Alarm Settings */ + public boolean mO2SatAlarmActive = false; + public boolean mO2SatNullAsAlarm = false; + public double mO2SatThreshMin = 80.0; + + public double rawData[]; int mNsamp = 0; @@ -87,6 +94,11 @@ public class SdData implements Parcelable { public boolean mHRFaultStanding = false; public double mHR = 0; + public boolean mO2SatAlarmStanding = false; + public boolean mO2SatFaultStanding = false; + public double mO2Sat = 0; + + public SdData() { simpleSpec = new int[10]; rawData = new double[N_RAW_DATA]; @@ -95,6 +107,7 @@ public class SdData implements Parcelable { /* * Intialise this SdData object from a JSON String + * FIXME - add O2saturation with checking in case it is not included in the data */ public boolean fromJSON(String jsonStr) { Log.v(TAG, "fromJSON() - parsing jsonString - " + jsonStr); @@ -182,6 +195,10 @@ public class SdData implements Parcelable { jsonObj.put("hrThreshMin",mHRThreshMin); jsonObj.put("hrThreshMax", mHRThreshMax); jsonObj.put("hr",mHR); + jsonObj.put("o2SatAlarmActive", mO2SatAlarmActive); + jsonObj.put("o2SatAlarmStanding", mO2SatAlarmStanding); + jsonObj.put("o2SatThreshMin",mO2SatThreshMin); + jsonObj.put("o2Sat",mO2Sat); JSONArray arr = new JSONArray(); for (int i = 0; i < simpleSpec.length; i++) { arr.put(simpleSpec[i]); @@ -220,6 +237,7 @@ public class SdData implements Parcelable { retval = retval + ", " + mSampleFreq; retval = retval + ", " + alarmPhrase; retval = retval + ", " + mHR; + retval = retval + ", " + mO2Sat; if (includeRawData) { for (int i = 0; i< mNsamp;i++) { retval = retval + ", " + rawData[i]; diff --git a/app/src/main/java/uk/org/openseizuredetector/SdDataSource.java b/app/src/main/java/uk/org/openseizuredetector/SdDataSource.java index 4603438..2eac58e 100644 --- a/app/src/main/java/uk/org/openseizuredetector/SdDataSource.java +++ b/app/src/main/java/uk/org/openseizuredetector/SdDataSource.java @@ -270,6 +270,12 @@ public abstract class SdDataSource { // if we get 'null' HR (For example if the heart rate is not working) mSdData.mHR = -1; } + try { + mSdData.mO2Sat = dataObject.getDouble("O2Sat"); + } catch (JSONException e) { + // if we get 'null' O2 Saturation (For example if the oxygen sensor is not working) + mSdData.mO2Sat = -1; + } try { mMute = dataObject.getInt("Mute"); } catch (JSONException e) { @@ -455,6 +461,7 @@ public abstract class SdDataSource { // Check this data to see if it represents an alarm state. alarmCheck(); hrCheck(); + o2SatCheck(); fallCheck(); muteCheck(); Log.v(TAG,"after fallCheck, mSdData.fallAlarmStanding="+mSdData.fallAlarmStanding); @@ -544,9 +551,39 @@ public abstract class SdDataSource { mSdData.mHRAlarmStanding = false; } } + } + + /** + * hrCheck - check the Heart rate data in mSdData to see if it represents an alarm condition. + * Sets mSdData.mHRAlarmStanding + */ + public void o2SatCheck() { + Log.v(TAG, "o2SatCheck()"); + /* Check Oxygen Saturation against alarm settings */ + if (mSdData.mO2SatAlarmActive) { + if (mSdData.mO2Sat < 0) { + if (mSdData.mO2SatNullAsAlarm) { + Log.i(TAG, "Oxygen Saturation Null - Alarming"); + mSdData.mO2SatFaultStanding = false; + mSdData.mO2SatAlarmStanding = true; + } else { + Log.i(TAG, "Oxygen Saturation Fault (O2Sat<0)"); + mSdData.mO2SatFaultStanding = true; + mSdData.mO2SatAlarmStanding = false; + } + } else if (mSdData.mO2Sat < mSdData.mO2SatThreshMin) { + Log.i(TAG, "Oxygen Saturation Abnormal - " + mSdData.mO2Sat + " %"); + mSdData.mO2SatFaultStanding = false; + mSdData.mO2SatAlarmStanding = true; + } else { + mSdData.mO2SatFaultStanding = false; + mSdData.mO2SatAlarmStanding = false; + } + } } + /**************************************************************** * Simple threshold analysis to chech for fall. * Called from clock_tick_handler() @@ -816,6 +853,19 @@ public abstract class SdDataSource { Log.v(TAG, "updatePrefs() HRThreshMax = " + mSdData.mHRThreshMax); mUtil.writeToSysLogFile( "updatePrefs() HRThreshMax = " + mSdData.mHRThreshMax); + mSdData.mO2SatAlarmActive = SP.getBoolean("O2SatAlarmActive", false); + Log.v(TAG, "updatePrefs() O2SatAlarmActive = " + mSdData.mO2SatAlarmActive); + mUtil.writeToSysLogFile( "updatePrefs() O2SatAlarmActive = " + mSdData.mO2SatAlarmActive); + + mSdData.mO2SatNullAsAlarm = SP.getBoolean("O2SatNullAsAlarm", false); + Log.v(TAG, "updatePrefs() O2SatNullAsAlarm = " + mSdData.mO2SatNullAsAlarm); + mUtil.writeToSysLogFile( "updatePrefs() O2SatNullAsAlarm = " + mSdData.mO2SatNullAsAlarm); + + prefStr = SP.getString("O2SatThreshMin", "SET_FROM_XML"); + mSdData.mO2SatThreshMin = (short) Integer.parseInt(prefStr); + Log.v(TAG, "updatePrefs() O2SatThreshMin = " + mSdData.mO2SatThreshMin); + mUtil.writeToSysLogFile( "updatePrefs() O2SatThreshMin = " + mSdData.mO2SatThreshMin); + } else { Log.v(TAG, "updatePrefs() - prefStr is null - WHY????"); mUtil.writeToSysLogFile("SDDataSource.updatePrefs() - prefStr is null - WHY??"); diff --git a/app/src/main/java/uk/org/openseizuredetector/SdServer.java b/app/src/main/java/uk/org/openseizuredetector/SdServer.java index f1c085b..8eb761d 100644 --- a/app/src/main/java/uk/org/openseizuredetector/SdServer.java +++ b/app/src/main/java/uk/org/openseizuredetector/SdServer.java @@ -672,9 +672,43 @@ public class SdServer extends Service implements SdDataReceiver { mUtil.showToast(getString(R.string.SMSAlarmDisabledNotSendingMsg)); Log.v(TAG, "mSMSAlarm is false - not sending"); } - } + // Handle Oxygen Saturation alarm + if ((sdData.mO2SatAlarmActive) && (sdData.mO2SatAlarmStanding)) { + sdData.alarmPhrase = "Oxygen Saturation ABNORMAL"; + if (mLogAlarms) { + Log.v(TAG, "***OXYGEN SATURATION*** - Logging to SD Card"); + writeAlarmToSD(); + } else { + Log.v(TAG, "***OXYGEN SATURATION***"); + } + // Make alarm beep tone + alarmBeep(); + showNotification(2); + // Display MainActvity + showMainActivity(); + // Send SMS Alarm. + if (mSMSAlarm) { + Time tnow = new Time(Time.getCurrentTimezone()); + tnow.setToNow(); + // limit SMS alarms to one per minute + if ((tnow.toMillis(false) + - mSMSTime.toMillis(false)) + > 60000) { + sendSMSAlarm(); + mSMSTime = tnow; + } else { + mUtil.showToast("SMS Alarm already sent - not re-sending"); + Log.v(TAG, "SMS Alarm already sent - not re-sending"); + } + } else { + mUtil.showToast(getString(R.string.SMSAlarmDisabledNotSendingMsg)); + Log.v(TAG, "mSMSAlarm is false - not sending"); + } + } + + // Fault if ((sdData.alarmState) == 4 || (sdData.alarmState == 7) || (sdData.mHRFaultStanding)) { sdData.alarmPhrase = "FAULT"; diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6fd61ac..b023675 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,7 +2,8 @@ OpenSeizureDetector - "V3.6.2 - Fix of issue with log file permissions on some Android 10 devices and added more translatable strings with polish translation. + "V3.7.0 - Added support for Garmin Blood Oxygen Saturation measurements + \nV3.6.2 - Fix of issue with log file permissions on some Android 10 devices and added more translatable strings with polish translation. \nV3.6.1 - Possible fix for issue with shutting down system and expanded Polish translation to all settings screens. \nV3.6 - Added phone sensor data source for testing without a watches \nV3.5 - Added support for SMS Annunciator App @@ -282,4 +283,11 @@ WarnTime (sec) Time to wait before initiating alarm (Default = 10 sec) AlarmTime (sec) + Blood Oxygen Saturation Alarm Settigs + O2Sat_enabled_summary + Enable O2 Saturation Alarm + Treat an error condition (null value of oxygen saturation reading) as an alarm condition + Treat Null Value as Alarm + Oxygen Saturation Low Alarm Level (%) + O2 Saturation Low Alarm Level (%) diff --git a/app/src/main/res/xml/seizure_detector_prefs.xml b/app/src/main/res/xml/seizure_detector_prefs.xml index 4af80aa..3a07770 100644 --- a/app/src/main/res/xml/seizure_detector_prefs.xml +++ b/app/src/main/res/xml/seizure_detector_prefs.xml @@ -65,6 +65,24 @@ android:title="@string/HRThreshMaxTitle" /> + + + + + +